comparison src/local.c @ 205:4fd237550525

REMOVED MAILDIR SUPPORT if you want to deliver to maildir, use an MDA like procmail masqmail can pass mail to an MDA by setting `mda' in masqmail.conf
author meillo@marmaro.de
date Fri, 16 Jul 2010 16:38:50 +0200
parents d1c53e76096f
children 996b53a50f55
comparison
equal deleted inserted replaced
204:5745edd5b769 205:4fd237550525
142 } 142 }
143 143
144 return ok; 144 return ok;
145 } 145 }
146 146
147 #ifdef ENABLE_MAILDIR
148 gboolean
149 maildir_out(message * msg, GList * hdr_list, gchar * user, guint flags)
150 {
151 struct passwd *pw;
152 gboolean ok = FALSE;
153
154 /* headers may be special for a local delivery */
155 if (hdr_list == NULL)
156 hdr_list = msg->hdr_list;
157
158 if ((pw = getpwnam(user))) {
159 uid_t saved_uid = geteuid();
160 gid_t saved_gid = getegid();
161 gboolean uid_ok = TRUE, gid_ok = TRUE;
162
163 if (!conf.run_as_user) {
164 uid_ok = (seteuid(0) == 0);
165 if (uid_ok) {
166 gid_ok = (setegid(conf.mail_gid) == 0);
167 uid_ok = (seteuid(pw->pw_uid) == 0);
168 }
169 }
170
171 DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
172
173 if (uid_ok && gid_ok) {
174 char *path = g_strdup_printf("%s/Maildir", pw->pw_dir);
175 struct stat statbuf;
176 int ret;
177
178 DEBUG(5) debugf(" path = %s\n", path);
179
180 ok = TRUE;
181 ret = stat(path, &statbuf);
182 if (ret != 0) {
183 ok = FALSE;
184 if (errno == ENOENT) {
185 logwrite(LOG_NOTICE, "directory %s does not exist, creating\n", path);
186 if (mkdir(path, 0700) == 0)
187 ok = TRUE;
188 } else
189 logwrite(LOG_ALERT, "stat of %s failed: %s\n", path, strerror(errno));
190 }
191 if (ok) {
192 ok = FALSE;
193 ret = stat(path, &statbuf);
194 if (S_ISDIR(statbuf.st_mode)) {
195 gchar *subdirs[] = { "tmp", "new", "cur" };
196 int i;
197 for (i = 0; i < 3; i++) {
198 char *path1 = g_strdup_printf("%s/%s", path, subdirs[i]);
199 ret = stat(path1, &statbuf);
200 if (ret != 0) {
201 if (errno == ENOENT) {
202 logwrite(LOG_NOTICE, "directory %s does not exist, creating\n", path1);
203 if (mkdir(path1, 0700) != 0)
204 break;
205 }
206 }
207 g_free(path1);
208 }
209 if (i == 3) {
210 FILE *out;
211 mode_t saved_mode = umask(066);
212 /* the qmail style unique works only if delivering with different process.
213 We do not fork for each delivery, so our uid is more unique.
214 Hope it is compatible with all MUAs.
215 */
216 gchar *filename = g_strdup_printf("%s/tmp/%s.%s", path, msg->uid, conf.host_name);
217
218 DEBUG(5) debugf("filename = %s\n", filename);
219
220 if ((out = fopen(filename, "w"))) {
221 gchar *newname = g_strdup_printf("%s/new/%s.%s", path, msg->uid, conf.host_name);
222 message_stream(out, msg, hdr_list, flags);
223 ok = TRUE;
224 if (fflush(out) == EOF)
225 ok = FALSE;
226 else if (fdatasync(fileno(out)) != 0) {
227 if (errno != EINVAL)
228 /* some fs do not support this.. I hope this also means that it is not necessary */
229 ok = FALSE;
230 }
231 fclose(out);
232 if (rename(filename, newname) != 0) {
233 ok = FALSE;
234 logwrite(LOG_ALERT, "moving %s to %s failed: %s", filename, newname, strerror(errno));
235 }
236 g_free(newname);
237 }
238 umask(saved_mode);
239 g_free(filename);
240 }
241 } else {
242 logwrite(LOG_ALERT, "%s is not a directory\n", path);
243 errno = ENOTDIR;
244 }
245 }
246 if (!conf.run_as_user) {
247 uid_ok = (seteuid(0) == 0);
248 if (uid_ok) {
249 gid_ok = (setegid(saved_gid) == 0);
250 uid_ok = (seteuid(saved_uid) == 0);
251 }
252 }
253 if (!uid_ok || !gid_ok) {
254 /* FIXME: if this fails we HAVE to exit, because we shall not run
255 with some users id. But we do not return, and so this message
256 will not be finished, so the user will get the message again
257 next time a delivery is attempted... */
258 logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
259 exit(EXIT_FAILURE);
260 }
261 g_free(path);
262 } else {
263 logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
264 }
265 } else {
266 logwrite(LOG_ALERT, "could not find password entry for user %s\n", user);
267 errno = ENOENT; /* getpwnam does not set errno correctly */
268 }
269 return ok;
270 }
271 #endif
272
273 gboolean 147 gboolean
274 pipe_out(message * msg, GList * hdr_list, address * rcpt, gchar * cmd, guint flags) 148 pipe_out(message * msg, GList * hdr_list, address * rcpt, gchar * cmd, guint flags)
275 { 149 {
276 gchar *envp[40]; 150 gchar *envp[40];
277 FILE *out; 151 FILE *out;