masqmail

view src/local.c @ 378:5781ba87df95

Removed ident. This had been discussed on the mailing list in Oct 2011. Ident is hardly useful in typical setups for masqmail. Probably Oliver had used it in his setup; that would make sense. Now, I know of nobody who needs it.
author markus schnalke <meillo@marmaro.de>
date Sat, 14 Jan 2012 21:36:58 +0100
parents 41958685480d
children f609a05ddff8
line source
1 /*
2 ** MasqMail
3 ** Copyright (C) 1999-2001 Oliver Kurth
4 ** Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
21 #include <sys/wait.h>
22 #include <sys/stat.h>
24 #include "masqmail.h"
25 #include "peopen.h"
27 static void
28 message_stream(FILE *out, message *msg, GList *hdr_list, guint flags)
29 {
30 time_t now = time(NULL);
31 GList *node;
33 if (flags & MSGSTR_FROMLINE) {
34 fprintf(out, "From <%s@%s> %s", msg->return_path->local_part, msg->return_path->domain, ctime(&now));
35 }
37 foreach(hdr_list, node) {
38 header *hdr = (header *) (node->data);
39 fputs(hdr->header, out);
40 }
41 putc('\n', out);
42 foreach(msg->data_list, node) {
43 /* From hack: */
44 if (flags & MSGSTR_FROMHACK) {
45 if (strncmp(node->data, "From ", 5) == 0)
46 putc('>', out);
47 }
48 fputs(node->data, out);
49 }
50 putc('\n', out);
51 }
53 gboolean
54 append_file(message *msg, GList *hdr_list, gchar *user)
55 {
56 struct passwd *pw;
57 gboolean ok = FALSE;
58 uid_t saved_uid = geteuid();
59 gid_t saved_gid = getegid();
60 gboolean uid_ok = TRUE, gid_ok = TRUE;
61 gchar *filename;
62 FILE *out;
64 /* headers may be special for a local delivery */
65 if (!hdr_list)
66 hdr_list = msg->hdr_list;
68 if (!(pw = getpwnam(user))) {
69 logwrite(LOG_ALERT, "could not find password entry for user %s\n", user);
70 errno = ENOENT; /* getpwnam does not set errno correctly */
71 return FALSE;
72 }
74 if (!conf.run_as_user) {
75 uid_ok = (seteuid(0) == 0);
76 if (uid_ok) {
77 gid_ok = (setegid(conf.mail_gid) == 0);
78 uid_ok = (seteuid(pw->pw_uid) == 0);
79 }
80 if (!uid_ok || !gid_ok) {
81 logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
82 return FALSE;
83 }
84 }
86 DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
88 filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
89 if (!(out = fopen(filename, "a"))) {
90 logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
91 } else {
92 #ifdef USE_LIBLOCKFILE
93 gint err;
94 /* lock file using liblockfile */
95 err = maillock(user, 3);
96 if (err == 0) {
97 #else
98 /* lock file: */
99 struct flock lock;
100 lock.l_type = F_WRLCK;
101 lock.l_whence = SEEK_END;
102 lock.l_start = lock.l_len = 0;
103 if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
104 #endif
105 fchmod(fileno(out), 0600);
106 message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
107 ok = TRUE;
109 /* close when still user */
110 fclose(out);
111 #ifdef USE_LIBLOCKFILE
112 mailunlock();
113 #endif
114 } else {
115 fclose(out);
116 #ifdef USE_LIBLOCKFILE
117 DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
118 } /* XEmacs indenting convenience... */
119 #else
120 DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
121 }
122 #endif
123 }
124 g_free(filename);
126 if (!conf.run_as_user) {
127 uid_ok = (seteuid(0) == 0);
128 if (uid_ok) {
129 gid_ok = (setegid(saved_gid) == 0);
130 uid_ok = (seteuid(saved_uid) == 0);
131 }
132 }
134 if (!uid_ok || !gid_ok) {
135 /*
136 ** FIXME: if this fails we HAVE to exit, because we shall
137 ** not run with some users id. But we do not return, and so
138 ** this message will not be finished, so the user will get
139 ** the message again next time a delivery is attempted...
140 */
141 logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
142 logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
143 getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
144 logwrite(LOG_ALERT, "In case of trouble, see local.c:append_file() for details.\n", strerror(errno));
145 exit(1);
146 }
147 return ok;
148 }
150 gboolean
151 pipe_out(message *msg, GList *hdr_list, address *rcpt, gchar *cmd, guint flags)
152 {
153 gchar *envp[40];
154 FILE *out;
155 uid_t saved_uid = geteuid();
156 gid_t saved_gid = getegid();
157 gboolean ok = FALSE;
158 gint i, n;
159 pid_t pid;
160 void (*old_signal) (int);
161 int status;
162 address *ancestor = addr_find_ancestor(rcpt);
164 /* set uid and gid to the mail ids */
165 if (!conf.run_as_user) {
166 set_euidgid(conf.mail_uid, conf.mail_gid, &saved_uid, &saved_gid);
167 }
169 /* set environment */
170 n = 0;
171 envp[n++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
172 envp[n++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
173 envp[n++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
174 envp[n++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
176 envp[n++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
177 envp[n++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
179 envp[n++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
180 envp[n++] = g_strdup_printf("USER=%s", ancestor->local_part);
181 envp[n++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
183 envp[n++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
184 envp[n++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
186 envp[n] = NULL;
188 old_signal = signal(SIGCHLD, SIG_DFL);
190 out = peidopen(cmd, "w", envp, &pid, conf.mail_uid, conf.mail_gid);
191 if (!out) {
192 logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
193 } else {
194 message_stream(out, msg, hdr_list, flags);
196 fclose(out);
198 waitpid(pid, &status, 0);
200 if (WEXITSTATUS(status) != 0) {
201 int exstat = WEXITSTATUS(status);
202 logwrite(LOG_ALERT, "process returned %d (%s)\n", exstat, ext_strerror(1024 + exstat));
203 errno = 1024 + exstat;
204 } else if (WIFSIGNALED(status)) {
205 logwrite(LOG_ALERT, "process got signal %d\n", WTERMSIG(status));
206 } else
207 ok = TRUE;
209 }
211 signal(SIGCHLD, old_signal);
213 /* free environment */
214 for (i = 0; i < n; i++) {
215 g_free(envp[i]);
216 }
218 /* set uid and gid back */
219 if (!conf.run_as_user) {
220 set_euidgid(saved_uid, saved_gid, NULL, NULL);
221 }
223 return ok;
224 }