1 /* ========================================================================
2 * Copyright 2008-2010 Mark Crispin
3 * ========================================================================
7 * Program: UNIX environment routines
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
31 /* in case stat.h is ancient */
34 #define S_IRUSR S_IREAD
37 #define S_IWUSR S_IWRITE
40 #define S_IXUSR S_IEXEC
43 #define S_IRGRP (S_IREAD >> 3)
46 #define S_IWGRP (S_IWRITE >> 3)
49 #define S_IXGRP (S_IEXEC >> 3)
52 #define S_IROTH (S_IREAD >> 6)
55 #define S_IWOTH (S_IWRITE >> 6)
58 #define S_IXOTH (S_IEXEC >> 6)
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
;
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
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
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.
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
};
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 */
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
)
274 switch ((int) function
) {
276 ret
= (void *) nslist
;
279 if (myUserName
) fs_give ((void **) &myUserName
);
280 myUserName
= cpystr ((char *) value
);
282 ret
= (void *) myUserName
;
285 if (myHomeDir
) fs_give ((void **) &myHomeDir
);
286 myHomeDir
= cpystr ((char *) value
);
288 ret
= (void *) myHomeDir
;
291 if (myLocalHost
) fs_give ((void **) &myLocalHost
);
292 myLocalHost
= cpystr ((char *) value
);
294 ret
= (void *) myLocalHost
;
297 if (myNewsrc
) fs_give ((void **) &myNewsrc
);
298 myNewsrc
= cpystr ((char *) value
);
300 ret
= (void *) myNewsrc
;
303 if (newsActive
) fs_give ((void **) &newsActive
);
304 newsActive
= cpystr ((char *) value
);
306 ret
= (void *) newsActive
;
309 if (newsSpool
) fs_give ((void **) &newsSpool
);
310 newsSpool
= cpystr ((char *) value
);
312 ret
= (void *) newsSpool
;
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
;
323 if (ftpHome
) fs_give ((void **) &ftpHome
);
324 ftpHome
= cpystr ((char *) value
);
326 ret
= (void *) ftpHome
;
329 if (publicHome
) fs_give ((void **) &publicHome
);
330 publicHome
= cpystr ((char *) value
);
332 ret
= (void *) publicHome
;
335 if (sharedHome
) fs_give ((void **) &sharedHome
);
336 sharedHome
= cpystr ((char *) value
);
338 ret
= (void *) sharedHome
;
341 if (sysInbox
) fs_give ((void **) &sysInbox
);
342 sysInbox
= cpystr ((char *) value
);
344 ret
= (void *) sysInbox
;
346 case SET_SSLCAPATH
: /* this can be set null */
347 if (sslCApath
) fs_give ((void **) &sslCApath
);
348 sslCApath
= value
? cpystr ((char *) value
) : value
;
351 ret
= (void *) sslCApath
;
353 case SET_SSLCAFILE
: /* this can be set null */
354 if (sslCAfile
) fs_give ((void **) &sslCAfile
);
355 sslCAfile
= value
? cpystr ((char *) value
) : value
;
358 ret
= (void *) sslCAfile
;
360 case SET_SSLAPPCAPATH
: /* this can be set null */
361 if (sslAppCApath
) fs_give ((void **) &sslAppCApath
);
362 sslAppCApath
= value
? cpystr ((char *) value
) : value
;
364 case GET_SSLAPPCAPATH
:
365 ret
= (void *) sslAppCApath
;
367 case SET_SSLAPPCAFILE
: /* this can be set null */
368 if (sslAppCAfile
) fs_give ((void **) &sslAppCAfile
);
369 sslAppCAfile
= value
? cpystr ((char *) value
) : value
;
371 case GET_SSLAPPCAFILE
:
372 ret
= (void *) sslAppCAfile
;
374 case SET_SSLCIPHERS
: /* this can be set null */
375 if (sslciphers
) fs_give ((void **) &sslciphers
);
376 sslciphers
= value
? cpystr ((char *) value
) : value
;
379 ret
= (void *) sslciphers
;
381 case SET_LISTMAXLEVEL
:
382 list_max_level
= (long) value
;
383 case GET_LISTMAXLEVEL
:
384 ret
= (void *) list_max_level
;
387 case SET_MBXPROTECTION
:
388 mbx_protection
= (long) value
;
389 case GET_MBXPROTECTION
:
390 ret
= (void *) mbx_protection
;
392 case SET_DIRPROTECTION
:
393 dir_protection
= (long) value
;
394 case GET_DIRPROTECTION
:
395 ret
= (void *) dir_protection
;
397 case SET_LOCKPROTECTION
:
398 dotlock_mode
= (long) value
;
399 case GET_LOCKPROTECTION
:
400 ret
= (void *) dotlock_mode
;
402 case SET_FTPPROTECTION
:
403 ftp_protection
= (long) value
;
404 case GET_FTPPROTECTION
:
405 ret
= (void *) ftp_protection
;
407 case SET_PUBLICPROTECTION
:
408 public_protection
= (long) value
;
409 case GET_PUBLICPROTECTION
:
410 ret
= (void *) public_protection
;
412 case SET_SHAREDPROTECTION
:
413 shared_protection
= (long) value
;
414 case GET_SHAREDPROTECTION
:
415 ret
= (void *) shared_protection
;
417 case SET_FTPDIRPROTECTION
:
418 ftp_dir_protection
= (long) value
;
419 case GET_FTPDIRPROTECTION
:
420 ret
= (void *) ftp_dir_protection
;
422 case SET_PUBLICDIRPROTECTION
:
423 public_dir_protection
= (long) value
;
424 case GET_PUBLICDIRPROTECTION
:
425 ret
= (void *) public_dir_protection
;
427 case SET_SHAREDDIRPROTECTION
:
428 shared_dir_protection
= (long) value
;
429 case GET_SHAREDDIRPROTECTION
:
430 ret
= (void *) shared_dir_protection
;
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
;
442 case SET_DISABLEFCNTLLOCK
:
443 fcntlhangbug
= value
? T
: NIL
;
444 case GET_DISABLEFCNTLLOCK
:
445 ret
= (void *) (fcntlhangbug
? VOIDT
: NIL
);
447 case SET_LOCKEACCESERROR
:
448 disableLockWarning
= value
? NIL
: T
;
449 case GET_LOCKEACCESERROR
:
450 ret
= (void *) (disableLockWarning
? NIL
: VOIDT
);
452 case SET_HIDEDOTFILES
:
453 hideDotFiles
= value
? T
: NIL
;
454 case GET_HIDEDOTFILES
:
455 ret
= (void *) (hideDotFiles
? VOIDT
: NIL
);
457 case SET_DISABLEPLAINTEXT
:
458 disablePlaintext
= (long) value
;
459 case GET_DISABLEPLAINTEXT
:
460 ret
= (void *) disablePlaintext
;
462 case SET_CHROOTSERVER
:
463 closedBox
= value
? T
: NIL
;
464 case GET_CHROOTSERVER
:
465 ret
= (void *) (closedBox
? VOIDT
: NIL
);
467 case SET_ADVERTISETHEWORLD
:
468 advertisetheworld
= value
? T
: NIL
;
469 case GET_ADVERTISETHEWORLD
:
470 ret
= (void *) (advertisetheworld
? VOIDT
: NIL
);
472 case SET_LIMITEDADVERTISE
:
473 limitedadvertise
= value
? T
: NIL
;
474 case GET_LIMITEDADVERTISE
:
475 ret
= (void *) (limitedadvertise
? VOIDT
: NIL
);
477 case SET_DISABLEAUTOSHAREDNS
:
478 noautomaticsharedns
= value
? T
: NIL
;
479 case GET_DISABLEAUTOSHAREDNS
:
480 ret
= (void *) (noautomaticsharedns
? VOIDT
: NIL
);
482 case SET_DISABLE822TZTEXT
:
483 no822tztext
= value
? T
: NIL
;
484 case GET_DISABLE822TZTEXT
:
485 ret
= (void *) (no822tztext
? VOIDT
: NIL
);
488 case SET_USERHASNOLIFE
:
489 has_no_life
= value
? T
: NIL
;
490 case GET_USERHASNOLIFE
:
491 ret
= (void *) (has_no_life
? VOIDT
: NIL
);
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
);
498 case SET_NETFSSTATBUG
:
499 netfsstatbug
= value
? T
: NIL
;
500 case GET_NETFSSTATBUG
:
501 ret
= (void *) (netfsstatbug
? VOIDT
: NIL
);
503 case SET_BLOCKENVINIT
:
504 block_env_init
= value
? T
: NIL
;
505 case GET_BLOCKENVINIT
:
506 ret
= (void *) (block_env_init
? VOIDT
: NIL
);
508 case SET_BLOCKNOTIFY
:
509 mailblocknotify
= (blocknotify_t
) value
;
510 case GET_BLOCKNOTIFY
:
511 ret
= (void *) mailblocknotify
;
514 maillogouthook
= (logouthook_t
) value
;
516 ret
= maillogouthook
;
519 maillogoutdata
= (void *) value
;
521 ret
= maillogoutdata
;
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
);
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
,
606 int onceonly
= server
&& service
&& sslservice
;
607 if (onceonly
) { /* set server name in syslog */
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 */
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 */
626 if (staint
) arm_signal (SIGUSR1
,staint
);
627 if (onceonly
) { /* set up network and maybe SSL */
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
,
638 ssl_server_init (server
);
640 else { /* not service or SSL service port */
641 syslog (LOG_DEBUG
,"port %ld service init from %s",port
,
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
)
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
)
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
);
691 /* Validate password for user name
692 * Accepts: user name string
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
[])
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 */
725 * Accepts: user name string
727 * authenticating user name string
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 */
756 /* Authenticated server log in
757 * Accepts: user name string
758 * authenticating user name string
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
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
),
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)
791 * Returns: T if successful, NIL if error
794 long pw_login (struct passwd
*pw
,char *auser
,char *user
,char *home
,int argc
,
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");
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
837 long env_init (char *user
,char *home
)
839 extern MAILSTREAM CREATEPROTO
;
840 extern MAILSTREAM EMPTYPROTO
;
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
);
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
;
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
) {
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 */
928 /* Return my user name
929 * Accepts: pointer to optional flags
930 * Returns: my user name
933 char *myusername_full (unsigned long *flags
)
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
;
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
)) ?
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
;
966 /* Return my local host name
967 * Returns: my local host name
970 char *mylocalhost (void)
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
) {
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 */
1029 /* Return mailbox directory name
1030 * Accepts: destination buffer
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 */
1041 if (strlen (dir
) > NETMAXMBX
) return NIL
;
1042 strcpy (tmp
,dir
); /* write directory prefix */
1044 else tmp
[0] = '\0'; /* otherwise null string */
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
1060 * Returns: file name or empty string for driver-selected INBOX or NIL if error
1063 char *mailboxfile (char *dst
,char *name
)
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") ?
1095 else dst
= NIL
; /* unknown namespace */
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);
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 */
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 */
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 */
1162 /* drop into to ordinary name case */
1163 default: /* ordinary name is easy */
1164 sprintf (dst
,"%s/%s",mymailboxdir (),name
);
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
];
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...",
1201 sleep (1); /* wait 1 second before next try */
1203 case NIL
: /* failure, can't retry */
1206 case T
: /* success, make sure others can break lock */
1207 chmod (base
->lock
,(int) dotlock_mode
);
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
));
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
);
1225 chmod (base
->lock
,(int) dotlock_mode
);
1226 umask (mask
); /* restore old umask */
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 */
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 ());
1263 _exit (execv (argv
[0],argv
));
1265 _exit (1); /* child is done */
1267 else if (j
> 0) { /* parent process */
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 */
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",
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
);
1306 sprintf (tmp
,"Mailbox vulnerable - error creating %.80s: %s",
1307 base
->lock
,strerror (errno
));
1308 if (!disableLockWarning
) MM_LOG (tmp
,WARN
);
1311 base
->lock
[0] = '\0'; /* don't use lock files */
1315 /* Dot-lock file unlocker
1316 * Accepts: lock file name
1317 * Returns: T if success, NIL if failure
1320 long dotlock_unlock (DOTLOCK
*base
)
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
);
1335 * Accepts: scratch buffer
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
)
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
)
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
];
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
);
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
,
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",
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
);
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))
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
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
;
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",
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
)
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 */
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
)
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
]);
1576 /* Return nth user flag
1577 * Accepts: user flag number
1581 char *default_user_flag (unsigned long i
)
1583 myusername (); /* make sure initialized */
1584 return userFlags
[i
];
1588 * Accepts: file name
1590 * Don't use this feature.
1593 void dorc (char *file
,long flag
)
1596 char *s
,*t
,*k
,*r
,tmp
[MAILTMPLEN
],tmpx
[MAILTMPLEN
];
1597 extern MAILSTREAM CREATEPROTO
;
1598 extern MAILSTREAM EMPTYPROTO
;
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
,
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
);
1639 sprintf (tmpx
,"Unknown new mailbox format in %s: %s",
1640 file
? file
: SYSCONFIG
,k
);
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
);
1659 sprintf (tmpx
,"Unknown empty mailbox format in %s: %s",
1660 file
? file
: SYSCONFIG
,k
);
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") ?
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"))
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
)
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 */
1870 /* Default block notify routine
1871 * Accepts: reason for calling
1876 void *mm_blocknotify (int reason
,void *data
)
1880 case BLOCK_SENSITIVE
: /* entering sensitive code */
1881 ret
= (void *) (unsigned long) alarm (0);
1883 case BLOCK_NONSENSITIVE
: /* exiting sensitive code */
1884 if ((unsigned long) data
) alarm ((unsigned long) data
);
1886 default: /* ignore all other reasons */
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
);
1912 for(i
= 0; i
< NUSERFLAGS
; i
++)
1913 if(userFlags
[i
]) fs_give((void **)&userFlags
[i
]);