# HG changeset patch # User markus schnalke # Date 1314454877 -7200 # Node ID 63efd381e27b1a7fc65f5a8dc56fee652450f5b9 # Parent e507c854a63ea9e67c2297473d97ccc418ab2e77 refactoring, partly also related to set_euidgid() diff -r e507c854a63e -r 63efd381e27b src/listen.c --- 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; */ diff -r e507c854a63e -r 63efd381e27b src/local.c --- 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[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("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("MESSAGE_ID=%s", msg->uid); + envp[n++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name); - envp[i++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid); - envp[i++] = 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);