]> granicus.if.org Git - uw-imap/commitdiff
add files for 2008-02-15T17:26:44Z
authorUnknown <>
Fri, 15 Feb 2008 17:26:44 +0000 (17:26 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Fri, 7 Sep 2018 00:02:39 +0000 (00:02 +0000)
src/osdep/unix/env_unix.c [new file with mode: 0644]

diff --git a/src/osdep/unix/env_unix.c b/src/osdep/unix/env_unix.c
new file mode 100644 (file)
index 0000000..4d6049e
--- /dev/null
@@ -0,0 +1,1841 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:    UNIX environment routines
+ *
+ * Author:     Mark Crispin
+ *             UW Technology
+ *             University of Washington
+ *             Seattle, WA  98195
+ *             Internet: MRC@Washington.EDU
+ *
+ * Date:       1 August 1988
+ * Last Edited:        15 February 2008
+ */
+
+#include <grp.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+
+/* in case stat.h is ancient */
+
+#ifndef S_IRUSR
+#define S_IRUSR S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR S_IWRITE
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR S_IEXEC
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP (S_IREAD >> 3)
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP (S_IWRITE >> 3)
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP (S_IEXEC >> 3)
+#endif
+#ifndef S_IROTH
+#define S_IROTH (S_IREAD >> 6)
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH (S_IWRITE >> 6)
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH (S_IEXEC >> 6)
+#endif
+\f
+/* c-client environment parameters */
+
+static char *myUserName = NIL; /* user name */
+static char *myHomeDir = NIL;  /* home directory name */
+static char *myServerName = NIL;/* server name */
+static char *myLocalHost = NIL;        /* local host name */
+static char *myNewsrc = NIL;   /* newsrc file name */
+static char *mailsubdir = NIL; /* mailbox subdirectory name */
+static char *sysInbox = NIL;   /* system inbox name */
+static char *newsActive = NIL; /* news active file */
+static char *newsSpool = NIL;  /* news spool */
+static char *blackBoxDir = NIL;        /* black box directory name */
+                               /* black box default home directory */
+static char *blackBoxDefaultHome = NIL;
+static char *sslCApath = NIL;  /* non-standard CA path */
+static short anonymous = NIL;  /* is anonymous */
+static short blackBox = NIL;   /* is a black box */
+static short closedBox = NIL;  /* is a closed box (uses chroot() jail) */
+static short restrictBox = NIL;        /* is a restricted box */
+static short has_no_life = NIL;        /* is a cretin with no life */
+                               /* block environment init */
+static short block_env_init = NIL;
+static short hideDotFiles = NIL;/* hide files whose names start with . */
+                               /* advertise filesystem root */
+static short advertisetheworld = NIL;
+                               /* only advertise own mailboxes and #shared */
+static short limitedadvertise = NIL;
+                               /* disable automatic shared namespaces */
+static short noautomaticsharedns = NIL;
+static short no822tztext = NIL;        /* disable RFC [2]822 timezone text */
+                               /* client principals include service name */
+static short kerb_cp_svr_name = NIL;
+static long locktimeout = 5;   /* default lock timeout in minutes */
+                               /* default prototypes */
+static MAILSTREAM *createProto = NIL;
+static MAILSTREAM *appendProto = NIL;
+                               /* default user flags */
+static char *userFlags[NUSERFLAGS] = {NIL};
+static NAMESPACE *nslist[3];   /* namespace list */
+static int logtry = 3;         /* number of server login tries */
+                               /* block notification */
+static blocknotify_t mailblocknotify = mm_blocknotify;
+                               /* logout function */
+static logouthook_t maillogouthook = NIL;
+                               /* logout data */
+static void *maillogoutdata = NIL;
+                               /* allow user config files */
+static short allowuserconfig = NIL;
+                               /* 1 = disable plaintext, 2 = if not SSL */
+static long disablePlaintext = NIL;
+static long list_max_level = 20;/* maximum level of list recursion */
+                               /* facility for syslog */
+static int syslog_facility = LOG_MAIL;
+\f
+/* Path of the privileged system lock program (mlock).  Normally set by
+ * logic test.
+ */
+
+static char *lockpgm = LOCKPGM;
+
+/* Directory used for shared locks.  MUST be the same for all users of the
+ * system, and MUST be protected 1777.  /var/tmp may be preferable on some
+ * systems.
+ */
+
+static const char *tmpdir = "/tmp";
+
+/* Do not change shlock_mode.  Doing so can cause mailbox corruption and
+ * denial of service.  It also defeats the entire purpose of the shared
+ * lock mechanism.  The right way to avoid shared locks is to set up a
+ * closed box (see the closedBox setting).
+ */
+
+                               /* shared lock mode */
+static const int shlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+
+
+/* It is STRONGLY recommended that you do not change dotlock_mode.  Doing so
+ * can cause denial of service with old dot-lock files left lying around.
+ * However, since dot-locks are only used with traditional UNIX and MMDF
+ * formats which are not normally shared, it is much less harmful to tamper
+ * with this than with shlock_mode.
+ */
+
+                               /* dot-lock mode */
+static long dotlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+\f
+/* File/directory access and protection policies */
+
+/* Unlike shlock_mode, the ????_protection modes are intended to be fully
+ * customizable according to site policy.  The values here are recommended
+ * settings, based upon the documented purposes of the namespaces.
+ */
+
+       /* user space - only owner can read/write */
+static char *myMailboxDir = NIL;/* user space directory name */
+                               /* default file protection */
+static long mbx_protection = S_IRUSR|S_IWUSR;
+                               /* default directory protection */
+static long dir_protection = S_IRUSR|S_IWUSR|S_IXUSR;
+
+       /* user space for user "anonymous" */
+                               /* anonymous home directory */
+static char *anonymousHome = NIL;
+
+       /* #ftp - everybody can read, only owner can write */
+static char *ftpHome = NIL;    /* ftp export home directory */
+                               /* default ftp file protection */
+static long ftp_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
+static long ftp_dir_protection =/* default ftp directory protection */
+  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+
+       /* #public - everybody can read/write */
+static char *publicHome = NIL; /* public home directory */
+static long public_protection =        /* default public file protection */
+  S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+                               /* default public directory protection */
+static long public_dir_protection =
+  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
+
+       /* #shared/ - owner and group members can read/write */
+static char *sharedHome = NIL; /* shared home directory */
+                               /* default shared file protection */
+static long shared_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
+                               /* default shared directory protection */
+static long shared_dir_protection =
+  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP;
+\f
+/* OS bug workarounds - should be avoided at all cost */
+
+
+/* Don't set fcntlhangbug unless you really have to, since it risks mailbox
+ * corruption.  The flocksim.c mechanism is designed to detect NFS access
+ * and no-op in that cases only, so this flag should be unnecessary.
+ */
+
+static short fcntlhangbug = NIL;/* flock() emulator using fcntl() is a no-op */
+
+
+/* Don't set netfsstatbug unless you really have to, since it dramatically
+ * slows down traditional UNIX and MMDF mailbox performance.
+ */
+
+static short netfsstatbug = NIL;/* compensate for broken stat() on network
+                                * filesystems (AFS and old NFS)
+                                */
+
+
+/* Note: setting disableLockWarning means that you assert that the
+ * so-modified copy of this software will NEVER be used:
+ *  1) in conjunction with any software which expects .lock files
+ *  2) to access NFS-mounted files and directories
+ *
+ * Unless both of these conditions apply, then do not set this flag.
+ * Instead, read the FAQ (item 7.10) and either use 1777 protection
+ * on the mail spool, or install mlock.
+ *
+ * In addition, by setting this flag you also agree that you are fully
+ * legally and morally responsible when (not if) mail files are damaged
+ * as the result of your choice.
+ *
+ * The mlock tool exists for a reason.  Use it.
+ */
+                               /* disable warning if can't make .lock file */
+static short disableLockWarning = NIL;
+\f
+/* UNIX Namespaces */
+
+                               /* personal mh namespace */
+static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
+static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
+                               /* home namespace */
+static NAMESPACE nshome = {"",'/',NIL,&nsmh};
+                               /* UNIX other user namespace */
+static NAMESPACE nsunixother = {"~",'/',NIL,NIL};
+                               /* black box other user namespace */
+static NAMESPACE nsblackother = {"/",'/',NIL,NIL};
+                               /* public (anonymous OK) namespace */
+static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
+                               /* netnews namespace */
+static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
+                               /* FTP export namespace */
+static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
+                               /* shared (no anonymous) namespace */
+static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
+                               /* world namespace */
+static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
+                               /* only shared and public namespaces */
+static NAMESPACE nslimited = {"#shared/",'/',NIL,&nspublic};
+
+
+
+#include "write.c"             /* include safe writing routines */
+#include "crexcl.c"            /* include exclusive create */
+#include "pmatch.c"            /* include wildcard pattern matcher */
+
+/* Get all authenticators */
+
+#include "auths.c"
+\f
+/* Environment manipulate parameters
+ * Accepts: function code
+ *         function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_NAMESPACE:
+    ret = (void *) nslist;
+    break;
+  case SET_USERNAME:
+    if (myUserName) fs_give ((void **) &myUserName);
+    myUserName = cpystr ((char *) value);
+  case GET_USERNAME:
+    ret = (void *) myUserName;
+    break;
+  case SET_HOMEDIR:
+    if (myHomeDir) fs_give ((void **) &myHomeDir);
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    if (myLocalHost) fs_give ((void **) &myLocalHost);
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    ret = (void *) myNewsrc;
+    break;
+  case SET_NEWSACTIVE:
+    if (newsActive) fs_give ((void **) &newsActive);
+    newsActive = cpystr ((char *) value);
+  case GET_NEWSACTIVE:
+    ret = (void *) newsActive;
+    break;
+  case SET_NEWSSPOOL:
+    if (newsSpool) fs_give ((void **) &newsSpool);
+    newsSpool = cpystr ((char *) value);
+  case GET_NEWSSPOOL:
+    ret = (void *) newsSpool;
+    break;
+\f
+  case SET_ANONYMOUSHOME:
+    if (anonymousHome) fs_give ((void **) &anonymousHome);
+    anonymousHome = cpystr ((char *) value);
+  case GET_ANONYMOUSHOME:
+    if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
+    ret = (void *) anonymousHome;
+    break;
+  case SET_FTPHOME:
+    if (ftpHome) fs_give ((void **) &ftpHome);
+    ftpHome = cpystr ((char *) value);
+  case GET_FTPHOME:
+    ret = (void *) ftpHome;
+    break;
+  case SET_PUBLICHOME:
+    if (publicHome) fs_give ((void **) &publicHome);
+    publicHome = cpystr ((char *) value);
+  case GET_PUBLICHOME:
+    ret = (void *) publicHome;
+    break;
+  case SET_SHAREDHOME:
+    if (sharedHome) fs_give ((void **) &sharedHome);
+    sharedHome = cpystr ((char *) value);
+  case GET_SHAREDHOME:
+    ret = (void *) sharedHome;
+    break;
+  case SET_SYSINBOX:
+    if (sysInbox) fs_give ((void **) &sysInbox);
+    sysInbox = cpystr ((char *) value);
+  case GET_SYSINBOX:
+    ret = (void *) sysInbox;
+    break;
+  case SET_SSLCAPATH:          /* this can be set null */
+    if (sslCApath) fs_give ((void **) &sslCApath);
+    sslCApath = value ? cpystr ((char *) value) : value;
+    break;
+  case GET_SSLCAPATH:
+    ret = (void *) sslCApath;
+    break;
+  case SET_LISTMAXLEVEL:
+    list_max_level = (long) value;
+  case GET_LISTMAXLEVEL:
+    ret = (void *) list_max_level;
+    break;
+\f
+  case SET_MBXPROTECTION:
+    mbx_protection = (long) value;
+  case GET_MBXPROTECTION:
+    ret = (void *) mbx_protection;
+    break;
+  case SET_DIRPROTECTION:
+    dir_protection = (long) value;
+  case GET_DIRPROTECTION:
+    ret = (void *) dir_protection;
+    break;
+  case SET_LOCKPROTECTION:
+    dotlock_mode = (long) value;
+  case GET_LOCKPROTECTION:
+    ret = (void *) dotlock_mode;
+    break;
+  case SET_FTPPROTECTION:
+    ftp_protection = (long) value;
+  case GET_FTPPROTECTION:
+    ret = (void *) ftp_protection;
+    break;
+  case SET_PUBLICPROTECTION:
+    public_protection = (long) value;
+  case GET_PUBLICPROTECTION:
+    ret = (void *) public_protection;
+    break;
+  case SET_SHAREDPROTECTION:
+    shared_protection = (long) value;
+  case GET_SHAREDPROTECTION:
+    ret = (void *) shared_protection;
+    break;
+  case SET_FTPDIRPROTECTION:
+    ftp_dir_protection = (long) value;
+  case GET_FTPDIRPROTECTION:
+    ret = (void *) ftp_dir_protection;
+    break;
+  case SET_PUBLICDIRPROTECTION:
+    public_dir_protection = (long) value;
+  case GET_PUBLICDIRPROTECTION:
+    ret = (void *) public_dir_protection;
+    break;
+  case SET_SHAREDDIRPROTECTION:
+    shared_dir_protection = (long) value;
+  case GET_SHAREDDIRPROTECTION:
+    ret = (void *) shared_dir_protection;
+    break;
+\f
+  case SET_LOCKTIMEOUT:
+    locktimeout = (long) value;
+  case GET_LOCKTIMEOUT:
+    ret = (void *) locktimeout;
+    break;
+  case SET_DISABLEFCNTLLOCK:
+    fcntlhangbug = value ? T : NIL;
+  case GET_DISABLEFCNTLLOCK:
+    ret = (void *) (fcntlhangbug ? VOIDT : NIL);
+    break;
+  case SET_LOCKEACCESERROR:
+    disableLockWarning = value ? NIL : T;
+  case GET_LOCKEACCESERROR:
+    ret = (void *) (disableLockWarning ? NIL : VOIDT);
+    break;
+  case SET_HIDEDOTFILES:
+    hideDotFiles = value ? T : NIL;
+  case GET_HIDEDOTFILES:
+    ret = (void *) (hideDotFiles ? VOIDT : NIL);
+    break;
+  case SET_DISABLEPLAINTEXT:
+    disablePlaintext = (long) value;
+  case GET_DISABLEPLAINTEXT:
+    ret = (void *) disablePlaintext;
+    break;
+  case SET_CHROOTSERVER:
+    closedBox = value ? T : NIL;
+  case GET_CHROOTSERVER:
+    ret = (void *) (closedBox ? VOIDT : NIL);
+    break;
+  case SET_ADVERTISETHEWORLD:
+    advertisetheworld = value ? T : NIL;
+  case GET_ADVERTISETHEWORLD:
+    ret = (void *) (advertisetheworld ? VOIDT : NIL);
+    break;
+  case SET_LIMITEDADVERTISE:
+    limitedadvertise = value ? T : NIL;
+  case GET_LIMITEDADVERTISE:
+    ret = (void *) (limitedadvertise ? VOIDT : NIL);
+    break;
+  case SET_DISABLEAUTOSHAREDNS:
+    noautomaticsharedns = value ? T : NIL;
+  case GET_DISABLEAUTOSHAREDNS:
+    ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+\f
+  case SET_USERHASNOLIFE:
+    has_no_life = value ? T : NIL;
+  case GET_USERHASNOLIFE:
+    ret = (void *) (has_no_life ? VOIDT : NIL);
+    break;
+  case SET_KERBEROS_CP_SVR_NAME:
+    kerb_cp_svr_name = value ? T : NIL;
+  case GET_KERBEROS_CP_SVR_NAME:
+    ret = (void *) (kerb_cp_svr_name ? VOIDT : NIL);
+    break;
+  case SET_NETFSSTATBUG:
+    netfsstatbug = value ? T : NIL;
+  case GET_NETFSSTATBUG:
+    ret = (void *) (netfsstatbug ? VOIDT : NIL);
+    break;
+  case SET_BLOCKENVINIT:
+    block_env_init = value ? T : NIL;
+  case GET_BLOCKENVINIT:
+    ret = (void *) (block_env_init ? VOIDT : NIL);
+    break;
+  case SET_BLOCKNOTIFY:
+    mailblocknotify = (blocknotify_t) value;
+  case GET_BLOCKNOTIFY:
+    ret = (void *) mailblocknotify;
+    break;
+  case SET_LOGOUTHOOK:
+    maillogouthook = (logouthook_t) value;
+  case GET_LOGOUTHOOK:
+    ret = maillogouthook;
+    break;
+  case SET_LOGOUTDATA:
+    maillogoutdata = (void *) value;
+  case GET_LOGOUTDATA:
+    ret = maillogoutdata;
+  }
+  return ret;
+}
+\f
+/* Write current time
+ * Accepts: destination string
+ *         optional format of day-of-week prefix
+ *         format of date and time
+ *         flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+  time_t tn = time (0);
+  struct tm *t = gmtime (&tn);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&tn);         /* get local time now */
+                               /* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+  if (prefix) {                        /* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);     /* make next sprintf append */
+  }
+                               /* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+          t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+                               /* append timezone suffix if desired */
+  if (suffix) rfc822_timezone (date,(void *) t);
+}
+\f
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+          no822tztext ? NIL : T);
+}
+
+
+/* Write current time in fixed-width RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_fixed_date (char *date)
+{
+  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+\f
+/* Initialize server
+ * Accepts: server name for syslog or NIL
+ *         /etc/services service name or NIL
+ *         alternate /etc/services service name or NIL
+ *         clock interrupt handler
+ *         kiss-of-death interrupt handler
+ *         hangup interrupt handler
+ *         termination interrupt handler
+ */
+
+void server_init (char *server,char *service,char *sslservice,
+                 void *clkint,void *kodint,void *hupint,void *trmint,
+                 void *staint)
+{
+  int onceonly = server && service && sslservice;
+  if (onceonly) {              /* set server name in syslog */
+    int mask;
+    openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
+    fclose (stderr);           /* possibly save a process ID */
+    dorc (NIL,NIL);            /* do systemwide configuration */
+    switch (mask = umask (022)){/* check old umask */
+    case 0:                    /* definitely unreasonable */
+    case 022:                  /* don't need to change it */
+      break;
+    default:                   /* already was a reasonable value */
+      umask (mask);            /* so change it back */
+    }
+  }
+  arm_signal (SIGALRM,clkint); /* prepare for clock interrupt */
+  arm_signal (SIGUSR2,kodint); /* prepare for Kiss Of Death */
+  arm_signal (SIGHUP,hupint);  /* prepare for hangup */
+  arm_signal (SIGPIPE,hupint); /* alternative hangup */
+  arm_signal (SIGTERM,trmint); /* prepare for termination */
+                               /* status dump */
+  if (staint) arm_signal (SIGUSR1,staint);
+  if (onceonly) {              /* set up network and maybe SSL */
+    long port;
+    struct servent *sv;
+    /* Use SSL if SSL service, or if server starts with "s" and not service */
+    if (((port = tcp_serverport ()) >= 0)) {
+      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
+       syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
+      else if ((sv = getservbyname (sslservice,"tcp")) &&
+              (port == ntohs (sv->s_port))) {
+       syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
+               tcp_clientaddr ());
+       ssl_server_init (server);
+      }
+      else {                   /* not service or SSL service port */
+       syslog (LOG_DEBUG,"port %ld service init from %s",port,
+               tcp_clientaddr ());
+       if (*server == 's') ssl_server_init (server);
+      }
+    }
+  }
+}
+\f
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long server_input_wait (long seconds)
+{
+  fd_set rfd,efd;
+  struct timeval tmo;
+  FD_ZERO (&rfd);
+  FD_ZERO (&efd);
+  FD_SET (0,&rfd);
+  FD_SET (0,&efd);
+  tmo.tv_sec = seconds; tmo.tv_usec = 0;
+  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
+}
+\f
+/* Return UNIX password entry for user name
+ * Accepts: user name string
+ * Returns: password entry
+ *
+ * Tries all-lowercase form of user name if given user name fails
+ */
+
+static struct passwd *pwuser (unsigned char *user)
+{
+  unsigned char *s;
+  struct passwd *pw = getpwnam (user);
+  if (!pw) {                   /* failed, see if any uppercase characters */
+    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
+    if (*s) {                  /* yes, try all lowercase form */
+      pw = getpwnam (s = lcase (cpystr (user)));
+      fs_give ((void **) &s);
+    }
+  }
+  return pw;
+}
+
+
+/* Validate password for user name
+ * Accepts: user name string
+ *         password string
+ *         argument count
+ *         argument vector
+ * Returns: password entry if validated
+ *
+ * Tries password+1 if password fails and starts with space
+ */
+
+static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
+{
+  char *s;
+  struct passwd *pw;
+  struct passwd *ret = NIL;
+  if (auth_md5.server) {       /* using CRAM-MD5 authentication? */
+    if (s = auth_md5_pwd (user)) {
+      if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
+       ret = pwuser (user);    /* validated, get passwd entry for user */
+      memset (s,0,strlen (s)); /* erase sensitive information */
+      fs_give ((void **) &s);
+    }
+  }
+  else if (pw = pwuser (user)) {/* can get user? */
+    s = cpystr (pw->pw_name);  /* copy returned name in case we need it */
+    if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
+       (*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
+      ret = checkpw (pw,pwd+1,argc,argv);
+    fs_give ((void **) &s);    /* don't need copy of name any more */
+  }
+  return ret;
+}
+\f
+/* Server log in
+ * Accepts: user name string
+ *         password string
+ *         authenticating user name string
+ *         argument count
+ *         argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
+{
+  struct passwd *pw = NIL;
+  int level = LOG_NOTICE;
+  char *err = "failed";
+                               /* cretins still haven't given up */
+  if ((strlen (user) >= NETMAXUSER) ||
+      (authuser && (strlen (authuser) >= NETMAXUSER))) {
+    level = LOG_ALERT;         /* escalate this alert */
+    err = "SYSTEM BREAK-IN ATTEMPT";
+    logtry = 0;                        /* render this session useless */
+  }
+  else if (logtry-- <= 0) err = "excessive login failures";
+  else if (disablePlaintext) err = "disabled";
+  else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
+  else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
+  if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
+  syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
+         user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
+  sleep (3);                   /* slow down possible cracker */
+  return NIL;
+}
+\f
+/* Authenticated server log in
+ * Accepts: user name string
+ *         authenticating user name string
+ *         argument count
+ *         argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long authserver_login (char *user,char *authuser,int argc,char *argv[])
+{
+  return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
+}
+
+
+/* Log in as anonymous daemon
+ * Accepts: argument count
+ *         argument vector
+ * Returns: T if successful, NIL if error
+ */
+
+long anonymous_login (int argc,char *argv[])
+{
+                               /* log in Mr. A. N. Onymous */
+  return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
+                  (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
+                  argc,argv);
+}
+\f
+/* Finish log in and environment initialization
+ * Accepts: passwd struct for loginpw()
+ *         optional authentication user name
+ *         user name (NIL for anonymous)
+ *         home directory (NIL to use directory from passwd struct)
+ *         argument count
+ *         argument vector
+ * Returns: T if successful, NIL if error
+ */
+
+long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
+              char *argv[])
+{
+  struct group *gr;
+  char **t;
+  long ret = NIL;
+  if (pw && pw->pw_uid) {      /* must have passwd struct for non-UID 0 */
+                               /* make safe copies of user and home */
+    if (user) user = cpystr (pw->pw_name);
+    home = cpystr (home ? home : pw->pw_dir);
+                               /* authorization ID .NE. authentication ID? */
+    if (user && auser && *auser && compare_cstring (auser,user)) {
+                               /* scan list of mail administrators */
+      if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
+       if (!compare_cstring (auser,*t++))
+         ret = pw_login (pw,NIL,user,home,argc,argv);
+      syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
+             ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
+    }
+    else if (closedBox) {      /* paranoid site, lock out other directories */
+      if (chdir (home) || chroot (home))
+       syslog (LOG_NOTICE|LOG_AUTH,
+               "Login %s failed: unable to set chroot=%.80s host=%.80s",
+               pw->pw_name,home,tcp_clienthost ());
+      else if (loginpw (pw,argc,argv)) ret = env_init (user,NIL);
+      else fatal ("Login failed after chroot");
+    }
+                               /* normal login */
+    else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
+            (ret = env_init (user,home))) chdir (myhomedir ());
+    fs_give ((void **) &home); /* clean up */
+    if (user) fs_give ((void **) &user);
+  }
+  endpwent ();                 /* in case shadow passwords in pw data */
+  return ret;                  /* return status */
+}
+\f
+/* Initialize environment
+ * Accepts: user name (NIL for anonymous)
+ *         home directory name
+ * Returns: T, always
+ */
+
+long env_init (char *user,char *home)
+{
+  extern MAILSTREAM CREATEPROTO;
+  extern MAILSTREAM EMPTYPROTO;
+  struct passwd *pw;
+  struct stat sbuf;
+  char tmp[MAILTMPLEN];
+                               /* don't init if blocked */
+  if (block_env_init) return LONGT;
+  if (myUserName) fatal ("env_init called twice!");
+                               /* initially nothing in namespace list */
+  nslist[0] = nslist[1] = nslist[2] = NIL;
+                               /* myUserName must be set before dorc() call */
+  myUserName = cpystr (user ? user : ANONYMOUSUSER);
+                               /* force default prototypes to be set */
+  if (!createProto) createProto = &CREATEPROTO;
+  if (!appendProto) appendProto = &EMPTYPROTO;
+  dorc (NIL,NIL);              /* do systemwide configuration */
+  if (!home) {                 /* closed box server */
+                               /* standard user can only reference home */
+    if (user) nslist[0] = &nshome;
+    else {                     /* anonymous user */
+      nslist[0] = &nsblackother; /* set root */
+      anonymous = T;           /* flag as anonymous */
+    }
+    myHomeDir = cpystr ("");   /* home directory is root */
+    sysInbox = cpystr ("INBOX");/* make system INBOX */
+  }
+  else {                       /* open or black box */
+    closedBox = NIL;           /* definitely not a closed box */
+    if (user) {                        /* remember user name and home directory */
+      if (blackBoxDir) {       /* build black box directory name */
+       sprintf (tmp,"%s/%s",blackBoxDir,myUserName);
+                               /* must exist */
+       if (!((!stat (home = tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ||
+             (blackBoxDefaultHome &&
+              !stat (home = blackBoxDefaultHome,&sbuf) &&
+              (sbuf.st_mode & S_IFDIR)))) fatal ("no home");
+       sysInbox = (char *) fs_get (strlen (home) + 7);
+                               /* set system INBOX */
+       sprintf (sysInbox,"%s/INBOX",home);
+       blackBox = T;           /* mark that it's a black box */
+                               /* mbox meaningless if black box */
+       mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox");
+      }
+      nslist[0] = &nshome;     /* home namespace */
+                               /* limited advertise namespaces */
+      if (limitedadvertise) nslist[2] = &nslimited;
+      else if (blackBox) {     /* black box namespaces */
+       nslist[1] = &nsblackother;
+       nslist[2] = &nsshared;
+      }
+      else {                   /* open box namespaces */
+       nslist[1] = &nsunixother;
+       nslist[2] = advertisetheworld ? &nsworld : &nsshared;
+      }
+    }
+    else {
+      nslist[2] = &nsftp;      /* anonymous user */
+      sprintf (tmp,"%s/INBOX",
+              home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
+      sysInbox = cpystr (tmp); /* make system INBOX */
+      anonymous = T;           /* flag as anonymous */
+    }
+    myHomeDir = cpystr (home); /* set home directory */
+  }
+\f
+  if (allowuserconfig) {       /* allow user config files */
+    dorc (strcat (strcpy (tmp,myHomeDir),"/.mminit"),T);
+    dorc (strcat (strcpy (tmp,myHomeDir),"/.imaprc"),NIL);
+  }
+  if (!closedBox && !noautomaticsharedns) {
+                               /* #ftp namespace */
+    if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
+                               /* #public namespace */
+    if (!publicHome && (pw = getpwnam ("imappublic")))
+      publicHome = cpystr (pw->pw_dir);
+                               /* #shared namespace */
+    if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
+      sharedHome = cpystr (pw->pw_dir);
+  }
+  if (!myLocalHost) mylocalhost ();
+  if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
+  if (!newsActive) newsActive = cpystr (ACTIVEFILE);
+  if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
+                               /* re-do open action to get flags */
+  (*createProto->dtb->open) (NIL);
+  endpwent ();                 /* close pw database */
+  return T;
+}
+\f 
+/* Return my user name
+ * Accepts: pointer to optional flags
+ * Returns: my user name
+ */
+
+char *myusername_full (unsigned long *flags)
+{
+  struct passwd *pw;
+  struct stat sbuf;
+  char *s;
+  unsigned long euid;
+  char *ret = UNLOGGEDUSER;
+                               /* no user name yet and not root? */
+  if (!myUserName && (euid = geteuid ())) {
+                               /* yes, look up getlogin() user name or EUID */
+    if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
+        (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
+       (pw = getpwuid (euid))) {
+      if (block_env_init) {    /* don't env_init if blocked */
+       if (flags) *flags = MU_LOGGEDIN;
+       return pw->pw_name;
+      }
+      env_init (pw->pw_name,
+               ((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
+                !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
+               s : pw->pw_dir);
+    }
+    else fatal ("Unable to look up user name");
+  }
+  if (myUserName) {            /* logged in? */
+    if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
+    ret = myUserName;          /* return user name */
+  }
+  else if (flags) *flags = MU_NOTLOGGEDIN;
+  return ret;
+}
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost ()
+{
+  char tmp[MAILTMPLEN];
+  if (!myLocalHost) {
+    gethostname(tmp,MAILTMPLEN);/* get local host name */
+    myLocalHost = cpystr (tcp_canonical (tmp));
+  }
+  return myLocalHost;
+}
+\f
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  if (!myHomeDir) myusername ();/* initialize if first time */
+  return myHomeDir ? myHomeDir : "";
+}
+
+
+/* Return my home mailbox name
+ * Returns: my home directory name
+ */
+
+static char *mymailboxdir ()
+{
+  char *home = myhomedir ();
+                               /* initialize if first time */
+  if (!myMailboxDir && myHomeDir) {
+    if (mailsubdir) {
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s/%s",home,mailsubdir);
+      myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
+    }
+    else myMailboxDir = cpystr (home);
+  }
+  return myMailboxDir ? myMailboxDir : "";
+}
+
+
+/* Return system standard INBOX
+ * Accepts: buffer string
+ */
+
+char *sysinbox ()
+{
+  char tmp[MAILTMPLEN];
+  if (!sysInbox) {             /* initialize if first time */
+    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
+    sysInbox = cpystr (tmp);   /* system inbox is from mail spool */
+  }
+  return sysInbox;
+}
+\f
+/* Return mailbox directory name
+ * Accepts: destination buffer
+ *         directory prefix
+ *         name in directory
+ * Returns: file name or NIL if error
+ */
+
+char *mailboxdir (char *dst,char *dir,char *name)
+{
+  char tmp[MAILTMPLEN];
+  if (dir || name) {           /* if either argument provided */
+    if (dir) {
+      if (strlen (dir) > NETMAXMBX) return NIL;
+      strcpy (tmp,dir);                /* write directory prefix */
+    }
+    else tmp[0] = '\0';                /* otherwise null string */
+    if (name) {
+      if (strlen (name) > NETMAXMBX) return NIL;
+      strcat (tmp,name);       /* write name in directory */
+    }
+                               /* validate name, return its name */
+    if (!mailboxfile (dst,tmp)) return NIL;
+  }
+                               /* no arguments, wants mailbox directory */
+  else strcpy (dst,mymailboxdir ());
+  return dst;                  /* return the name */
+}
+\f
+/* Return mailbox file name
+ * Accepts: destination buffer
+ *         mailbox name
+ * Returns: file name or empty string for driver-selected INBOX or NIL if error
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+  struct passwd *pw;
+  char *s;
+  if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
+      ((anonymous || blackBox || restrictBox || (*name == '#')) &&
+       (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
+    dst = NIL;                 /* invalid name */
+  else switch (*name) {                /* determine mailbox type based upon name */
+  case '#':                    /* namespace name */
+                               /* #ftp/ namespace */
+    if (((name[1] == 'f') || (name[1] == 'F')) &&
+       ((name[2] == 't') || (name[2] == 'T')) &&
+       ((name[3] == 'p') || (name[3] == 'P')) &&
+       (name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
+                               /* #public/ and #shared/ namespaces */
+    else if ((((name[1] == 'p') || (name[1] == 'P')) &&
+             ((name[2] == 'u') || (name[2] == 'U')) &&
+             ((name[3] == 'b') || (name[3] == 'B')) &&
+             ((name[4] == 'l') || (name[4] == 'L')) &&
+             ((name[5] == 'i') || (name[5] == 'I')) &&
+             ((name[6] == 'c') || (name[6] == 'C')) &&
+             (name[7] == '/') && (s = publicHome)) ||
+            (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
+             ((name[2] == 'h') || (name[2] == 'H')) &&
+             ((name[3] == 'a') || (name[3] == 'A')) &&
+             ((name[4] == 'r') || (name[4] == 'R')) &&
+             ((name[5] == 'e') || (name[5] == 'E')) &&
+             ((name[6] == 'd') || (name[6] == 'D')) &&
+             (name[7] == '/') && (s = sharedHome)))
+      sprintf (dst,"%s/%s",s,compare_cstring (name+8,"INBOX") ?
+              name+8 : "INBOX");
+    else dst = NIL;            /* unknown namespace */
+    break;
+\f
+  case '/':                    /* root access */
+    if (anonymous) dst = NIL;  /* anonymous forbidden to do this */
+    else if (blackBox) {       /* other user access if blackbox */
+      if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
+                               /* see if other user INBOX */
+      else if ((s = strchr (name+1,'/')) && !compare_cstring (s+1,"INBOX")) {
+       *s = '\0';              /* temporarily tie off string */
+       sprintf (dst,"%s/%s/INBOX",blackBoxDir,name+1);
+       *s = '/';               /* in case caller cares */
+      }
+      else sprintf (dst,"%s/%s",blackBoxDir,name+1);
+    }
+    else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
+      dst = NIL;               /* restricted and not access to sysinbox */
+    else strcpy (dst,name);    /* unrestricted, copy root name */
+    break;
+  case '~':                    /* other user access */
+                               /* bad syntax or anonymous can't win */
+    if (!*++name || anonymous) dst = NIL;
+                               /* ~/ equivalent to ordinary name */
+    else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
+                               /* other user forbidden if closed/restricted */
+    else if (closedBox || (restrictBox & RESTRICTOTHERUSER)) dst = NIL;
+    else if (blackBox) {       /* black box form of other user */
+                               /* see if other user INBOX */
+      if ((s = strchr (name,'/')) && compare_cstring (s+1,"INBOX")) {
+       *s = '\0';              /* temporarily tie off string */
+       sprintf (dst,"%s/%s/INBOX",blackBoxDir,name);
+       *s = '/';               /* in case caller cares */
+      }
+      else sprintf (dst,"%s/%s",blackBoxDir,name);
+    }
+    else {                     /* clear box other user */
+                               /* copy user name */
+      for (s = dst; *name && (*name != '/'); *s++ = *name++);
+      *s++ = '\0';             /* tie off user name, look up in passwd file */
+      if ((pw = getpwnam (dst)) && pw->pw_dir) {
+       if (*name) name++;      /* skip past the slash */
+                               /* canonicalize case of INBOX */
+       if (!compare_cstring (name,"INBOX")) name = "INBOX";
+                               /* remove trailing / from directory */
+       if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
+                               /* don't allow ~root/ if restricted root */
+       if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
+                               /* build final name w/ subdir if needed */
+       else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
+       else sprintf (dst,"%s/%s",pw->pw_dir,name);
+      }
+      else dst = NIL;          /* no such user */
+    }
+    break;
+\f
+  case 'I': case 'i':          /* possible INBOX */
+    if (!compare_cstring (name+1,"NBOX")) {
+                               /* if restricted, use INBOX in mailbox dir */
+      if (anonymous || blackBox || closedBox)
+       sprintf (dst,"%s/INBOX",mymailboxdir ());
+      else *dst = '\0';                /* otherwise driver selects the name */
+      break;
+    }
+                               /* drop into to ordinary name case */
+  default:                     /* ordinary name is easy */
+    sprintf (dst,"%s/%s",mymailboxdir (),name);
+    break;
+  }
+  return dst;                  /* return final name */
+}
+\f
+/* Dot-lock file locker
+ * Accepts: file name to lock
+ *         destination buffer for lock file name
+ *         open file description on file name to lock
+ * Returns: T if success, NIL if failure
+ */
+
+long dotlock_lock (char *file,DOTLOCK *base,int fd)
+{
+  int i = locktimeout * 60;
+  int j,mask,retry,pi[2],po[2];
+  char *s,tmp[MAILTMPLEN];
+  struct stat sb;
+                               /* flush absurd file name */
+  if (strlen (file) > 512) return NIL;
+                               /* build lock filename */
+  sprintf (base->lock,"%s.lock",file);
+                               /* assume no pipe */
+  base->pipei = base->pipeo = -1;
+  do {                         /* make sure not symlink */
+    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
+                               /* time out if file older than 5 minutes */
+    if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
+                               /* try to create the lock */
+    switch (retry = crexcl (base->lock)) {
+    case -1:                   /* OK to retry */
+      if (!(i%15)) {           /* time to notify? */
+       sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
+                file,i);
+       MM_LOG (tmp,WARN);
+      }
+      sleep (1);               /* wait 1 second before next try */
+      break;
+    case NIL:                  /* failure, can't retry */
+      i = 0;
+      break;
+    case T:                    /* success, make sure others can break lock */
+      chmod (base->lock,(int) dotlock_mode);
+      return LONGT;
+    }
+  } while (i--);               /* until out of retries */
+  if (retry < 0) {             /* still returning retry after locktimeout? */
+    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
+    if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
+      sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
+              (long) (time (0) - sb.st_ctime));
+      MM_LOG (tmp,WARN);
+    }
+    mask = umask (0);          /* want our lock protection */
+    unlink (base->lock);       /* try to remove the old file */
+                               /* seize the lock */
+    if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) dotlock_mode)) >= 0) {
+      close (i);               /* don't need descriptor any more */
+      sprintf (tmp,"Mailbox %.80s lock overridden",file);
+      MM_LOG (tmp,NIL);
+      chmod (base->lock,(int) dotlock_mode);
+      umask (mask);            /* restore old umask */
+      return LONGT;
+    }
+    umask (mask);              /* restore old umask */
+  }
+\f
+  if (fd >= 0) switch (errno) {
+  case EACCES:                 /* protection failure? */
+    MM_CRITICAL (NIL);         /* go critical */
+    if (closedBox || !lockpgm);        /* can't do on closed box or disabled */
+    else if ((*lockpgm && stat (lockpgm,&sb)) ||
+            (!*lockpgm && stat (lockpgm = LOCKPGM1,&sb) &&
+             stat (lockpgm = LOCKPGM2,&sb) && stat (lockpgm = LOCKPGM3,&sb)))
+      lockpgm = NIL;           /* disable if can't find lockpgm */
+    else if (pipe (pi) >= 0) { /* make command pipes */
+      long cf;
+      char *argv[4],arg[20];
+                               /* if input pipes usable create output pipes */
+      if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
+                               /* make sure output pipes are usable */
+       if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
+                               /* all is good, make inferior process */
+       else if (!(j = fork ())) {
+         if (!fork ()) {       /* make grandchild so it's inherited by init */
+                               /* prepare argument vector */
+           sprintf (arg,"%d",fd);
+           argv[0] = lockpgm; argv[1] = arg;
+           argv[2] = file; argv[3] = NIL;
+                               /* set parent's I/O to my O/I */
+           dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
+                               /* close all unnecessary descriptors */
+           for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
+                cf >= 3; --cf) if (cf != fd) close (cf);
+                               /* be our own process group */
+           setpgrp (0,getpid ());
+                               /* now run it */
+           _exit (execv (argv[0],argv));
+         }
+         _exit (1);            /* child is done */
+       }
+       else if (j > 0) {       /* parent process */
+         fd_set rfd;
+         struct timeval tmo;
+         FD_ZERO (&rfd);
+         FD_SET (pi[0],&rfd);
+         tmo.tv_sec = locktimeout * 60;
+         grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
+                               /* read response from locking program */
+         if (select (pi[0]+1,&rfd,0,0,&tmo) &&
+             (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
+                               /* success, record pipes */
+           base->pipei = pi[0]; base->pipeo = po[1];
+                               /* close child's side of the pipes */
+           close (pi[1]); close (po[0]);
+           MM_NOCRITICAL (NIL);/* no longer critical */
+           return LONGT;
+         }
+       }
+       close (po[0]); close (po[1]);
+      }
+      close (pi[0]); close (pi[1]);
+    }
+\f
+    MM_NOCRITICAL (NIL);       /* no longer critical */
+                               /* find directory/file delimiter */
+    if (s = strrchr (base->lock,'/')) {
+      *s = '\0';               /* tie off at directory */
+      sprintf(tmp,             /* generate default message */
+             "Mailbox vulnerable - directory %.80s must have 1777 protection",
+             base->lock);
+                               /* definitely not 1777 if can't stat */
+      mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
+      *s = '/';                        /* restore lock name */
+      if (mask != 1777) {      /* default warning if not 1777 */
+       if (!disableLockWarning) MM_LOG (tmp,WARN);
+       break;
+      }
+    }
+  default:
+    sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
+            base->lock,strerror (errno));
+    if (!disableLockWarning) MM_LOG (tmp,WARN);
+    break;
+  }
+  base->lock[0] = '\0';                /* don't use lock files */
+  return NIL;
+}
+\f
+/* Dot-lock file unlocker
+ * Accepts: lock file name
+ * Returns: T if success, NIL if failure
+ */
+
+long dotlock_unlock (DOTLOCK *base)
+{
+  long ret = LONGT;
+  if (base && base->lock[0]) {
+    if (base->pipei >= 0) {    /* if running through a pipe unlocker */
+      ret = (write (base->pipeo,"+",1) == 1);
+                               /* nuke the pipes */
+      close (base->pipei); close (base->pipeo);
+    }
+    else ret = !unlink (base->lock);
+  }
+  return ret;
+}
+\f
+/* Lock file name
+ * Accepts: scratch buffer
+ *         file name
+ *         type of locking operation (LOCK_SH or LOCK_EX)
+ *         pointer to return PID of locker
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lockname (char *lock,char *fname,int op,long *pid)
+{
+  struct stat sbuf;
+  *pid = 0;                    /* no locker PID */
+  return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
+}
+
+
+/* Lock file descriptor
+ * Accepts: file descriptor
+ *         lock file name buffer
+ *         type of locking operation (LOCK_SH or LOCK_EX)
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lockfd (int fd,char *lock,int op)
+{
+  struct stat sbuf;
+  return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
+}
+\f
+/* Lock file name worker
+ * Accepts: lock file name
+ *         pointer to stat() buffer
+ *         type of locking operation (LOCK_SH or LOCK_EX)
+ *         pointer to return PID of locker
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lock_work (char *lock,void *sb,int op,long *pid)
+{
+  struct stat lsb,fsb;
+  struct stat *sbuf = (struct stat *) sb;
+  char tmp[MAILTMPLEN];
+  long i;
+  int fd;
+  int mask = umask (0);
+  if (pid) *pid = 0;           /* initialize return PID */
+                               /* make temporary lock file name */
+  sprintf (lock,"%s/.%lx.%lx",closedBox ? "" : tmpdir,
+          (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
+  while (T) {                  /* until get a good lock */
+    do switch ((int) chk_notsymlink (lock,&lsb)) {
+    case 1:                    /* exists just once */
+      if (((fd = open (lock,O_RDWR,shlock_mode)) >= 0) ||
+         (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
+    case -1:                   /* name doesn't exist */
+      fd = open (lock,O_RDWR|O_CREAT|O_EXCL,shlock_mode);
+      break;
+    default:                   /* multiple hard links */
+      MM_LOG ("hard link to lock name",ERROR);
+      syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
+    case 0:                    /* symlink (already did syslog) */
+      umask (mask);            /* restore old mask */
+      return -1;               /* fail: no lock file */
+    } while ((fd < 0) && (errno == EEXIST));
+    if (fd < 0) {              /* failed to get file descriptor */
+      syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
+             strerror (errno));
+      if (!closedBox) {                /* more explicit snarl for bad configuration */
+       if (stat (tmpdir,&lsb))
+         syslog (LOG_CRIT,"SYSTEM ERROR: no %s: %s",tmpdir,strerror (errno));
+       else if ((lsb.st_mode & 01777) != 01777) {
+         sprintf (tmp,"Can't lock for write: %.80s must have 1777 protection",
+                  tmpdir);
+         MM_LOG (tmp,WARN);
+       }
+      }
+      umask (mask);            /* restore old mask */
+      return -1;               /* fail: can't open lock file */
+    }
+\f
+                               /* non-blocking form */
+    if (op & LOCK_NB) i = flock (fd,op);
+    else {                     /* blocking form */
+      (*mailblocknotify) (BLOCK_FILELOCK,NIL);
+      i = flock (fd,op);
+      (*mailblocknotify) (BLOCK_NONE,NIL);
+    }
+    if (i) {                   /* failed, get other process' PID */
+      if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
+         (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
+       *pid = i;
+      close (fd);              /* failed, give up on lock */
+      umask (mask);            /* restore old mask */
+      return -1;               /* fail: can't lock */
+    }
+                               /* make sure this lock is good for us */
+    if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
+       !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
+       (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
+    close (fd);                        /* lock not right, drop fd and try again */
+  }
+  chmod (lock,shlock_mode);    /* make sure mode OK (don't use fchmod()) */
+  umask (mask);                        /* restore old mask */
+  return fd;                   /* success */
+}
+\f
+/* Check to make sure not a symlink
+ * Accepts: file name
+ *         stat buffer
+ * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
+ */
+
+long chk_notsymlink (char *name,void *sb)
+{
+  struct stat *sbuf = (struct stat *) sb;
+                               /* name exists? */
+  if (lstat (name,sbuf)) return -1;
+                               /* forbid symbolic link */
+  if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
+    MM_LOG ("symbolic link on lock name",ERROR);
+    syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
+           name);
+    return NIL;
+  }
+  return (long) sbuf->st_nlink;        /* return number of hard links */
+}
+
+
+/* Unlock file descriptor
+ * Accepts: file descriptor
+ *         lock file name from lockfd()
+ */
+
+void unlockfd (int fd,char *lock)
+{
+                               /* delete the file if no sharers */
+  if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
+  flock (fd,LOCK_UN);          /* unlock it */
+  close (fd);                  /* close it */
+}
+\f
+/* Set proper file protection for mailbox
+ * Accepts: mailbox name
+ *         actual file path name
+ * Returns: T, always
+ */
+
+long set_mbx_protections (char *mailbox,char *path)
+{
+  struct stat sbuf;
+  int mode = (int) mbx_protection;
+  if (*mailbox == '#') {       /* possible namespace? */
+      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
+         ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
+         ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
+         (mailbox[4] == '/')) mode = (int) ftp_protection;
+      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
+              ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
+              ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
+              ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
+              ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
+              ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
+              (mailbox[7] == '/')) mode = (int) public_protection;
+      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
+              ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
+              ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
+              ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
+              ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
+              ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
+              (mailbox[7] == '/')) mode = (int) shared_protection;
+  }
+                               /* if a directory */
+  if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+                               /* set owner search if allow read or write */
+    if (mode & 0600) mode |= 0100;
+    if (mode & 060) mode |= 010;/* set group search if allow read or write */
+    if (mode & 06) mode |= 01; /* set world search if allow read or write */
+                               /* preserve directory SGID bit */
+    if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
+  }
+  chmod (path,mode);           /* set the new protection, ignore failure */
+  return LONGT;
+}
+\f
+/* Get proper directory protection
+ * Accepts: mailbox name
+ * Returns: directory mode, always
+ */
+
+long get_dir_protection (char *mailbox)
+{
+  if (*mailbox == '#') {       /* possible namespace? */
+      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
+         ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
+         ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
+         (mailbox[4] == '/')) return ftp_dir_protection;
+      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
+              ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
+              ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
+              ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
+              ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
+              ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
+              (mailbox[7] == '/')) return public_dir_protection;
+      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
+              ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
+              ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
+              ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
+              ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
+              ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
+              (mailbox[7] == '/')) return shared_dir_protection;
+  }
+  return dir_protection;
+}
+\f
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  myusername ();               /* make sure initialized */
+                               /* return default driver's prototype */
+  return type ? appendProto : createProto;
+}
+
+
+/* Set up user flags for stream
+ * Accepts: MAIL stream
+ * Returns: MAIL stream with user flags set up
+ */
+
+MAILSTREAM *user_flags (MAILSTREAM *stream)
+{
+  int i;
+  myusername ();               /* make sure initialized */
+  for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
+    if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
+  return stream;
+}
+
+
+/* Return nth user flag
+ * Accepts: user flag number
+ * Returns: flag
+ */
+
+char *default_user_flag (unsigned long i)
+{
+  myusername ();               /* make sure initialized */
+  return userFlags[i];
+}
+\f
+/* Process rc file
+ * Accepts: file name
+ *         .mminit flag
+ * Don't use this feature.
+ */
+
+void dorc (char *file,long flag)
+{
+  int i;
+  char *s,*t,*k,*r,tmp[MAILTMPLEN],tmpx[MAILTMPLEN];
+  extern MAILSTREAM CREATEPROTO;
+  extern MAILSTREAM EMPTYPROTO;
+  DRIVER *d;
+  FILE *f;
+  if ((f = fopen (file ? file : SYSCONFIG,"r")) &&
+      (s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))) do {
+    *t++ = '\0';               /* tie off line, find second space */
+    if ((k = strchr (s,' ')) && (k = strchr (++k,' '))) {
+      *k++ = '\0';             /* tie off two words */
+      if (!compare_cstring (s,"set keywords") && !userFlags[0]) {
+                               /* yes, get first keyword */
+       k = strtok_r (k,", ",&r);
+                               /* copy keyword list */
+       for (i = 0; k && i < NUSERFLAGS; ++i) if (strlen (k) <= MAXUSERFLAG) {
+         if (userFlags[i]) fs_give ((void **) &userFlags[i]);
+         userFlags[i] = cpystr (k);
+         k = strtok_r (NIL,", ",&r);
+       }
+       if (flag) break;        /* found "set keywords" in .mminit */
+      }
+\f
+      else if (!flag) {                /* none of these valid in .mminit */
+       if (myUserName) {       /* only valid if logged in */
+         if (!compare_cstring (s,"set new-mailbox-format") ||
+             !compare_cstring (s,"set new-folder-format")) {
+           if (!compare_cstring (k,"same-as-inbox")) {
+             if (d = mail_valid (NIL,"INBOX",NIL)) {
+               if (!compare_cstring (d->name,"mbox"))
+                 d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,
+                                                 (void *) "unix");
+               else if (!compare_cstring (d->name,"dummy")) d = NIL;
+             }
+             createProto = d ? ((*d->open) (NIL)) : &CREATEPROTO;
+           }
+           else if (!compare_cstring (k,"system-standard"))
+             createProto = &CREATEPROTO;
+           else {              /* canonicalize mbox to unix */
+             if (!compare_cstring (k,"mbox")) k = "unix";
+                               /* see if a driver name */
+             if (d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,(void *) k))
+               createProto = (*d->open) (NIL);
+             else {            /* duh... */
+               sprintf (tmpx,"Unknown new mailbox format in %s: %s",
+                        file ? file : SYSCONFIG,k);
+               MM_LOG (tmpx,WARN);
+             }
+           }
+         }
+         if (!compare_cstring (s,"set empty-mailbox-format") ||
+             !compare_cstring (s,"set empty-folder-format")) {
+           if (!compare_cstring (k,"invalid")) appendProto = NIL;
+           else if (!compare_cstring (k,"same-as-inbox"))
+             appendProto = ((d = mail_valid (NIL,"INBOX",NIL)) &&
+                            compare_cstring (d->name,"dummy")) ?
+                              ((*d->open) (NIL)) : &EMPTYPROTO;
+           else if (!compare_cstring (k,"system-standard"))
+             appendProto = &EMPTYPROTO;
+           else {              /* see if a driver name */
+             for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
+                  d && compare_cstring (d->name,k); d = d->next);
+             if (d) appendProto = (*d->open) (NIL);
+             else {            /* duh... */
+               sprintf (tmpx,"Unknown empty mailbox format in %s: %s",
+                        file ? file : SYSCONFIG,k);
+               MM_LOG (tmpx,WARN);
+             }
+           }
+         }
+       }
+\f
+       if (!compare_cstring (s,"set local-host")) {
+         fs_give ((void **) &myLocalHost);
+         myLocalHost = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set news-active-file")) {
+         fs_give ((void **) &newsActive);
+         newsActive = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set news-spool-directory")) {
+         fs_give ((void **) &newsSpool);
+         newsSpool = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set mh-path"))
+         mail_parameters (NIL,SET_MHPATH,(void *) k);
+       else if (!compare_cstring (s,"set mh-allow-inbox"))
+         mail_parameters (NIL,SET_MHALLOWINBOX,(void *) atol (k));
+       else if (!compare_cstring (s,"set news-state-file")) {
+         fs_give ((void **) &myNewsrc);
+         myNewsrc = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set ftp-export-directory")) {
+         fs_give ((void **) &ftpHome);
+         ftpHome = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set public-home-directory")) {
+         fs_give ((void **) &publicHome);
+         publicHome = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set shared-home-directory")) {
+         fs_give ((void **) &sharedHome);
+         sharedHome = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set system-inbox")) {
+         fs_give ((void **) &sysInbox);
+         sysInbox = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set mail-subdirectory")) {
+         fs_give ((void **) &mailsubdir);
+         mailsubdir = cpystr (k);
+       }
+       else if (!compare_cstring (s,"set from-widget"))
+         mail_parameters (NIL,SET_FROMWIDGET,
+                          compare_cstring (k,"header-only") ?
+                          VOIDT : NIL);
+\f
+       else if (!compare_cstring (s,"set rsh-command"))
+         mail_parameters (NIL,SET_RSHCOMMAND,(void *) k);
+       else if (!compare_cstring (s,"set rsh-path"))
+         mail_parameters (NIL,SET_RSHPATH,(void *) k);
+       else if (!compare_cstring (s,"set ssh-command"))
+         mail_parameters (NIL,SET_SSHCOMMAND,(void *) k);
+       else if (!compare_cstring (s,"set ssh-path"))
+         mail_parameters (NIL,SET_SSHPATH,(void *) k);
+       else if (!compare_cstring (s,"set tcp-open-timeout"))
+         mail_parameters (NIL,SET_OPENTIMEOUT,(void *) atol (k));
+       else if (!compare_cstring (s,"set tcp-read-timeout"))
+         mail_parameters (NIL,SET_READTIMEOUT,(void *) atol (k));
+       else if (!compare_cstring (s,"set tcp-write-timeout"))
+         mail_parameters (NIL,SET_WRITETIMEOUT,(void *) atol (k));
+       else if (!compare_cstring (s,"set rsh-timeout"))
+         mail_parameters (NIL,SET_RSHTIMEOUT,(void *) atol (k));
+       else if (!compare_cstring (s,"set ssh-timeout"))
+         mail_parameters (NIL,SET_SSHTIMEOUT,(void *) atol (k));
+       else if (!compare_cstring (s,"set maximum-login-trials"))
+         mail_parameters (NIL,SET_MAXLOGINTRIALS,(void *) atol (k));
+       else if (!compare_cstring (s,"set lookahead"))
+         mail_parameters (NIL,SET_LOOKAHEAD,(void *) atol (k));
+       else if (!compare_cstring (s,"set prefetch"))
+         mail_parameters (NIL,SET_PREFETCH,(void *) atol (k));
+       else if (!compare_cstring (s,"set close-on-error"))
+         mail_parameters (NIL,SET_CLOSEONERROR,(void *) atol (k));
+       else if (!compare_cstring (s,"set imap-port"))
+         mail_parameters (NIL,SET_IMAPPORT,(void *) atol (k));
+       else if (!compare_cstring (s,"set pop3-port"))
+         mail_parameters (NIL,SET_POP3PORT,(void *) atol (k));
+       else if (!compare_cstring (s,"set uid-lookahead"))
+         mail_parameters (NIL,SET_UIDLOOKAHEAD,(void *) atol (k));
+       else if (!compare_cstring (s,"set try-ssl-first"))
+         mail_parameters (NIL,SET_TRYSSLFIRST,(void *) atol (k));
+\f
+       else if (!compare_cstring (s,"set mailbox-protection"))
+         mbx_protection = atol (k);
+       else if (!compare_cstring (s,"set directory-protection"))
+         dir_protection = atol (k);
+       else if (!compare_cstring (s,"set lock-protection"))
+         dotlock_mode = atol (k);
+       else if (!compare_cstring (s,"set ftp-protection"))
+         ftp_protection = atol (k);
+       else if (!compare_cstring (s,"set public-protection"))
+         public_protection = atol (k);
+       else if (!compare_cstring (s,"set shared-protection"))
+         shared_protection = atol (k);
+       else if (!compare_cstring (s,"set ftp-directory-protection"))
+         ftp_dir_protection = atol (k);
+       else if (!compare_cstring (s,"set public-directory-protection"))
+         public_dir_protection = atol (k);
+       else if (!compare_cstring (s,"set shared-directory-protection"))
+         shared_dir_protection = atol (k);
+       else if (!compare_cstring (s,"set dot-lock-file-timeout"))
+         locktimeout = atoi (k);
+       else if (!compare_cstring (s,"set disable-fcntl-locking"))
+         fcntlhangbug = atoi (k);
+       else if (!compare_cstring (s,"set disable-lock-warning"))
+         disableLockWarning = atoi (k);
+       else if (!compare_cstring (s,"set disable-unix-UIDs-and-keywords"))
+         has_no_life = atoi (k);
+       else if (!compare_cstring (s,"set hide-dot-files"))
+         hideDotFiles = atoi (k);
+       else if (!compare_cstring (s,"set list-maximum-level"))
+         list_max_level = atol (k);
+       else if (!compare_cstring (s,"set trust-dns"))
+         mail_parameters (NIL,SET_TRUSTDNS,(void *) atol (k));
+       else if (!compare_cstring (s,"set sasl-uses-ptr-name"))
+         mail_parameters (NIL,SET_SASLUSESPTRNAME,(void *) atol (k));
+       else if (!compare_cstring (s,"set network-filesystem-stat-bug"))
+         netfsstatbug = atoi (k);
+       else if (!compare_cstring (s,"set nntp-range"))
+         mail_parameters (NIL,SET_NNTPRANGE,(void *) atol (k));
+\f
+       else if (!file) {       /* only allowed in system init */
+         if (!compare_cstring (s,"set black-box-directory") &&
+             !blackBoxDir) blackBoxDir = cpystr (k);
+         else if (!compare_cstring(s,"set black-box-default-home-directory")&&
+                  blackBoxDir && !blackBoxDefaultHome)
+           blackBoxDefaultHome = cpystr (k);
+         else if (!compare_cstring (s,"set anonymous-home-directory") &&
+                  !anonymousHome) anonymousHome = cpystr (k);
+                               /* It's tempting to allow setting the CA path
+                                * in a user init.  However, that opens up a
+                                * vector of attack big enough to drive a
+                                * truck through...  Resist the temptation.
+                                */
+         else if (!compare_cstring (s,"set CA-certificate-path"))
+           sslCApath = cpystr (k);
+         else if (!compare_cstring (s,"set disable-plaintext"))
+           disablePlaintext = atoi (k);
+         else if (!compare_cstring (s,"set allowed-login-attempts"))
+           logtry = atoi (k);
+         else if (!compare_cstring (s,"set chroot-server"))
+           closedBox = atoi (k);
+         else if (!compare_cstring (s,"set restrict-mailbox-access"))
+           for (k = strtok_r (k,", ",&r); k; k = strtok_r (NIL,", ",&r)) {
+             if (!compare_cstring (k,"root")) restrictBox |= RESTRICTROOT;
+             else if (!compare_cstring (k,"otherusers"))
+               restrictBox |= RESTRICTOTHERUSER;
+             else if (!compare_cstring (k,"all")) restrictBox = -1;
+           }
+         else if (!compare_cstring (s,"set advertise-the-world"))
+           advertisetheworld = atoi (k);
+         else if (!compare_cstring (s,"set limited-advertise"))
+           limitedadvertise = atoi (k);
+         else if (!compare_cstring
+                  (s,"set disable-automatic-shared-namespaces"))
+           noautomaticsharedns = atoi (k);
+         else if (!compare_cstring (s,"set allow-user-config"))
+           allowuserconfig = atoi (k);
+         else if (!compare_cstring (s,"set allow-reverse-dns"))
+           mail_parameters (NIL,SET_ALLOWREVERSEDNS,(void *) atol (k));
+         else if (!compare_cstring (s,"set k5-cp-uses-service-name"))
+           kerb_cp_svr_name = atoi (k);
+                               /* must appear in file after any
+                                * "set disable-plaintext" command! */
+         else if (!compare_cstring (s,"set plaintext-allowed-clients")) {
+           for (k = strtok_r (k,", ",&r); k && !tcp_isclienthost (k);
+                k = strtok_r (NIL,", ",&r));
+           if (k) disablePlaintext = 0;
+         }
+       }
+      }
+    }
+  } while ((s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n')));
+  if (f) fclose (f);           /* flush the file */
+}
+\f
+/* INBOX create function for tmail/dmail use only
+ * Accepts: mail stream
+ *         path name buffer, preloaded with driver-dependent path
+ * Returns: T on success, NIL on failure
+ *
+ * This routine is evil and a truly incredible kludge.  It is private for
+ * tmail/dmail and is not supported for any other application.
+ */
+
+long path_create (MAILSTREAM *stream,char *path)
+{
+  long ret;
+  short rsave = restrictBox;
+  restrictBox = NIL;           /* can't restrict */
+  if (blackBox) {              /* if black box */
+                               /* toss out driver dependent names */
+    printf (path,"%s/INBOX",mymailboxdir ());
+    blackBox = NIL;            /* well that's evil - evil is going on */
+    ret = mail_create (stream,path);
+    blackBox = T;              /* restore the box */
+  }
+                               /* easy thing otherwise */
+  else ret = mail_create (stream,path);
+  restrictBox = rsave;         /* restore restrictions */
+  return ret;
+}
+\f
+/* Default block notify routine
+ * Accepts: reason for calling
+ *         data
+ * Returns: data
+ */
+
+void *mm_blocknotify (int reason,void *data)
+{
+  void *ret = data;
+  switch (reason) {
+  case BLOCK_SENSITIVE:                /* entering sensitive code */
+    ret = (void *) (unsigned long) alarm (0);
+    break;
+  case BLOCK_NONSENSITIVE:     /* exiting sensitive code */
+    if ((unsigned long) data) alarm ((unsigned long) data);
+    break;
+  default:                     /* ignore all other reasons */
+    break;
+  }
+  return ret;
+}