* Clean up some function definitions to comply with strict
[alpine.git] / imap / src / osdep / unix / env_unix.c
blobc2fae37065db8825de32c61f5521807cafc2e557
1 /* ========================================================================
2 * Copyright 2008-2010 Mark Crispin
3 * ========================================================================
4 */
6 /*
7 * Program: UNIX environment routines
9 * Author: Mark Crispin
11 * Date: 1 August 1988
12 * Last Edited: 15 November 2010
14 * Previous versions of this file were
16 * Copyright 1988-2008 University of Washington
18 * Licensed under the Apache License, Version 2.0 (the "License");
19 * you may not use this file except in compliance with the License.
20 * You may obtain a copy of the License at
22 * http://www.apache.org/licenses/LICENSE-2.0
26 #include <grp.h>
27 #include <signal.h>
28 #include <sys/wait.h>
31 /* in case stat.h is ancient */
33 #ifndef S_IRUSR
34 #define S_IRUSR S_IREAD
35 #endif
36 #ifndef S_IWUSR
37 #define S_IWUSR S_IWRITE
38 #endif
39 #ifndef S_IXUSR
40 #define S_IXUSR S_IEXEC
41 #endif
42 #ifndef S_IRGRP
43 #define S_IRGRP (S_IREAD >> 3)
44 #endif
45 #ifndef S_IWGRP
46 #define S_IWGRP (S_IWRITE >> 3)
47 #endif
48 #ifndef S_IXGRP
49 #define S_IXGRP (S_IEXEC >> 3)
50 #endif
51 #ifndef S_IROTH
52 #define S_IROTH (S_IREAD >> 6)
53 #endif
54 #ifndef S_IWOTH
55 #define S_IWOTH (S_IWRITE >> 6)
56 #endif
57 #ifndef S_IXOTH
58 #define S_IXOTH (S_IEXEC >> 6)
59 #endif
61 /* c-client environment parameters */
63 static char *myUserName = NIL; /* user name */
64 static char *myHomeDir = NIL; /* home directory name */
65 static char *myServerName = NIL;/* server name */
66 static char *myLocalHost = NIL; /* local host name */
67 static char *myNewsrc = NIL; /* newsrc file name */
68 static char *mailsubdir = NIL; /* mailbox subdirectory name */
69 static char *sysInbox = NIL; /* system inbox name */
70 static char *newsActive = NIL; /* news active file */
71 static char *newsSpool = NIL; /* news spool */
72 static char *blackBoxDir = NIL; /* black box directory name */
73 /* black box default home directory */
74 static char *blackBoxDefaultHome = NIL;
75 static char *sslCApath = NIL; /* non-standard CA path */
76 static char *sslCAfile = NIL; /* non-standard CA container */
77 static char *sslAppCApath = NIL; /* App SSL CA path */
78 static char *sslAppCAfile = NIL; /* App SSL CA container */
79 static char *sslciphers = NIL; /* ciphers to negotiate with a SSL server */
80 static short anonymous = NIL; /* is anonymous */
81 static short blackBox = NIL; /* is a black box */
82 static short closedBox = NIL; /* is a closed box (uses chroot() jail) */
83 static long restrictBox = NIL; /* is a restricted box */
84 static short has_no_life = NIL; /* is a cretin with no life */
85 /* block environment init */
86 static short block_env_init = NIL;
87 static short hideDotFiles = NIL;/* hide files whose names start with . */
88 /* advertise filesystem root */
89 static short advertisetheworld = NIL;
90 /* only advertise own mailboxes and #shared */
91 static short limitedadvertise = NIL;
92 /* disable automatic shared namespaces */
93 static short noautomaticsharedns = NIL;
94 static short no822tztext = NIL; /* disable RFC [2]822 timezone text */
95 /* client principals include service name */
96 static short kerb_cp_svr_name = NIL;
97 static long locktimeout = 5; /* default lock timeout in minutes */
98 /* default prototypes */
99 static MAILSTREAM *createProto = NIL;
100 static MAILSTREAM *appendProto = NIL;
101 /* default user flags */
102 static char *userFlags[NUSERFLAGS] = {NIL};
103 static NAMESPACE *nslist[3]; /* namespace list */
104 static int logtry = 3; /* number of server login tries */
105 /* block notification */
106 static blocknotify_t mailblocknotify = mm_blocknotify;
107 /* logout function */
108 static logouthook_t maillogouthook = NIL;
109 /* logout data */
110 static void *maillogoutdata = NIL;
111 /* allow user config files */
112 static short allowuserconfig = NIL;
113 /* 1 = disable plaintext, 2 = if not SSL */
114 static long disablePlaintext = NIL;
115 static long list_max_level = 20;/* maximum level of list recursion */
116 /* facility for syslog */
117 static int syslog_facility = LOG_MAIL;
119 /* Path of the privileged system lock program (mlock). Normally set by
120 * logic test.
123 static char *lockpgm = LOCKPGM;
125 /* Directory used for shared locks. MUST be the same for all users of the
126 * system, and MUST be protected 1777. /var/tmp may be preferable on some
127 * systems.
130 static const char *tmpdir = "/tmp";
132 /* Do not change shlock_mode. Doing so can cause mailbox corruption and
133 * denial of service. It also defeats the entire purpose of the shared
134 * lock mechanism. The right way to avoid shared locks is to set up a
135 * closed box (see the closedBox setting).
138 /* shared lock mode */
139 static const int shlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
142 /* It is STRONGLY recommended that you do not change dotlock_mode. Doing so
143 * can cause denial of service with old dot-lock files left lying around.
144 * However, since dot-locks are only used with traditional UNIX and MMDF
145 * formats which are not normally shared, it is much less harmful to tamper
146 * with this than with shlock_mode.
149 /* dot-lock mode */
150 static long dotlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
152 /* File/directory access and protection policies */
154 /* Unlike shlock_mode, the ????_protection modes are intended to be fully
155 * customizable according to site policy. The values here are recommended
156 * settings, based upon the documented purposes of the namespaces.
159 /* user space - only owner can read/write */
160 static char *myMailboxDir = NIL;/* user space directory name */
161 /* default file protection */
162 static long mbx_protection = S_IRUSR|S_IWUSR;
163 /* default directory protection */
164 static long dir_protection = S_IRUSR|S_IWUSR|S_IXUSR;
166 /* user space for user "anonymous" */
167 /* anonymous home directory */
168 static char *anonymousHome = NIL;
170 /* #ftp - everybody can read, only owner can write */
171 static char *ftpHome = NIL; /* ftp export home directory */
172 /* default ftp file protection */
173 static long ftp_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
174 static long ftp_dir_protection =/* default ftp directory protection */
175 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
177 /* #public - everybody can read/write */
178 static char *publicHome = NIL; /* public home directory */
179 static long public_protection = /* default public file protection */
180 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
181 /* default public directory protection */
182 static long public_dir_protection =
183 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
185 /* #shared/ - owner and group members can read/write */
186 static char *sharedHome = NIL; /* shared home directory */
187 /* default shared file protection */
188 static long shared_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
189 /* default shared directory protection */
190 static long shared_dir_protection =
191 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP;
193 /* OS bug workarounds - should be avoided at all cost */
196 /* Don't set fcntlhangbug unless you really have to, since it risks mailbox
197 * corruption. The flocksim.c mechanism is designed to detect NFS access
198 * and no-op in that cases only, so this flag should be unnecessary.
201 static short fcntlhangbug = NIL;/* flock() emulator using fcntl() is a no-op */
204 /* Don't set netfsstatbug unless you really have to, since it dramatically
205 * slows down traditional UNIX and MMDF mailbox performance.
208 static short netfsstatbug = NIL;/* compensate for broken stat() on network
209 * filesystems (AFS and old NFS)
213 /* Note: setting disableLockWarning means that you assert that the
214 * so-modified copy of this software will NEVER be used:
215 * 1) in conjunction with any software which expects .lock files
216 * 2) to access NFS-mounted files and directories
218 * Unless both of these conditions apply, then do not set this flag.
219 * Instead, read the FAQ (item 7.10) and either use 1777 protection
220 * on the mail spool, or install mlock.
222 * In addition, by setting this flag you also agree that you are fully
223 * legally and morally responsible when (not if) mail files are damaged
224 * as the result of your choice.
226 * The mlock tool exists for a reason. Use it.
228 /* disable warning if can't make .lock file */
229 static short disableLockWarning = NIL;
231 /* UNIX Namespaces */
233 /* personal mh namespace */
234 static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
235 static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
236 /* home namespace */
237 static NAMESPACE nshome = {"",'/',NIL,&nsmh};
238 /* UNIX other user namespace */
239 static NAMESPACE nsunixother = {"~",'/',NIL,NIL};
240 /* black box other user namespace */
241 static NAMESPACE nsblackother = {"/",'/',NIL,NIL};
242 /* public (anonymous OK) namespace */
243 static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
244 /* netnews namespace */
245 static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
246 /* FTP export namespace */
247 static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
248 /* shared (no anonymous) namespace */
249 static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
250 /* world namespace */
251 static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
252 /* only shared and public namespaces */
253 static NAMESPACE nslimited = {"#shared/",'/',NIL,&nspublic};
257 #include "write.c" /* include safe writing routines */
258 #include "crexcl.c" /* include exclusive create */
259 #include "pmatch.c" /* include wildcard pattern matcher */
261 /* Get all authenticators */
263 #include "auths.c"
265 /* Environment manipulate parameters
266 * Accepts: function code
267 * function-dependent value
268 * Returns: function-dependent return value
271 void *env_parameters (long function,void *value)
273 void *ret = NIL;
274 switch ((int) function) {
275 case GET_NAMESPACE:
276 ret = (void *) nslist;
277 break;
278 case SET_USERNAME:
279 if (myUserName) fs_give ((void **) &myUserName);
280 myUserName = cpystr ((char *) value);
281 case GET_USERNAME:
282 ret = (void *) myUserName;
283 break;
284 case SET_HOMEDIR:
285 if (myHomeDir) fs_give ((void **) &myHomeDir);
286 myHomeDir = cpystr ((char *) value);
287 case GET_HOMEDIR:
288 ret = (void *) myHomeDir;
289 break;
290 case SET_LOCALHOST:
291 if (myLocalHost) fs_give ((void **) &myLocalHost);
292 myLocalHost = cpystr ((char *) value);
293 case GET_LOCALHOST:
294 ret = (void *) myLocalHost;
295 break;
296 case SET_NEWSRC:
297 if (myNewsrc) fs_give ((void **) &myNewsrc);
298 myNewsrc = cpystr ((char *) value);
299 case GET_NEWSRC:
300 ret = (void *) myNewsrc;
301 break;
302 case SET_NEWSACTIVE:
303 if (newsActive) fs_give ((void **) &newsActive);
304 newsActive = cpystr ((char *) value);
305 case GET_NEWSACTIVE:
306 ret = (void *) newsActive;
307 break;
308 case SET_NEWSSPOOL:
309 if (newsSpool) fs_give ((void **) &newsSpool);
310 newsSpool = cpystr ((char *) value);
311 case GET_NEWSSPOOL:
312 ret = (void *) newsSpool;
313 break;
315 case SET_ANONYMOUSHOME:
316 if (anonymousHome) fs_give ((void **) &anonymousHome);
317 anonymousHome = cpystr ((char *) value);
318 case GET_ANONYMOUSHOME:
319 if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
320 ret = (void *) anonymousHome;
321 break;
322 case SET_FTPHOME:
323 if (ftpHome) fs_give ((void **) &ftpHome);
324 ftpHome = cpystr ((char *) value);
325 case GET_FTPHOME:
326 ret = (void *) ftpHome;
327 break;
328 case SET_PUBLICHOME:
329 if (publicHome) fs_give ((void **) &publicHome);
330 publicHome = cpystr ((char *) value);
331 case GET_PUBLICHOME:
332 ret = (void *) publicHome;
333 break;
334 case SET_SHAREDHOME:
335 if (sharedHome) fs_give ((void **) &sharedHome);
336 sharedHome = cpystr ((char *) value);
337 case GET_SHAREDHOME:
338 ret = (void *) sharedHome;
339 break;
340 case SET_SYSINBOX:
341 if (sysInbox) fs_give ((void **) &sysInbox);
342 sysInbox = cpystr ((char *) value);
343 case GET_SYSINBOX:
344 ret = (void *) sysInbox;
345 break;
346 case SET_SSLCAPATH: /* this can be set null */
347 if (sslCApath) fs_give ((void **) &sslCApath);
348 sslCApath = value ? cpystr ((char *) value) : value;
349 break;
350 case GET_SSLCAPATH:
351 ret = (void *) sslCApath;
352 break;
353 case SET_SSLCAFILE: /* this can be set null */
354 if (sslCAfile) fs_give ((void **) &sslCAfile);
355 sslCAfile = value ? cpystr ((char *) value) : value;
356 break;
357 case GET_SSLCAFILE:
358 ret = (void *) sslCAfile;
359 break;
360 case SET_SSLAPPCAPATH: /* this can be set null */
361 if (sslAppCApath) fs_give ((void **) &sslAppCApath);
362 sslAppCApath = value ? cpystr ((char *) value) : value;
363 break;
364 case GET_SSLAPPCAPATH:
365 ret = (void *) sslAppCApath;
366 break;
367 case SET_SSLAPPCAFILE: /* this can be set null */
368 if (sslAppCAfile) fs_give ((void **) &sslAppCAfile);
369 sslAppCAfile = value ? cpystr ((char *) value) : value;
370 break;
371 case GET_SSLAPPCAFILE:
372 ret = (void *) sslAppCAfile;
373 break;
374 case SET_SSLCIPHERS: /* this can be set null */
375 if (sslciphers) fs_give ((void **) &sslciphers);
376 sslciphers = value ? cpystr ((char *) value) : value;
377 break;
378 case GET_SSLCIPHERS:
379 ret = (void *) sslciphers;
380 break;
381 case SET_LISTMAXLEVEL:
382 list_max_level = (long) value;
383 case GET_LISTMAXLEVEL:
384 ret = (void *) list_max_level;
385 break;
387 case SET_MBXPROTECTION:
388 mbx_protection = (long) value;
389 case GET_MBXPROTECTION:
390 ret = (void *) mbx_protection;
391 break;
392 case SET_DIRPROTECTION:
393 dir_protection = (long) value;
394 case GET_DIRPROTECTION:
395 ret = (void *) dir_protection;
396 break;
397 case SET_LOCKPROTECTION:
398 dotlock_mode = (long) value;
399 case GET_LOCKPROTECTION:
400 ret = (void *) dotlock_mode;
401 break;
402 case SET_FTPPROTECTION:
403 ftp_protection = (long) value;
404 case GET_FTPPROTECTION:
405 ret = (void *) ftp_protection;
406 break;
407 case SET_PUBLICPROTECTION:
408 public_protection = (long) value;
409 case GET_PUBLICPROTECTION:
410 ret = (void *) public_protection;
411 break;
412 case SET_SHAREDPROTECTION:
413 shared_protection = (long) value;
414 case GET_SHAREDPROTECTION:
415 ret = (void *) shared_protection;
416 break;
417 case SET_FTPDIRPROTECTION:
418 ftp_dir_protection = (long) value;
419 case GET_FTPDIRPROTECTION:
420 ret = (void *) ftp_dir_protection;
421 break;
422 case SET_PUBLICDIRPROTECTION:
423 public_dir_protection = (long) value;
424 case GET_PUBLICDIRPROTECTION:
425 ret = (void *) public_dir_protection;
426 break;
427 case SET_SHAREDDIRPROTECTION:
428 shared_dir_protection = (long) value;
429 case GET_SHAREDDIRPROTECTION:
430 ret = (void *) shared_dir_protection;
431 break;
432 case SET_RESTRICTIONS:
433 restrictBox = (long) value;
434 case GET_RESTRICTIONS:
435 ret = (void *) restrictBox;
437 case SET_LOCKTIMEOUT:
438 locktimeout = (long) value;
439 case GET_LOCKTIMEOUT:
440 ret = (void *) locktimeout;
441 break;
442 case SET_DISABLEFCNTLLOCK:
443 fcntlhangbug = value ? T : NIL;
444 case GET_DISABLEFCNTLLOCK:
445 ret = (void *) (fcntlhangbug ? VOIDT : NIL);
446 break;
447 case SET_LOCKEACCESERROR:
448 disableLockWarning = value ? NIL : T;
449 case GET_LOCKEACCESERROR:
450 ret = (void *) (disableLockWarning ? NIL : VOIDT);
451 break;
452 case SET_HIDEDOTFILES:
453 hideDotFiles = value ? T : NIL;
454 case GET_HIDEDOTFILES:
455 ret = (void *) (hideDotFiles ? VOIDT : NIL);
456 break;
457 case SET_DISABLEPLAINTEXT:
458 disablePlaintext = (long) value;
459 case GET_DISABLEPLAINTEXT:
460 ret = (void *) disablePlaintext;
461 break;
462 case SET_CHROOTSERVER:
463 closedBox = value ? T : NIL;
464 case GET_CHROOTSERVER:
465 ret = (void *) (closedBox ? VOIDT : NIL);
466 break;
467 case SET_ADVERTISETHEWORLD:
468 advertisetheworld = value ? T : NIL;
469 case GET_ADVERTISETHEWORLD:
470 ret = (void *) (advertisetheworld ? VOIDT : NIL);
471 break;
472 case SET_LIMITEDADVERTISE:
473 limitedadvertise = value ? T : NIL;
474 case GET_LIMITEDADVERTISE:
475 ret = (void *) (limitedadvertise ? VOIDT : NIL);
476 break;
477 case SET_DISABLEAUTOSHAREDNS:
478 noautomaticsharedns = value ? T : NIL;
479 case GET_DISABLEAUTOSHAREDNS:
480 ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
481 break;
482 case SET_DISABLE822TZTEXT:
483 no822tztext = value ? T : NIL;
484 case GET_DISABLE822TZTEXT:
485 ret = (void *) (no822tztext ? VOIDT : NIL);
486 break;
488 case SET_USERHASNOLIFE:
489 has_no_life = value ? T : NIL;
490 case GET_USERHASNOLIFE:
491 ret = (void *) (has_no_life ? VOIDT : NIL);
492 break;
493 case SET_KERBEROS_CP_SVR_NAME:
494 kerb_cp_svr_name = value ? T : NIL;
495 case GET_KERBEROS_CP_SVR_NAME:
496 ret = (void *) (kerb_cp_svr_name ? VOIDT : NIL);
497 break;
498 case SET_NETFSSTATBUG:
499 netfsstatbug = value ? T : NIL;
500 case GET_NETFSSTATBUG:
501 ret = (void *) (netfsstatbug ? VOIDT : NIL);
502 break;
503 case SET_BLOCKENVINIT:
504 block_env_init = value ? T : NIL;
505 case GET_BLOCKENVINIT:
506 ret = (void *) (block_env_init ? VOIDT : NIL);
507 break;
508 case SET_BLOCKNOTIFY:
509 mailblocknotify = (blocknotify_t) value;
510 case GET_BLOCKNOTIFY:
511 ret = (void *) mailblocknotify;
512 break;
513 case SET_LOGOUTHOOK:
514 maillogouthook = (logouthook_t) value;
515 case GET_LOGOUTHOOK:
516 ret = maillogouthook;
517 break;
518 case SET_LOGOUTDATA:
519 maillogoutdata = (void *) value;
520 case GET_LOGOUTDATA:
521 ret = maillogoutdata;
523 return ret;
526 /* Write current time
527 * Accepts: destination string
528 * optional format of day-of-week prefix
529 * format of date and time
530 * flag whether to append symbolic timezone
533 static void do_date (char *date,char *prefix,char *fmt,int suffix)
535 time_t tn = time (0);
536 struct tm *t = gmtime (&tn);
537 int zone = t->tm_hour * 60 + t->tm_min;
538 int julian = t->tm_yday;
539 t = localtime (&tn); /* get local time now */
540 /* minus UTC minutes since midnight */
541 zone = t->tm_hour * 60 + t->tm_min - zone;
542 /* julian can be one of:
543 * 36x local time is December 31, UTC is January 1, offset -24 hours
544 * 1 local time is 1 day ahead of UTC, offset +24 hours
545 * 0 local time is same day as UTC, no offset
546 * -1 local time is 1 day behind UTC, offset -24 hours
547 * -36x local time is January 1, UTC is December 31, offset +24 hours
549 if ((julian = t->tm_yday -julian) != 0)
550 zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
551 if (prefix) { /* want day of week? */
552 sprintf (date,prefix,days[t->tm_wday]);
553 date += strlen (date); /* make next sprintf append */
555 /* output the date */
556 sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
557 t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
558 /* append timezone suffix if desired */
559 if (suffix) rfc822_timezone (date,(void *) t);
562 /* Write current time in RFC 822 format
563 * Accepts: destination string
566 void rfc822_date (char *date)
568 do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
569 no822tztext ? NIL : T);
573 /* Write current time in fixed-width RFC 822 format
574 * Accepts: destination string
577 void rfc822_fixed_date (char *date)
579 do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
583 /* Write current time in internal format
584 * Accepts: destination string
587 void internal_date (char *date)
589 do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
592 /* Initialize server
593 * Accepts: server name for syslog or NIL
594 * /etc/services service name or NIL
595 * alternate /etc/services service name or NIL
596 * clock interrupt handler
597 * kiss-of-death interrupt handler
598 * hangup interrupt handler
599 * termination interrupt handler
602 void server_init (char *server,char *service,char *sslservice,
603 void *clkint,void *kodint,void *hupint,void *trmint,
604 void *staint)
606 int onceonly = server && service && sslservice;
607 if (onceonly) { /* set server name in syslog */
608 int mask;
609 openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
610 fclose (stderr); /* possibly save a process ID */
611 dorc (NIL,NIL); /* do systemwide configuration */
612 switch (mask = umask (022)){/* check old umask */
613 case 0: /* definitely unreasonable */
614 case 022: /* don't need to change it */
615 break;
616 default: /* already was a reasonable value */
617 umask (mask); /* so change it back */
620 arm_signal (SIGALRM,clkint); /* prepare for clock interrupt */
621 arm_signal (SIGUSR2,kodint); /* prepare for Kiss Of Death */
622 arm_signal (SIGHUP,hupint); /* prepare for hangup */
623 arm_signal (SIGPIPE,hupint); /* alternative hangup */
624 arm_signal (SIGTERM,trmint); /* prepare for termination */
625 /* status dump */
626 if (staint) arm_signal (SIGUSR1,staint);
627 if (onceonly) { /* set up network and maybe SSL */
628 long port;
629 struct servent *sv;
630 /* Use SSL if SSL service, or if server starts with "s" and not service */
631 if (((port = tcp_serverport ()) >= 0)) {
632 if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
633 syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
634 else if ((sv = getservbyname (sslservice,"tcp")) &&
635 (port == ntohs (sv->s_port))) {
636 syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
637 tcp_clientaddr ());
638 ssl_server_init (server);
640 else { /* not service or SSL service port */
641 syslog (LOG_DEBUG,"port %ld service init from %s",port,
642 tcp_clientaddr ());
643 if (*server == 's') ssl_server_init (server);
649 /* Wait for stdin input
650 * Accepts: timeout in seconds
651 * Returns: T if have input on stdin, else NIL
654 long server_input_wait (long seconds)
656 int err;
657 fd_set rfd,efd;
658 struct timeval tmo;
659 do {
660 FD_ZERO (&rfd);
661 FD_ZERO (&efd);
662 FD_SET (0,&rfd);
663 FD_SET (0,&efd);
664 tmo.tv_sec = seconds; tmo.tv_usec = 0;
665 } while (((err = select (1,&rfd,0,&efd,&tmo)) < 0) && (errno = EINTR));
666 return err ? LONGT : NIL;
669 /* Return UNIX password entry for user name
670 * Accepts: user name string
671 * Returns: password entry
673 * Tries all-lowercase form of user name if given user name fails
676 static struct passwd *pwuser (unsigned char *user)
678 unsigned char *s;
679 struct passwd *pw = getpwnam (user);
680 if (!pw) { /* failed, see if any uppercase characters */
681 for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
682 if (*s) { /* yes, try all lowercase form */
683 pw = getpwnam (s = lcase (cpystr (user)));
684 fs_give ((void **) &s);
687 return pw;
691 /* Validate password for user name
692 * Accepts: user name string
693 * password string
694 * argument count
695 * argument vector
696 * Returns: password entry if validated
698 * Tries password+1 if password fails and starts with space
701 static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
703 char *s;
704 struct passwd *pw;
705 struct passwd *ret = NIL;
706 if (auth_md5.server) { /* using CRAM-MD5 authentication? */
707 if ((s = auth_md5_pwd (user)) != NULL) {
708 if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
709 ret = pwuser (user); /* validated, get passwd entry for user */
710 memset (s,0,strlen (s)); /* erase sensitive information */
711 fs_give ((void **) &s);
714 else if ((pw = pwuser (user)) != NULL) {/* can get user? */
715 s = cpystr (pw->pw_name); /* copy returned name in case we need it */
716 if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
717 (*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
718 ret = checkpw (pw,pwd+1,argc,argv);
719 fs_give ((void **) &s); /* don't need copy of name any more */
721 return ret;
724 /* Server log in
725 * Accepts: user name string
726 * password string
727 * authenticating user name string
728 * argument count
729 * argument vector
730 * Returns: T if password validated, NIL otherwise
733 long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
735 struct passwd *pw = NIL;
736 int level = LOG_NOTICE;
737 char *err = "failed";
738 /* cretins still haven't given up */
739 if ((strlen (user) >= NETMAXUSER) ||
740 (authuser && (strlen (authuser) >= NETMAXUSER))) {
741 level = LOG_ALERT; /* escalate this alert */
742 err = "SYSTEM BREAK-IN ATTEMPT";
743 logtry = 0; /* render this session useless */
745 else if (logtry-- <= 0) err = "excessive login failures";
746 else if (disablePlaintext) err = "disabled";
747 else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
748 else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
749 if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
750 syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
751 user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
752 sleep (3); /* slow down possible cracker */
753 return NIL;
756 /* Authenticated server log in
757 * Accepts: user name string
758 * authenticating user name string
759 * argument count
760 * argument vector
761 * Returns: T if password validated, NIL otherwise
764 long authserver_login (char *user,char *authuser,int argc,char *argv[])
766 return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
770 /* Log in as anonymous daemon
771 * Accepts: argument count
772 * argument vector
773 * Returns: T if successful, NIL if error
776 long anonymous_login (int argc,char *argv[])
778 /* log in Mr. A. N. Onymous */
779 return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
780 (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
781 argc,argv);
784 /* Finish log in and environment initialization
785 * Accepts: passwd struct for loginpw()
786 * optional authentication user name
787 * user name (NIL for anonymous)
788 * home directory (NIL to use directory from passwd struct)
789 * argument count
790 * argument vector
791 * Returns: T if successful, NIL if error
794 long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
795 char *argv[])
797 struct group *gr;
798 char **t;
799 long ret = NIL;
800 if (pw && pw->pw_uid) { /* must have passwd struct for non-UID 0 */
801 /* make safe copies of user and home */
802 if (user) user = cpystr (pw->pw_name);
803 home = cpystr (home ? home : pw->pw_dir);
804 /* authorization ID .NE. authentication ID? */
805 if (user && auser && *auser && compare_cstring (auser,user)) {
806 /* scan list of mail administrators */
807 if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
808 if (!compare_cstring (auser,*t++))
809 ret = pw_login (pw,NIL,user,home,argc,argv);
810 syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
811 ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
813 else if (closedBox) { /* paranoid site, lock out other directories */
814 if (chdir (home) || chroot (home))
815 syslog (LOG_NOTICE|LOG_AUTH,
816 "Login %s failed: unable to set chroot=%.80s host=%.80s",
817 pw->pw_name,home,tcp_clienthost ());
818 else if (loginpw (pw,argc,argv)) ret = env_init (user,NIL);
819 else fatal ("Login failed after chroot");
821 /* normal login */
822 else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
823 (ret = env_init (user,home))) chdir (myhomedir ());
824 fs_give ((void **) &home); /* clean up */
825 if (user) fs_give ((void **) &user);
827 endpwent (); /* in case shadow passwords in pw data */
828 return ret; /* return status */
831 /* Initialize environment
832 * Accepts: user name (NIL for anonymous)
833 * home directory name
834 * Returns: T, always
837 long env_init (char *user,char *home)
839 extern MAILSTREAM CREATEPROTO;
840 extern MAILSTREAM EMPTYPROTO;
841 struct passwd *pw;
842 struct stat sbuf;
843 char tmp[MAILTMPLEN];
844 /* don't init if blocked */
845 if (block_env_init) return LONGT;
846 if (myUserName) fatal ("env_init called twice!");
847 /* initially nothing in namespace list */
848 nslist[0] = nslist[1] = nslist[2] = NIL;
849 /* myUserName must be set before dorc() call */
850 myUserName = cpystr (user ? user : ANONYMOUSUSER);
851 /* force default prototypes to be set */
852 if (!createProto) createProto = &CREATEPROTO;
853 if (!appendProto) appendProto = &EMPTYPROTO;
854 dorc (NIL,NIL); /* do systemwide configuration */
855 if (!home) { /* closed box server */
856 /* standard user can only reference home */
857 if (user) nslist[0] = &nshome;
858 else { /* anonymous user */
859 nslist[0] = &nsblackother; /* set root */
860 anonymous = T; /* flag as anonymous */
862 myHomeDir = cpystr (""); /* home directory is root */
863 sysInbox = cpystr ("INBOX");/* make system INBOX */
865 else { /* open or black box */
866 closedBox = NIL; /* definitely not a closed box */
867 if (user) { /* remember user name and home directory */
868 if (blackBoxDir) { /* build black box directory name */
869 sprintf (tmp,"%s/%s",blackBoxDir,myUserName);
870 /* must exist */
871 if (!((!stat (home = tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ||
872 (blackBoxDefaultHome &&
873 !stat (home = blackBoxDefaultHome,&sbuf) &&
874 (sbuf.st_mode & S_IFDIR)))) fatal ("no home");
875 sysInbox = (char *) fs_get (strlen (home) + 7);
876 /* set system INBOX */
877 sprintf (sysInbox,"%s/INBOX",home);
878 blackBox = T; /* mark that it's a black box */
879 /* mbox meaningless if black box */
880 mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox");
882 nslist[0] = &nshome; /* home namespace */
883 /* limited advertise namespaces */
884 if (limitedadvertise) nslist[2] = &nslimited;
885 else if (blackBox) { /* black box namespaces */
886 nslist[1] = &nsblackother;
887 nslist[2] = &nsshared;
889 else { /* open box namespaces */
890 nslist[1] = &nsunixother;
891 nslist[2] = advertisetheworld ? &nsworld : &nsshared;
894 else {
895 nslist[2] = &nsftp; /* anonymous user */
896 sprintf (tmp,"%s/INBOX",
897 home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
898 sysInbox = cpystr (tmp); /* make system INBOX */
899 anonymous = T; /* flag as anonymous */
901 myHomeDir = cpystr (home); /* set home directory */
904 if (allowuserconfig) { /* allow user config files */
905 dorc (strcat (strcpy (tmp,myHomeDir),"/.mminit"),T);
906 dorc (strcat (strcpy (tmp,myHomeDir),"/.imaprc"),NIL);
908 if (!closedBox && !noautomaticsharedns) {
909 /* #ftp namespace */
910 if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
911 /* #public namespace */
912 if (!publicHome && (pw = getpwnam ("imappublic")))
913 publicHome = cpystr (pw->pw_dir);
914 /* #shared namespace */
915 if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
916 sharedHome = cpystr (pw->pw_dir);
918 if (!myLocalHost) mylocalhost ();
919 if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
920 if (!newsActive) newsActive = cpystr (ACTIVEFILE);
921 if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
922 /* re-do open action to get flags */
923 (*createProto->dtb->open) (NIL);
924 endpwent (); /* close pw database */
925 return T;
928 /* Return my user name
929 * Accepts: pointer to optional flags
930 * Returns: my user name
933 char *myusername_full (unsigned long *flags)
935 struct passwd *pw;
936 struct stat sbuf;
937 char *s;
938 unsigned long euid;
939 char *ret = UNLOGGEDUSER;
940 /* no user name yet and not root? */
941 if (!myUserName && (euid = geteuid ())) {
942 /* yes, look up getlogin() user name or EUID */
943 if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
944 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
945 (pw = getpwuid (euid))) {
946 if (block_env_init) { /* don't env_init if blocked */
947 if (flags) *flags = MU_LOGGEDIN;
948 return pw->pw_name;
950 env_init (pw->pw_name,
951 ((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
952 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
953 s : pw->pw_dir);
955 else fatal ("Unable to look up user name");
957 if (myUserName) { /* logged in? */
958 if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
959 ret = myUserName; /* return user name */
961 else if (flags) *flags = MU_NOTLOGGEDIN;
962 return ret;
966 /* Return my local host name
967 * Returns: my local host name
970 char *mylocalhost (void)
972 if (!myLocalHost) {
973 char *s,tmp[MAILTMPLEN];
974 tmp[0] = tmp[MAILTMPLEN-1] = '\0';
975 if (!gethostname (tmp,MAILTMPLEN-1) && tmp[0]) {
976 /* sanity check of name */
977 for (s = tmp; (*s > 0x20) && (*s < 0x7f); ++s);
978 if (!*s) myLocalHost = tcp_canonical (tmp);
981 return myLocalHost ? myLocalHost : "unknown";
984 /* Return my home directory name
985 * Returns: my home directory name
988 char *myhomedir (void)
990 if (!myHomeDir) myusername ();/* initialize if first time */
991 return myHomeDir ? myHomeDir : "";
995 /* Return my home mailbox name
996 * Returns: my home directory name
999 static char *mymailboxdir (void)
1001 char *home = myhomedir ();
1002 /* initialize if first time */
1003 if (!myMailboxDir && myHomeDir) {
1004 if (mailsubdir) {
1005 char tmp[MAILTMPLEN];
1006 sprintf (tmp,"%s/%s",home,mailsubdir);
1007 myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
1009 else myMailboxDir = cpystr (home);
1011 return myMailboxDir ? myMailboxDir : "";
1015 /* Return system standard INBOX
1016 * Accepts: buffer string
1019 char *sysinbox (void)
1021 char tmp[MAILTMPLEN];
1022 if (!sysInbox) { /* initialize if first time */
1023 sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
1024 sysInbox = cpystr (tmp); /* system inbox is from mail spool */
1026 return sysInbox;
1029 /* Return mailbox directory name
1030 * Accepts: destination buffer
1031 * directory prefix
1032 * name in directory
1033 * Returns: file name or NIL if error
1036 char *mailboxdir (char *dst,char *dir,char *name)
1038 char tmp[MAILTMPLEN];
1039 if (dir || name) { /* if either argument provided */
1040 if (dir) {
1041 if (strlen (dir) > NETMAXMBX) return NIL;
1042 strcpy (tmp,dir); /* write directory prefix */
1044 else tmp[0] = '\0'; /* otherwise null string */
1045 if (name) {
1046 if (strlen (name) > NETMAXMBX) return NIL;
1047 strcat (tmp,name); /* write name in directory */
1049 /* validate name, return its name */
1050 if (!mailboxfile (dst,tmp)) return NIL;
1052 /* no arguments, wants mailbox directory */
1053 else strcpy (dst,mymailboxdir ());
1054 return dst; /* return the name */
1057 /* Return mailbox file name
1058 * Accepts: destination buffer
1059 * mailbox name
1060 * Returns: file name or empty string for driver-selected INBOX or NIL if error
1063 char *mailboxfile (char *dst,char *name)
1065 struct passwd *pw;
1066 char *s;
1067 if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
1068 ((anonymous || blackBox || restrictBox || (*name == '#')) &&
1069 (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
1070 dst = NIL; /* invalid name */
1071 else switch (*name) { /* determine mailbox type based upon name */
1072 case '#': /* namespace name */
1073 /* #ftp/ namespace */
1074 if (((name[1] == 'f') || (name[1] == 'F')) &&
1075 ((name[2] == 't') || (name[2] == 'T')) &&
1076 ((name[3] == 'p') || (name[3] == 'P')) &&
1077 (name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
1078 /* #public/ and #shared/ namespaces */
1079 else if ((((name[1] == 'p') || (name[1] == 'P')) &&
1080 ((name[2] == 'u') || (name[2] == 'U')) &&
1081 ((name[3] == 'b') || (name[3] == 'B')) &&
1082 ((name[4] == 'l') || (name[4] == 'L')) &&
1083 ((name[5] == 'i') || (name[5] == 'I')) &&
1084 ((name[6] == 'c') || (name[6] == 'C')) &&
1085 (name[7] == '/') && (s = publicHome)) ||
1086 (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
1087 ((name[2] == 'h') || (name[2] == 'H')) &&
1088 ((name[3] == 'a') || (name[3] == 'A')) &&
1089 ((name[4] == 'r') || (name[4] == 'R')) &&
1090 ((name[5] == 'e') || (name[5] == 'E')) &&
1091 ((name[6] == 'd') || (name[6] == 'D')) &&
1092 (name[7] == '/') && (s = sharedHome)))
1093 sprintf (dst,"%s/%s",s,compare_cstring (name+8,"INBOX") ?
1094 name+8 : "INBOX");
1095 else dst = NIL; /* unknown namespace */
1096 break;
1098 case '/': /* root access */
1099 if (anonymous) dst = NIL; /* anonymous forbidden to do this */
1100 else if (blackBox) { /* other user access if blackbox */
1101 if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
1102 /* see if other user INBOX */
1103 else if ((s = strchr (name+1,'/')) && !compare_cstring (s+1,"INBOX")) {
1104 *s = '\0'; /* temporarily tie off string */
1105 sprintf (dst,"%s/%s/INBOX",blackBoxDir,name+1);
1106 *s = '/'; /* in case caller cares */
1108 else sprintf (dst,"%s/%s",blackBoxDir,name+1);
1110 else {
1111 size_t i = strlen (mymailboxdir ());
1112 if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()) &&
1113 (!i || strncmp (name,mymailboxdir (),i) || (name[i] !='/')))
1114 dst = NIL; /* restricted and not sysinbox or home */
1115 else strcpy (dst,name); /* unrestricted, copy root name */
1117 break;
1118 case '~': /* other user access */
1119 /* bad syntax or anonymous can't win */
1120 if (!*++name || anonymous) dst = NIL;
1121 /* ~/ equivalent to ordinary name */
1122 else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
1123 /* other user forbidden if closed/restricted */
1124 else if (closedBox || (restrictBox & RESTRICTOTHERUSER)) dst = NIL;
1125 else if (blackBox) { /* black box form of other user */
1126 /* see if other user INBOX */
1127 if ((s = strchr (name,'/')) && compare_cstring (s+1,"INBOX")) {
1128 *s = '\0'; /* temporarily tie off string */
1129 sprintf (dst,"%s/%s/INBOX",blackBoxDir,name);
1130 *s = '/'; /* in case caller cares */
1132 else sprintf (dst,"%s/%s",blackBoxDir,name);
1134 else { /* clear box other user */
1135 /* copy user name */
1136 for (s = dst; *name && (*name != '/'); *s++ = *name++);
1137 *s++ = '\0'; /* tie off user name, look up in passwd file */
1138 if ((pw = getpwnam (dst)) && pw->pw_dir) {
1139 if (*name) name++; /* skip past the slash */
1140 /* canonicalize case of INBOX */
1141 if (!compare_cstring (name,"INBOX")) name = "INBOX";
1142 /* remove trailing / from directory */
1143 if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
1144 /* don't allow ~root/ if restricted root */
1145 if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
1146 /* build final name w/ subdir if needed */
1147 else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
1148 else sprintf (dst,"%s/%s",pw->pw_dir,name);
1150 else dst = NIL; /* no such user */
1152 break;
1154 case 'I': case 'i': /* possible INBOX */
1155 if (!compare_cstring (name+1,"NBOX")) {
1156 /* if restricted, use INBOX in mailbox dir */
1157 if (anonymous || blackBox || closedBox)
1158 sprintf (dst,"%s/INBOX",mymailboxdir ());
1159 else *dst = '\0'; /* otherwise driver selects the name */
1160 break;
1162 /* drop into to ordinary name case */
1163 default: /* ordinary name is easy */
1164 sprintf (dst,"%s/%s",mymailboxdir (),name);
1165 break;
1167 return dst; /* return final name */
1170 /* Dot-lock file locker
1171 * Accepts: file name to lock
1172 * destination buffer for lock file name
1173 * open file description on file name to lock
1174 * Returns: T if success, NIL if failure
1177 long dotlock_lock (char *file,DOTLOCK *base,int fd)
1179 int i = locktimeout * 60;
1180 int j,mask,retry,pi[2],po[2];
1181 char *s,tmp[MAILTMPLEN];
1182 struct stat sb;
1183 /* flush absurd file name */
1184 if (strlen (file) > 512) return NIL;
1185 /* build lock filename */
1186 sprintf (base->lock,"%s.lock",file);
1187 /* assume no pipe */
1188 base->pipei = base->pipeo = -1;
1189 do { /* make sure not symlink */
1190 if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
1191 /* time out if file older than 5 minutes */
1192 if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
1193 /* try to create the lock */
1194 switch (retry = crexcl (base->lock)) {
1195 case -1: /* OK to retry */
1196 if (!(i%15)) { /* time to notify? */
1197 sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
1198 file,i);
1199 MM_LOG (tmp,WARN);
1201 sleep (1); /* wait 1 second before next try */
1202 break;
1203 case NIL: /* failure, can't retry */
1204 i = 0;
1205 break;
1206 case T: /* success, make sure others can break lock */
1207 chmod (base->lock,(int) dotlock_mode);
1208 return LONGT;
1210 } while (i--); /* until out of retries */
1211 if (retry < 0) { /* still returning retry after locktimeout? */
1212 if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
1213 if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
1214 sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
1215 (long) (time (0) - sb.st_ctime));
1216 MM_LOG (tmp,WARN);
1218 mask = umask (0); /* want our lock protection */
1219 unlink (base->lock); /* try to remove the old file */
1220 /* seize the lock */
1221 if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) dotlock_mode)) >= 0) {
1222 close (i); /* don't need descriptor any more */
1223 sprintf (tmp,"Mailbox %.80s lock overridden",file);
1224 MM_LOG (tmp,NIL);
1225 chmod (base->lock,(int) dotlock_mode);
1226 umask (mask); /* restore old umask */
1227 return LONGT;
1229 umask (mask); /* restore old umask */
1232 if (fd >= 0) switch (errno) {
1233 case EACCES: /* protection failure? */
1234 MM_CRITICAL (NIL); /* go critical */
1235 if (closedBox || !lockpgm); /* can't do on closed box or disabled */
1236 else if ((*lockpgm && stat (lockpgm,&sb)) ||
1237 (!*lockpgm && stat (lockpgm = LOCKPGM1,&sb) &&
1238 stat (lockpgm = LOCKPGM2,&sb) && stat (lockpgm = LOCKPGM3,&sb) &&
1239 stat (lockpgm = LOCKPGM4,&sb)))
1240 lockpgm = NIL; /* disable if can't find lockpgm */
1241 else if (pipe (pi) >= 0) { /* make command pipes */
1242 long cf;
1243 char *argv[4],arg[20];
1244 /* if input pipes usable create output pipes */
1245 if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
1246 /* make sure output pipes are usable */
1247 if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
1248 /* all is good, make inferior process */
1249 else if (!(j = fork ())) {
1250 if (!fork ()) { /* make grandchild so it's inherited by init */
1251 /* prepare argument vector */
1252 sprintf (arg,"%d",fd);
1253 argv[0] = lockpgm; argv[1] = arg;
1254 argv[2] = file; argv[3] = NIL;
1255 /* set parent's I/O to my O/I */
1256 dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
1257 /* close all unnecessary descriptors */
1258 for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
1259 cf >= 3; --cf) if (cf != fd) close (cf);
1260 /* be our own process group */
1261 setpgrp (0,getpid ());
1262 /* now run it */
1263 _exit (execv (argv[0],argv));
1265 _exit (1); /* child is done */
1267 else if (j > 0) { /* parent process */
1268 fd_set rfd;
1269 struct timeval tmo;
1270 FD_ZERO (&rfd);
1271 FD_SET (pi[0],&rfd);
1272 tmo.tv_sec = locktimeout * 60;
1273 grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
1274 /* read response from locking program */
1275 if (select (pi[0]+1,&rfd,0,0,&tmo) &&
1276 (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
1277 /* success, record pipes */
1278 base->pipei = pi[0]; base->pipeo = po[1];
1279 /* close child's side of the pipes */
1280 close (pi[1]); close (po[0]);
1281 MM_NOCRITICAL (NIL);/* no longer critical */
1282 return LONGT;
1285 close (po[0]); close (po[1]);
1287 close (pi[0]); close (pi[1]);
1290 MM_NOCRITICAL (NIL); /* no longer critical */
1291 /* find directory/file delimiter */
1292 if ((s = strrchr (base->lock,'/')) != NULL) {
1293 *s = '\0'; /* tie off at directory */
1294 sprintf(tmp, /* generate default message */
1295 "Mailbox vulnerable - directory %.80s must have 1777 protection",
1296 base->lock);
1297 /* definitely not 1777 if can't stat */
1298 mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
1299 *s = '/'; /* restore lock name */
1300 if (mask != 1777) { /* default warning if not 1777 */
1301 if (!disableLockWarning) MM_LOG (tmp,WARN);
1302 break;
1305 default:
1306 sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
1307 base->lock,strerror (errno));
1308 if (!disableLockWarning) MM_LOG (tmp,WARN);
1309 break;
1311 base->lock[0] = '\0'; /* don't use lock files */
1312 return NIL;
1315 /* Dot-lock file unlocker
1316 * Accepts: lock file name
1317 * Returns: T if success, NIL if failure
1320 long dotlock_unlock (DOTLOCK *base)
1322 long ret = LONGT;
1323 if (base && base->lock[0]) {
1324 if (base->pipei >= 0) { /* if running through a pipe unlocker */
1325 ret = (write (base->pipeo,"+",1) == 1);
1326 /* nuke the pipes */
1327 close (base->pipei); close (base->pipeo);
1329 else ret = !unlink (base->lock);
1331 return ret;
1334 /* Lock file name
1335 * Accepts: scratch buffer
1336 * file name
1337 * type of locking operation (LOCK_SH or LOCK_EX)
1338 * pointer to return PID of locker
1339 * Returns: file descriptor of lock or negative if error
1342 int lockname (char *lock,char *fname,int op,long *pid)
1344 struct stat sbuf;
1345 *pid = 0; /* no locker PID */
1346 return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
1350 /* Lock file descriptor
1351 * Accepts: file descriptor
1352 * lock file name buffer
1353 * type of locking operation (LOCK_SH or LOCK_EX)
1354 * Returns: file descriptor of lock or negative if error
1357 int lockfd (int fd,char *lock,int op)
1359 struct stat sbuf;
1360 return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
1363 /* Lock file name worker
1364 * Accepts: lock file name
1365 * pointer to stat() buffer
1366 * type of locking operation (LOCK_SH or LOCK_EX)
1367 * pointer to return PID of locker
1368 * Returns: file descriptor of lock or negative if error
1371 int lock_work (char *lock,void *sb,int op,long *pid)
1373 struct stat lsb,fsb;
1374 struct stat *sbuf = (struct stat *) sb;
1375 char tmp[MAILTMPLEN];
1376 long i;
1377 int fd;
1378 int mask = umask (0);
1379 if (pid) *pid = 0; /* initialize return PID */
1380 /* make temporary lock file name */
1381 sprintf (lock,"%s/.%lx.%lx",closedBox ? "" : tmpdir,
1382 (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
1383 while (T) { /* until get a good lock */
1384 do switch ((int) chk_notsymlink (lock,&lsb)) {
1385 case 1: /* exists just once */
1386 if (((fd = open (lock,O_RDWR,shlock_mode)) >= 0) ||
1387 (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
1388 case -1: /* name doesn't exist */
1389 fd = open (lock,O_RDWR|O_CREAT|O_EXCL,shlock_mode);
1390 break;
1391 default: /* multiple hard links */
1392 MM_LOG ("hard link to lock name",ERROR);
1393 syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
1394 case 0: /* symlink (already did syslog) */
1395 umask (mask); /* restore old mask */
1396 return -1; /* fail: no lock file */
1397 } while ((fd < 0) && (errno == EEXIST));
1398 if (fd < 0) { /* failed to get file descriptor */
1399 syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
1400 strerror (errno));
1401 if (!closedBox) { /* more explicit snarl for bad configuration */
1402 if (stat (tmpdir,&lsb))
1403 syslog (LOG_CRIT,"SYSTEM ERROR: no %s: %s",tmpdir,strerror (errno));
1404 else if ((lsb.st_mode & 01777) != 01777) {
1405 sprintf (tmp,"Can't lock for write: %.80s must have 1777 protection",
1406 tmpdir);
1407 MM_LOG (tmp,WARN);
1410 umask (mask); /* restore old mask */
1411 return -1; /* fail: can't open lock file */
1414 /* non-blocking form */
1415 if (op & LOCK_NB) i = flock (fd,op);
1416 else { /* blocking form */
1417 (*mailblocknotify) (BLOCK_FILELOCK,NIL);
1418 i = flock (fd,op);
1419 (*mailblocknotify) (BLOCK_NONE,NIL);
1421 if (i) { /* failed, get other process' PID */
1422 if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
1423 (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
1424 *pid = i;
1425 close (fd); /* failed, give up on lock */
1426 umask (mask); /* restore old mask */
1427 return -1; /* fail: can't lock */
1429 /* make sure this lock is good for us */
1430 if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
1431 !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
1432 (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
1433 close (fd); /* lock not right, drop fd and try again */
1435 chmod (lock,shlock_mode); /* make sure mode OK (don't use fchmod()) */
1436 umask (mask); /* restore old mask */
1437 return fd; /* success */
1440 /* Check to make sure not a symlink
1441 * Accepts: file name
1442 * stat buffer
1443 * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
1446 long chk_notsymlink (char *name,void *sb)
1448 struct stat *sbuf = (struct stat *) sb;
1449 /* name exists? */
1450 if (lstat (name,sbuf)) return -1;
1451 /* forbid symbolic link */
1452 if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
1453 MM_LOG ("symbolic link on lock name",ERROR);
1454 syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
1455 name);
1456 return NIL;
1458 return (long) sbuf->st_nlink; /* return number of hard links */
1462 /* Unlock file descriptor
1463 * Accepts: file descriptor
1464 * lock file name from lockfd()
1467 void unlockfd (int fd,char *lock)
1469 /* delete the file if no sharers */
1470 if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
1471 flock (fd,LOCK_UN); /* unlock it */
1472 close (fd); /* close it */
1475 /* Set proper file protection for mailbox
1476 * Accepts: mailbox name
1477 * actual file path name
1478 * Returns: T, always
1481 long set_mbx_protections (char *mailbox,char *path)
1483 struct stat sbuf;
1484 int mode = (int) mbx_protection;
1485 if (*mailbox == '#') { /* possible namespace? */
1486 if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
1487 ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
1488 ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
1489 (mailbox[4] == '/')) mode = (int) ftp_protection;
1490 else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
1491 ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
1492 ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
1493 ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
1494 ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
1495 ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
1496 (mailbox[7] == '/')) mode = (int) public_protection;
1497 else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
1498 ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
1499 ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
1500 ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
1501 ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
1502 ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
1503 (mailbox[7] == '/')) mode = (int) shared_protection;
1505 /* if a directory */
1506 if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
1507 /* set owner search if allow read or write */
1508 if (mode & 0600) mode |= 0100;
1509 if (mode & 060) mode |= 010;/* set group search if allow read or write */
1510 if (mode & 06) mode |= 01; /* set world search if allow read or write */
1511 /* preserve directory SGID bit */
1512 if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
1514 chmod (path,mode); /* set the new protection, ignore failure */
1515 return LONGT;
1518 /* Get proper directory protection
1519 * Accepts: mailbox name
1520 * Returns: directory mode, always
1523 long get_dir_protection (char *mailbox)
1525 if (*mailbox == '#') { /* possible namespace? */
1526 if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
1527 ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
1528 ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
1529 (mailbox[4] == '/')) return ftp_dir_protection;
1530 else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
1531 ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
1532 ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
1533 ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
1534 ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
1535 ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
1536 (mailbox[7] == '/')) return public_dir_protection;
1537 else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
1538 ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
1539 ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
1540 ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
1541 ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
1542 ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
1543 (mailbox[7] == '/')) return shared_dir_protection;
1545 return dir_protection;
1548 /* Determine default prototype stream to user
1549 * Accepts: type (NIL for create, T for append)
1550 * Returns: default prototype stream
1553 MAILSTREAM *default_proto (long type)
1555 myusername (); /* make sure initialized */
1556 /* return default driver's prototype */
1557 return type ? appendProto : createProto;
1561 /* Set up user flags for stream
1562 * Accepts: MAIL stream
1563 * Returns: MAIL stream with user flags set up
1566 MAILSTREAM *user_flags (MAILSTREAM *stream)
1568 int i;
1569 myusername (); /* make sure initialized */
1570 for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
1571 if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
1572 return stream;
1576 /* Return nth user flag
1577 * Accepts: user flag number
1578 * Returns: flag
1581 char *default_user_flag (unsigned long i)
1583 myusername (); /* make sure initialized */
1584 return userFlags[i];
1587 /* Process rc file
1588 * Accepts: file name
1589 * .mminit flag
1590 * Don't use this feature.
1593 void dorc (char *file,long flag)
1595 int i;
1596 char *s,*t,*k,*r,tmp[MAILTMPLEN],tmpx[MAILTMPLEN];
1597 extern MAILSTREAM CREATEPROTO;
1598 extern MAILSTREAM EMPTYPROTO;
1599 DRIVER *d;
1600 FILE *f;
1601 if ((f = fopen (file ? file : SYSCONFIG,"r")) &&
1602 (s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))) do {
1603 *t++ = '\0'; /* tie off line, find second space */
1604 if ((k = strchr (s,' ')) && (k = strchr (++k,' '))) {
1605 *k++ = '\0'; /* tie off two words */
1606 if (!compare_cstring (s,"set keywords") && !userFlags[0]) {
1607 /* yes, get first keyword */
1608 k = strtok_r (k,", ",&r);
1609 /* copy keyword list */
1610 for (i = 0; k && i < NUSERFLAGS; ++i) if (strlen (k) <= MAXUSERFLAG) {
1611 if (userFlags[i]) fs_give ((void **) &userFlags[i]);
1612 userFlags[i] = cpystr (k);
1613 k = strtok_r (NIL,", ",&r);
1615 if (flag) break; /* found "set keywords" in .mminit */
1618 else if (!flag) { /* none of these valid in .mminit */
1619 if (myUserName) { /* only valid if logged in */
1620 if (!compare_cstring (s,"set new-mailbox-format") ||
1621 !compare_cstring (s,"set new-folder-format")) {
1622 if (!compare_cstring (k,"same-as-inbox")) {
1623 if ((d = mail_valid (NIL,"INBOX",NIL)) != NULL) {
1624 if (!compare_cstring (d->name,"mbox"))
1625 d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,
1626 (void *) "unix");
1627 else if (!compare_cstring (d->name,"dummy")) d = NIL;
1629 createProto = d ? ((*d->open) (NIL)) : &CREATEPROTO;
1631 else if (!compare_cstring (k,"system-standard"))
1632 createProto = &CREATEPROTO;
1633 else { /* canonicalize mbox to unix */
1634 if (!compare_cstring (k,"mbox")) k = "unix";
1635 /* see if a driver name */
1636 if ((d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,(void *) k)) != NULL)
1637 createProto = (*d->open) (NIL);
1638 else { /* duh... */
1639 sprintf (tmpx,"Unknown new mailbox format in %s: %s",
1640 file ? file : SYSCONFIG,k);
1641 MM_LOG (tmpx,WARN);
1645 if (!compare_cstring (s,"set empty-mailbox-format") ||
1646 !compare_cstring (s,"set empty-folder-format")) {
1647 if (!compare_cstring (k,"invalid")) appendProto = NIL;
1648 else if (!compare_cstring (k,"same-as-inbox"))
1649 appendProto = ((d = mail_valid (NIL,"INBOX",NIL)) &&
1650 compare_cstring (d->name,"dummy")) ?
1651 ((*d->open) (NIL)) : &EMPTYPROTO;
1652 else if (!compare_cstring (k,"system-standard"))
1653 appendProto = &EMPTYPROTO;
1654 else { /* see if a driver name */
1655 for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
1656 d && compare_cstring (d->name,k); d = d->next);
1657 if (d) appendProto = (*d->open) (NIL);
1658 else { /* duh... */
1659 sprintf (tmpx,"Unknown empty mailbox format in %s: %s",
1660 file ? file : SYSCONFIG,k);
1661 MM_LOG (tmpx,WARN);
1667 if (!compare_cstring (s,"set local-host")) {
1668 fs_give ((void **) &myLocalHost);
1669 myLocalHost = cpystr (k);
1671 else if (!compare_cstring (s,"set news-active-file")) {
1672 fs_give ((void **) &newsActive);
1673 newsActive = cpystr (k);
1675 else if (!compare_cstring (s,"set news-spool-directory")) {
1676 fs_give ((void **) &newsSpool);
1677 newsSpool = cpystr (k);
1679 else if (!compare_cstring (s,"set mh-path"))
1680 mail_parameters (NIL,SET_MHPATH,(void *) k);
1681 else if (!compare_cstring (s,"set mh-allow-inbox"))
1682 mail_parameters (NIL,SET_MHALLOWINBOX,(void *) atol (k));
1683 else if (!compare_cstring (s,"set news-state-file")) {
1684 fs_give ((void **) &myNewsrc);
1685 myNewsrc = cpystr (k);
1687 else if (!compare_cstring (s,"set ftp-export-directory")) {
1688 fs_give ((void **) &ftpHome);
1689 ftpHome = cpystr (k);
1691 else if (!compare_cstring (s,"set public-home-directory")) {
1692 fs_give ((void **) &publicHome);
1693 publicHome = cpystr (k);
1695 else if (!compare_cstring (s,"set shared-home-directory")) {
1696 fs_give ((void **) &sharedHome);
1697 sharedHome = cpystr (k);
1699 else if (!compare_cstring (s,"set system-inbox")) {
1700 fs_give ((void **) &sysInbox);
1701 sysInbox = cpystr (k);
1703 else if (!compare_cstring (s,"set mail-subdirectory")) {
1704 fs_give ((void **) &mailsubdir);
1705 mailsubdir = cpystr (k);
1707 else if (!compare_cstring (s,"set from-widget"))
1708 mail_parameters (NIL,SET_FROMWIDGET,
1709 compare_cstring (k,"header-only") ?
1710 VOIDT : NIL);
1712 else if (!compare_cstring (s,"set rsh-command"))
1713 mail_parameters (NIL,SET_RSHCOMMAND,(void *) k);
1714 else if (!compare_cstring (s,"set rsh-path"))
1715 mail_parameters (NIL,SET_RSHPATH,(void *) k);
1716 else if (!compare_cstring (s,"set ssh-command"))
1717 mail_parameters (NIL,SET_SSHCOMMAND,(void *) k);
1718 else if (!compare_cstring (s,"set ssh-path"))
1719 mail_parameters (NIL,SET_SSHPATH,(void *) k);
1720 else if (!compare_cstring (s,"set tcp-open-timeout"))
1721 mail_parameters (NIL,SET_OPENTIMEOUT,(void *) atol (k));
1722 else if (!compare_cstring (s,"set tcp-read-timeout"))
1723 mail_parameters (NIL,SET_READTIMEOUT,(void *) atol (k));
1724 else if (!compare_cstring (s,"set tcp-write-timeout"))
1725 mail_parameters (NIL,SET_WRITETIMEOUT,(void *) atol (k));
1726 else if (!compare_cstring (s,"set rsh-timeout"))
1727 mail_parameters (NIL,SET_RSHTIMEOUT,(void *) atol (k));
1728 else if (!compare_cstring (s,"set ssh-timeout"))
1729 mail_parameters (NIL,SET_SSHTIMEOUT,(void *) atol (k));
1730 else if (!compare_cstring (s,"set maximum-login-trials"))
1731 mail_parameters (NIL,SET_MAXLOGINTRIALS,(void *) atol (k));
1732 else if (!compare_cstring (s,"set lookahead"))
1733 mail_parameters (NIL,SET_LOOKAHEAD,(void *) atol (k));
1734 else if (!compare_cstring (s,"set prefetch"))
1735 mail_parameters (NIL,SET_PREFETCH,(void *) atol (k));
1736 else if (!compare_cstring (s,"set close-on-error"))
1737 mail_parameters (NIL,SET_CLOSEONERROR,(void *) atol (k));
1738 else if (!compare_cstring (s,"set imap-port"))
1739 mail_parameters (NIL,SET_IMAPPORT,(void *) atol (k));
1740 else if (!compare_cstring (s,"set pop3-port"))
1741 mail_parameters (NIL,SET_POP3PORT,(void *) atol (k));
1742 else if (!compare_cstring (s,"set uid-lookahead"))
1743 mail_parameters (NIL,SET_UIDLOOKAHEAD,(void *) atol (k));
1744 else if (!compare_cstring (s,"set try-ssl-first"))
1745 mail_parameters (NIL,SET_TRYSSLFIRST,(void *) atol (k));
1747 else if (!compare_cstring (s,"set mailbox-protection"))
1748 mbx_protection = atol (k);
1749 else if (!compare_cstring (s,"set directory-protection"))
1750 dir_protection = atol (k);
1751 else if (!compare_cstring (s,"set lock-protection"))
1752 dotlock_mode = atol (k);
1753 else if (!compare_cstring (s,"set ftp-protection"))
1754 ftp_protection = atol (k);
1755 else if (!compare_cstring (s,"set public-protection"))
1756 public_protection = atol (k);
1757 else if (!compare_cstring (s,"set shared-protection"))
1758 shared_protection = atol (k);
1759 else if (!compare_cstring (s,"set ftp-directory-protection"))
1760 ftp_dir_protection = atol (k);
1761 else if (!compare_cstring (s,"set public-directory-protection"))
1762 public_dir_protection = atol (k);
1763 else if (!compare_cstring (s,"set shared-directory-protection"))
1764 shared_dir_protection = atol (k);
1765 else if (!compare_cstring (s,"set dot-lock-file-timeout"))
1766 locktimeout = atoi (k);
1767 else if (!compare_cstring (s,"set disable-fcntl-locking"))
1768 fcntlhangbug = atoi (k);
1769 else if (!compare_cstring (s,"set disable-lock-warning"))
1770 disableLockWarning = atoi (k);
1771 else if (!compare_cstring (s,"set disable-unix-UIDs-and-keywords"))
1772 has_no_life = atoi (k);
1773 else if (!compare_cstring (s,"set hide-dot-files"))
1774 hideDotFiles = atoi (k);
1775 else if (!compare_cstring (s,"set list-maximum-level"))
1776 list_max_level = atol (k);
1777 else if (!compare_cstring (s,"set trust-dns"))
1778 mail_parameters (NIL,SET_TRUSTDNS,(void *) atol (k));
1779 else if (!compare_cstring (s,"set sasl-uses-ptr-name"))
1780 mail_parameters (NIL,SET_SASLUSESPTRNAME,(void *) atol (k));
1781 else if (!compare_cstring (s,"set network-filesystem-stat-bug"))
1782 netfsstatbug = atoi (k);
1783 else if (!compare_cstring (s,"set nntp-range"))
1784 mail_parameters (NIL,SET_NNTPRANGE,(void *) atol (k));
1786 else if (!file) { /* only allowed in system init */
1787 if (!compare_cstring (s,"set black-box-directory") &&
1788 !blackBoxDir) blackBoxDir = cpystr (k);
1789 else if (!compare_cstring(s,"set black-box-default-home-directory")&&
1790 blackBoxDir && !blackBoxDefaultHome)
1791 blackBoxDefaultHome = cpystr (k);
1792 else if (!compare_cstring (s,"set anonymous-home-directory") &&
1793 !anonymousHome) anonymousHome = cpystr (k);
1794 /* It's tempting to allow setting the CA path
1795 * in a user init. However, that opens up a
1796 * vector of attack big enough to drive a
1797 * truck through... Resist the temptation.
1799 else if (!compare_cstring (s,"set CA-certificate-path"))
1800 sslCApath = cpystr (k);
1801 else if (!compare_cstring (s,"set CA-certificate-container"))
1802 sslCAfile = cpystr (k);
1803 else if (!compare_cstring (s,"set disable-plaintext"))
1804 disablePlaintext = atoi (k);
1805 else if (!compare_cstring (s,"set allowed-login-attempts"))
1806 logtry = atoi (k);
1807 else if (!compare_cstring (s,"set chroot-server"))
1808 closedBox = atoi (k);
1809 else if (!compare_cstring (s,"set restrict-mailbox-access"))
1810 for (k = strtok_r (k,", ",&r); k; k = strtok_r (NIL,", ",&r)) {
1811 if (!compare_cstring (k,"root")) restrictBox |= RESTRICTROOT;
1812 else if (!compare_cstring (k,"otherusers"))
1813 restrictBox |= RESTRICTOTHERUSER;
1814 else if (!compare_cstring (k,"all")) restrictBox = -1;
1816 else if (!compare_cstring (s,"set advertise-the-world"))
1817 advertisetheworld = atoi (k);
1818 else if (!compare_cstring (s,"set limited-advertise"))
1819 limitedadvertise = atoi (k);
1820 else if (!compare_cstring
1821 (s,"set disable-automatic-shared-namespaces"))
1822 noautomaticsharedns = atoi (k);
1823 else if (!compare_cstring (s,"set allow-user-config"))
1824 allowuserconfig = atoi (k);
1825 else if (!compare_cstring (s,"set allow-reverse-dns"))
1826 mail_parameters (NIL,SET_ALLOWREVERSEDNS,(void *) atol (k));
1827 else if (!compare_cstring (s,"set k5-cp-uses-service-name"))
1828 kerb_cp_svr_name = atoi (k);
1829 /* must appear in file after any
1830 * "set disable-plaintext" command! */
1831 else if (!compare_cstring (s,"set plaintext-allowed-clients")) {
1832 for (k = strtok_r (k,", ",&r); k && !tcp_isclienthost (k);
1833 k = strtok_r (NIL,", ",&r));
1834 if (k) disablePlaintext = 0;
1839 } while ((s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n')));
1840 if (f) fclose (f); /* flush the file */
1843 /* INBOX create function for tmail/dmail use only
1844 * Accepts: mail stream
1845 * path name buffer, preloaded with driver-dependent path
1846 * Returns: T on success, NIL on failure
1848 * This routine is evil and a truly incredible kludge. It is private for
1849 * tmail/dmail and is not supported for any other application.
1852 long path_create (MAILSTREAM *stream,char *path)
1854 long ret;
1855 short rsave = restrictBox;
1856 restrictBox = NIL; /* can't restrict */
1857 if (blackBox) { /* if black box */
1858 /* toss out driver dependent names */
1859 sprintf (path,"%s/INBOX",mymailboxdir ());
1860 blackBox = NIL; /* well that's evil - evil is going on */
1861 ret = mail_create (stream,path);
1862 blackBox = T; /* restore the box */
1864 /* easy thing otherwise */
1865 else ret = mail_create (stream,path);
1866 restrictBox = rsave; /* restore restrictions */
1867 return ret;
1870 /* Default block notify routine
1871 * Accepts: reason for calling
1872 * data
1873 * Returns: data
1876 void *mm_blocknotify (int reason,void *data)
1878 void *ret = data;
1879 switch (reason) {
1880 case BLOCK_SENSITIVE: /* entering sensitive code */
1881 ret = (void *) (unsigned long) alarm (0);
1882 break;
1883 case BLOCK_NONSENSITIVE: /* exiting sensitive code */
1884 if ((unsigned long) data) alarm ((unsigned long) data);
1885 break;
1886 default: /* ignore all other reasons */
1887 break;
1889 return ret;
1892 void env_end(void)
1894 if(myMailboxDir) fs_give((void **) &myMailboxDir);
1895 if(myUserName) fs_give((void **)&myUserName);
1896 if(myHomeDir) fs_give((void **)&myHomeDir);
1897 if(ftpHome) fs_give((void **)&ftpHome);
1898 if(myServerName) fs_give((void **)&myServerName);
1899 if(myLocalHost) fs_give((void **)&myLocalHost);
1900 if(myNewsrc) fs_give((void **)&myNewsrc);
1901 if(mailsubdir) fs_give((void **)&mailsubdir);
1902 if(sysInbox) fs_give((void **)&sysInbox);
1903 if(newsActive) fs_give((void **)&newsActive);
1904 if(newsSpool) fs_give((void **)&newsSpool);
1905 if(blackBoxDir) fs_give((void **)&blackBoxDir);
1906 if(blackBoxDefaultHome)
1907 fs_give((void **)&blackBoxDefaultHome);
1908 if(sslCApath) fs_give((void **)&sslCApath);
1909 if(sslCAfile) fs_give((void **)&sslCAfile);
1910 if(userFlags){
1911 int i;
1912 for(i = 0; i < NUSERFLAGS; i++)
1913 if(userFlags[i]) fs_give((void **)&userFlags[i]);