changeset 332:63efd381e27b

refactoring, partly also related to set_euidgid()
author markus schnalke <meillo@marmaro.de>
date Sat, 27 Aug 2011 16:21:17 +0200 (2011-08-27)
parents e507c854a63e
children 0bd27f603910
files src/listen.c src/local.c
diffstat 2 files changed, 98 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/src/listen.c	Sat Aug 27 16:19:07 2011 +0200
+++ b/src/listen.c	Sat Aug 27 16:21:17 2011 +0200
@@ -131,14 +131,7 @@
 
 	/* now that we have our socket(s), we can give up root privileges */
 	if (!conf.run_as_user) {
-		if (setegid(conf.mail_gid) != 0) {
-			logwrite(LOG_ALERT, "could not change gid to %d: %s\n", conf.mail_gid, strerror(errno));
-			exit(1);
-		}
-		if (seteuid(conf.mail_uid) != 0) {
-			logwrite(LOG_ALERT, "could not change uid to %d: %s\n", conf.mail_uid, strerror(errno));
-			exit(1);
-		}
+		set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL);
 	}
 
 	/*  sel_ret = 0; */
--- a/src/local.c	Sat Aug 27 16:19:07 2011 +0200
+++ b/src/local.c	Sat Aug 27 16:21:17 2011 +0200
@@ -54,94 +54,93 @@
 {
 	struct passwd *pw;
 	gboolean ok = FALSE;
+	uid_t saved_uid = geteuid();
+	gid_t saved_gid = getegid();
+	gboolean uid_ok = TRUE, gid_ok = TRUE;
+	gchar *filename;
+	FILE *out;
 
 	/* headers may be special for a local delivery */
-	if (hdr_list == NULL)
+	if (!hdr_list)
 		hdr_list = msg->hdr_list;
 
-	if ((pw = getpwnam(user))) {
-		uid_t saved_uid = geteuid();
-		gid_t saved_gid = getegid();
-		gboolean uid_ok = TRUE, gid_ok = TRUE;
-
-		if (!conf.run_as_user) {
-			uid_ok = (seteuid(0) == 0);
-			if (uid_ok) {
-				gid_ok = (setegid(conf.mail_gid) == 0);
-				uid_ok = (seteuid(pw->pw_uid) == 0);
-			}
-		}
-
-		DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
-
-		if (uid_ok && gid_ok) {
-			gchar *filename;
-			FILE *out;
-
-			filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
-			if ((out = fopen(filename, "a"))) {
-#ifdef USE_LIBLOCKFILE
-				gint err;
-				/* lock file using liblockfile */
-				err = maillock(user, 3);
-				if (err == 0) {
-#else
-				/* lock file: */
-				struct flock lock;
-				lock.l_type = F_WRLCK;
-				lock.l_whence = SEEK_END;
-				lock.l_start = lock.l_len = 0;
-				if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
-#endif
-					fchmod(fileno(out), 0600);
-					message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
-					ok = TRUE;
-
-					/* close when still user */
-					fclose(out);
-#ifdef USE_LIBLOCKFILE
-					mailunlock();
-#endif
-				} else {
-					fclose(out);
-#ifdef USE_LIBLOCKFILE
-					DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
-				}  /* XEmacs indenting convenience... */
-#else
-					DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
-				}
-#endif
-			} else {
-				logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
-			}
-			g_free(filename);
-
-			if (!conf.run_as_user) {
-				uid_ok = (seteuid(0) == 0);
-				if (uid_ok) {
-					gid_ok = (setegid(saved_gid) == 0);
-					uid_ok = (seteuid(saved_uid) == 0);
-				}
-			}
-
-			if (!uid_ok || !gid_ok) {
-				/* FIXME: if this fails we HAVE to exit, because we shall not run
-				   with some users id. But we do not return, and so this message
-				   will not be finished, so the user will get the message again
-				   next time a delivery is attempted... */
-				logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
-				logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
-				         getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
-				exit(1);
-			}
-		} else {
-			logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
-		}
-	} else {
+	if (!(pw = getpwnam(user))) {
 		logwrite(LOG_ALERT, "could not find password entry for user %s\n", user);
 		errno = ENOENT;  /* getpwnam does not set errno correctly */
+		return FALSE;
+	}
+
+	if (!conf.run_as_user) {
+		uid_ok = (seteuid(0) == 0);
+		if (uid_ok) {
+			gid_ok = (setegid(conf.mail_gid) == 0);
+			uid_ok = (seteuid(pw->pw_uid) == 0);
+		}
+		if (!uid_ok || !gid_ok) {
+			logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
+			return FALSE;
+		}
 	}
 
+	DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
+
+	filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
+	if (!(out = fopen(filename, "a"))) {
+		logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
+	} else {
+#ifdef USE_LIBLOCKFILE
+		gint err;
+		/* lock file using liblockfile */
+		err = maillock(user, 3);
+		if (err == 0) {
+#else
+		/* lock file: */
+		struct flock lock;
+		lock.l_type = F_WRLCK;
+		lock.l_whence = SEEK_END;
+		lock.l_start = lock.l_len = 0;
+		if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
+#endif
+			fchmod(fileno(out), 0600);
+			message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
+			ok = TRUE;
+
+			/* close when still user */
+			fclose(out);
+#ifdef USE_LIBLOCKFILE
+			mailunlock();
+#endif
+		} else {
+			fclose(out);
+#ifdef USE_LIBLOCKFILE
+			DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
+		}  /* XEmacs indenting convenience... */
+#else
+			DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
+		}
+#endif
+	}
+	g_free(filename);
+
+	if (!conf.run_as_user) {
+		uid_ok = (seteuid(0) == 0);
+		if (uid_ok) {
+			gid_ok = (setegid(saved_gid) == 0);
+			uid_ok = (seteuid(saved_uid) == 0);
+		}
+	}
+
+	if (!uid_ok || !gid_ok) {
+		/* FIXME: if this fails we HAVE to exit, because we shall not run
+		   with some users id. But we do not return, and so this message
+		   will not be finished, so the user will get the message again
+		   next time a delivery is attempted... */
+		logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
+		logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
+		         getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
+		logwrite(LOG_ALERT, "In case of trouble, see local.c:append_file() for details.\n", strerror(errno));
+		exit(1);
+	}
 	return ok;
 }
 
@@ -157,6 +156,7 @@
 	pid_t pid;
 	void (*old_signal) (int);
 	int status;
+	address *ancestor = addr_find_ancestor(rcpt);
 
 	/* set uid and gid to the mail ids */
 	if (!conf.run_as_user) {
@@ -164,33 +164,30 @@
 	}
 
 	/* set environment */
-	{
-		gint i = 0;
-		address *ancestor = addr_find_ancestor(rcpt);
+	n = 0;
+	envp[n++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
+	envp[n++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
+	envp[n++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
+	envp[n++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
 
-		envp[i++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
-		envp[i++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
-		envp[i++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
-		envp[i++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
+	envp[n++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
+	envp[n++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
 
-		envp[i++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
-		envp[i++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
-
-		envp[i++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
-		envp[i++] = g_strdup_printf("USER=%s", ancestor->local_part);
-		envp[i++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
+	envp[n++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
+	envp[n++] = g_strdup_printf("USER=%s", ancestor->local_part);
+	envp[n++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
 
-		envp[i++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
-		envp[i++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
+	envp[n++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
+	envp[n++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
 
-		envp[i] = NULL;
-		n = i;
-	}
+	envp[n] = NULL;
 
 	old_signal = signal(SIGCHLD, SIG_DFL);
 
 	out = peidopen(cmd, "w", envp, &pid, conf.mail_uid, conf.mail_gid);
-	if (out != NULL) {
+	if (!out) {
+		logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
+	} else {
 		message_stream(out, msg, hdr_list, flags);
 
 		fclose(out);
@@ -206,8 +203,7 @@
 		} else
 			ok = TRUE;
 
-	} else
-		logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
+	}
 
 	signal(SIGCHLD, old_signal);