env_ami.c
上传用户:ycwykj01
上传日期:2007-01-04
资源大小:1819k
文件大小:33k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: Amiga environment routines
  3.  *
  4.  * Author: Mark Crispin
  5.  * Networks and Distributed Computing
  6.  * Computing & Communications
  7.  * University of Washington
  8.  * Administration Building, AG-44
  9.  * Seattle, WA  98195
  10.  * Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date: 1 August 1988
  13.  * Last Edited: 1 November 1999
  14.  *
  15.  * Copyright 1999 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made available
  24.  * "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35. #include <signal.h>
  36. #include <sys/wait.h>
  37. #include "write.c" /* include safe writing routines */
  38. /* Get all authenticators */
  39. #include "auths.c"
  40. /* c-client environment parameters */
  41. static const char *anonymous_user = "nobody";
  42. static const char *unlogged_user = "root";
  43. static char *myUserName = NIL; /* user name */
  44. static char *myHomeDir = NIL; /* home directory name */
  45. static char *myLocalHost = NIL; /* local host name */
  46. static char *myNewsrc = NIL; /* newsrc file name */
  47. static char *sysInbox = NIL; /* system inbox name */
  48. static char *newsActive = NIL; /* news active file */
  49. static char *newsSpool = NIL; /* news spool */
  50. /* anonymous home directory */
  51. static char *anonymousHome = NIL;
  52. static char *ftpHome = NIL; /* ftp export home directory */
  53. static char *publicHome = NIL; /* public home directory */
  54. static char *sharedHome = NIL; /* shared home directory */
  55. static short anonymous = NIL; /* is anonymous */
  56. static short has_no_life = NIL; /* is a cretin with no life */
  57. static long list_max_level = 20;/* maximum level of list recursion */
  58. /* default file protection */
  59. static long mbx_protection = 0600;
  60. /* default directory protection */
  61. static long dir_protection = 0700;
  62. /* default lock file protection */
  63. static long lock_protection = 0666;
  64. /* default ftp file protection */
  65. static long ftp_protection = 0644;
  66. /* default public file protection */
  67. static long public_protection = 0666;
  68. /* default shared file protection */
  69. static long shared_protection = 0660;
  70. static long locktimeout = 5; /* default lock timeout */
  71. /* warning on EACCES errors on .lock files */
  72. static long lockEaccesError = T;
  73. /* default prototypes */
  74. static MAILSTREAM *createProto = NIL;
  75. static MAILSTREAM *appendProto = NIL;
  76. /* default user flags */
  77. static char *userFlags[NUSERFLAGS] = {NIL};
  78. static NAMESPACE *nslist[3]; /* namespace list */
  79. static int logtry = 3; /* number of server login tries */
  80. /* block notification */
  81. static blocknotify_t mailblocknotify = mm_blocknotify;
  82. /* Amiga namespaces */
  83. /* personal mh namespace */
  84. static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
  85. static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
  86. /* home namespace */
  87. static NAMESPACE nshome = {"",'/',NIL,&nsmh};
  88. /* Amiga other user namespace */
  89. static NAMESPACE nsamigaother = {"~",'/',NIL,NIL};
  90. /* public (anonymous OK) namespace */
  91. static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
  92. /* netnews namespace */
  93. static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
  94. /* FTP export namespace */
  95. static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
  96. /* shared (no anonymous) namespace */
  97. static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
  98. /* Environment manipulate parameters
  99.  * Accepts: function code
  100.  *     function-dependent value
  101.  * Returns: function-dependent return value
  102.  */
  103. void *env_parameters (long function,void *value)
  104. {
  105.   switch ((int) function) {
  106.   case SET_NAMESPACE:
  107.     fatal ("SET_NAMESPACE not permitted");
  108.   case GET_NAMESPACE:
  109.     value = (void *) nslist;
  110.     break;
  111.   case SET_USERNAME:
  112.     if (myUserName) fs_give ((void **) &myUserName);
  113.     myUserName = cpystr ((char *) value);
  114.     break;
  115.   case GET_USERNAME:
  116.     value = (void *) myUserName;
  117.     break;
  118.   case SET_HOMEDIR:
  119.     if (myHomeDir) fs_give ((void **) &myHomeDir);
  120.     myHomeDir = cpystr ((char *) value);
  121.     break;
  122.   case GET_HOMEDIR:
  123.     value = (void *) myHomeDir;
  124.     break;
  125.   case SET_LOCALHOST:
  126.     if (myLocalHost) fs_give ((void **) &myLocalHost);
  127.     myLocalHost = cpystr ((char *) value);
  128.     break;
  129.   case GET_LOCALHOST:
  130.     value = (void *) myLocalHost;
  131.     break;
  132.   case SET_NEWSRC:
  133.     if (myNewsrc) fs_give ((void **) &myNewsrc);
  134.     myNewsrc = cpystr ((char *) value);
  135.     break;
  136.   case GET_NEWSRC:
  137.     value = (void *) myNewsrc;
  138.     break;
  139.   case SET_NEWSACTIVE:
  140.     if (newsActive) fs_give ((void **) &newsActive);
  141.     newsActive = cpystr ((char *) value);
  142.     break;
  143.   case GET_NEWSACTIVE:
  144.     value = (void *) newsActive;
  145.     break;
  146.   case SET_NEWSSPOOL:
  147.     if (newsSpool) fs_give ((void **) &newsSpool);
  148.     newsSpool = cpystr ((char *) value);
  149.     break;
  150.   case GET_NEWSSPOOL:
  151.     value = (void *) newsSpool;
  152.     break;
  153.   case SET_ANONYMOUSHOME:
  154.     if (anonymousHome) fs_give ((void **) &anonymousHome);
  155.     anonymousHome = cpystr ((char *) value);
  156.     break;
  157.   case GET_ANONYMOUSHOME:
  158.     value = (void *) anonymousHome;
  159.     break;
  160.   case SET_FTPHOME:
  161.     if (ftpHome) fs_give ((void **) &ftpHome);
  162.     ftpHome = cpystr ((char *) value);
  163.     break;
  164.   case GET_FTPHOME:
  165.     value = (void *) ftpHome;
  166.     break;
  167.   case SET_PUBLICHOME:
  168.     if (publicHome) fs_give ((void **) &publicHome);
  169.     publicHome = cpystr ((char *) value);
  170.     break;
  171.   case GET_PUBLICHOME:
  172.     value = (void *) publicHome;
  173.     break;
  174.   case SET_SHAREDHOME:
  175.     if (sharedHome) fs_give ((void **) &sharedHome);
  176.     sharedHome = cpystr ((char *) value);
  177.     break;
  178.   case GET_SHAREDHOME:
  179.     value = (void *) sharedHome;
  180.     break;
  181.   case SET_SYSINBOX:
  182.     if (sysInbox) fs_give ((void **) &sysInbox);
  183.     sysInbox = cpystr ((char *) value);
  184.     break;
  185.   case GET_SYSINBOX:
  186.     value = (void *) sysInbox;
  187.     break;
  188.   case SET_LISTMAXLEVEL:
  189.     list_max_level = (long) value;
  190.     break;
  191.   case GET_LISTMAXLEVEL:
  192.     value = (void *) list_max_level;
  193.     break;
  194.   case SET_MBXPROTECTION:
  195.     mbx_protection = (long) value;
  196.     break;
  197.   case GET_MBXPROTECTION:
  198.     value = (void *) mbx_protection;
  199.     break;
  200.   case SET_DIRPROTECTION:
  201.     dir_protection = (long) value;
  202.     break;
  203.   case GET_DIRPROTECTION:
  204.     value = (void *) dir_protection;
  205.     break;
  206.   case SET_LOCKPROTECTION:
  207.     lock_protection = (long) value;
  208.     break;
  209.   case GET_LOCKPROTECTION:
  210.     value = (void *) lock_protection;
  211.     break;
  212.   case SET_FTPPROTECTION:
  213.     ftp_protection = (long) value;
  214.     break;
  215.   case GET_FTPPROTECTION:
  216.     value = (void *) ftp_protection;
  217.     break;
  218.   case SET_PUBLICPROTECTION:
  219.     public_protection = (long) value;
  220.     break;
  221.   case GET_PUBLICPROTECTION:
  222.     value = (void *) public_protection;
  223.     break;
  224.   case SET_SHAREDPROTECTION:
  225.     shared_protection = (long) value;
  226.     break;
  227.   case GET_SHAREDPROTECTION:
  228.     value = (void *) shared_protection;
  229.     break;
  230.   case SET_LOCKTIMEOUT:
  231.     locktimeout = (long) value;
  232.     break;
  233.   case GET_LOCKTIMEOUT:
  234.     value = (void *) locktimeout;
  235.     break;
  236.   case SET_LOCKEACCESERROR:
  237.     lockEaccesError = (long) value;
  238.     break;
  239.   case GET_LOCKEACCESERROR:
  240.     value = (void *) lockEaccesError;
  241.     break;
  242.   case SET_USERHASNOLIFE:
  243.     has_no_life = value ? T : NIL;
  244.     break;
  245.   case GET_USERHASNOLIFE:
  246.     value = (void *) (has_no_life ? T : NIL);
  247.     break;
  248.   case SET_BLOCKNOTIFY:
  249.     mailblocknotify = (blocknotify_t) value;
  250.   case GET_BLOCKNOTIFY:
  251.     value = (void *) mailblocknotify;
  252.     break;
  253.   default:
  254.     value = NIL; /* error case */
  255.     break;
  256.   }
  257.   return value;
  258. }
  259. /* Write current time
  260.  * Accepts: destination string
  261.  *     optional format of day-of-week prefix
  262.  *     format of date and time
  263.  *     flag whether to append symbolic timezone
  264.  */
  265. static void do_date (char *date,char *prefix,char *fmt,int suffix)
  266. {
  267.   time_t tn = time (0);
  268.   struct tm *t = gmtime (&tn);
  269.   int zone = t->tm_hour * 60 + t->tm_min;
  270.   int julian = t->tm_yday;
  271.   t = localtime (&tn); /* get local time now */
  272. /* minus UTC minutes since midnight */
  273.   zone = t->tm_hour * 60 + t->tm_min - zone;
  274.   /* julian can be one of:
  275.    *  36x  local time is December 31, UTC is January 1, offset -24 hours
  276.    *    1  local time is 1 day ahead of UTC, offset +24 hours
  277.    *    0  local time is same day as UTC, no offset
  278.    *   -1  local time is 1 day behind UTC, offset -24 hours
  279.    * -36x  local time is January 1, UTC is December 31, offset +24 hours
  280.    */
  281.   if (julian = t->tm_yday -julian)
  282.     zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
  283.   if (prefix) { /* want day of week? */
  284.     sprintf (date,prefix,days[t->tm_wday]);
  285.     date += strlen (date); /* make next sprintf append */
  286.   }
  287. /* output the date */
  288.   sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  289.    t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
  290. /* append timezone suffix if desired */
  291.   if (suffix) rfc822_timezone (date,(void *) t);
  292. }
  293. /* Write current time in RFC 822 format
  294.  * Accepts: destination string
  295.  */
  296. void rfc822_date (char *date)
  297. {
  298.   do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",T);
  299. }
  300. /* Write current time in fixed-width RFC 822 format
  301.  * Accepts: destination string
  302.  */
  303. void rfc822_fixed_date (char *date)
  304. {
  305.   do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
  306. }
  307. /* Write current time in internal format
  308.  * Accepts: destination string
  309.  */
  310. void internal_date (char *date)
  311. {
  312.   do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
  313. }
  314. /* Initialize server
  315.  * Accepts: server name for syslog or NIL
  316.  *     /etc/services service name or NIL
  317.  *     alternate /etc/services service name or NIL
  318.  *     SASL service name or NIL
  319.  *     clock interrupt handler
  320.  *     kiss-of-death interrupt handler
  321.  *     hangup interrupt handler
  322.  *     termination interrupt handler
  323.  */
  324. void server_init (char *server,char *service,char *altservice,char *sasl,
  325.   void *clkint,void *kodint,void *hupint,void *trmint)
  326. {
  327.   long port;
  328.   struct servent *sv;
  329.   struct sockaddr_in sin;
  330.   int sinlen = sizeof (struct sockaddr_in);
  331.   /* Don't use tcp_clienthost() since reverse DNS problems may slow down the
  332.    * greeting message and cause the client to time out.
  333.    */
  334.   char *client = getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ?
  335.     "UNKNOWN" : inet_ntoa (sin.sin_addr);
  336. /* set server name in syslog */
  337.   if (server) openlog (server,LOG_PID,LOG_MAIL);
  338.   if (service && altservice && ((port = tcp_serverport ()) >= 0)) {
  339.     if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
  340.       syslog (LOG_DEBUG,"%s service init from %s",service,client);
  341.     else if ((sv = getservbyname (altservice,"tcp")) &&
  342.      (port == ntohs (sv->s_port)))
  343.       syslog (LOG_DEBUG,"%s alternative service init from %s",
  344.       altservice,client);
  345.     else syslog (LOG_DEBUG,"port %ld service init from %s",port,client);
  346.   }
  347. /* set SASL name */
  348.   if (sasl) mail_parameters (NIL,SET_SERVICENAME,(void *) sasl);
  349.   signal (SIGALRM,clkint); /* prepare for clock interrupt */
  350.   signal (SIGUSR2,kodint); /* prepare for Kiss Of Death */
  351.   signal (SIGHUP,hupint); /* prepare for hangup */
  352.   signal (SIGTERM,trmint); /* prepare for termination */
  353. }
  354. /* Wait for stdin input
  355.  * Accepts: timeout in seconds
  356.  * Returns: T if have input on stdin, else NIL
  357.  */
  358. long server_input_wait (long seconds)
  359. {
  360.   fd_set rfd,efd;
  361.   struct timeval tmo;
  362.   FD_ZERO (&rfd);
  363.   FD_ZERO (&efd);
  364.   FD_SET (0,&rfd);
  365.   FD_SET (0,&efd);
  366.   tmo.tv_sec = seconds; tmo.tv_usec = 0;
  367.   return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
  368. }
  369. /* Server log in
  370.  * Accepts: user name string
  371.  *     password string
  372.  *     argument count
  373.  *     argument vector
  374.  * Returns: T if password validated, NIL otherwise
  375.  */
  376. long server_login (char *user,char *pwd,int argc,char *argv[])
  377. {
  378.   char *s,usr[MAILTMPLEN];
  379.   struct passwd *pw;
  380. /* cretins still haven't given up */
  381.   if (strlen (user) >= MAILTMPLEN)
  382.     syslog (LOG_ALERT|LOG_AUTH,"System break-in attempt, host=%.80s",
  383.     tcp_clienthost ());
  384. /* validate with case-independence */
  385.   else if ((logtry > 0) && ((pw = getpwnam (strcpy (usr,user))) ||
  386.     (pw = getpwnam (lcase (usr))))) {
  387.     if (auth_md5.server) { /* if using CRAM-MD5 authentication */
  388.       char *p = auth_md5_pwd (pw->pw_name);
  389.       if (p) { /* verify password */
  390. if (strcmp (p,pwd) && strcmp (p,pwd+1)) pw = NIL;
  391. memset (p,0,strlen (p));/* erase sensitive information */
  392. fs_give ((void **) &p); /* flush erased password */
  393. if (pw) return pw_login (pw,pw->pw_name,pw->pw_dir,argc,argv);
  394.       }
  395.       else syslog (LOG_ERR|LOG_AUTH,
  396.    "Login failed: %s has no CRAM-MD5 password, host=%.80s",
  397.    pw->pw_name,tcp_clienthost ());
  398.     }
  399. /* ordinary password authentication */
  400.     else if ((pw = checkpw (pw,pwd,argc,argv)) ||
  401.      ((*pwd == ' ') && (pw = checkpw (getpwnam(usr),pwd+1,argc,argv))))
  402.       return pw_login (pw,pw->pw_name,pw->pw_dir,argc,argv);
  403.   }
  404.   s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
  405. /* note the failure in the syslog */
  406.   syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
  407.   sleep (3); /* slow down possible cracker */
  408.   return NIL;
  409. }
  410. /* Authenticated server log in
  411.  * Accepts: user name string
  412.  *     argument count
  413.  *     argument vector
  414.  * Returns: T if password validated, NIL otherwise
  415.  */
  416. long authserver_login (char *user,int argc,char *argv[])
  417. {
  418.   struct passwd *pw = getpwnam (user);
  419.   return pw ? pw_login (pw,pw->pw_name,pw->pw_dir,argc,argv) : NIL;
  420. }
  421. /* Log in as anonymous daemon
  422.  * Accepts: argument count
  423.  *     argument vector
  424.  * Returns: T if successful, NIL if error
  425.  */
  426. long anonymous_login (int argc,char *argv[])
  427. {
  428.   struct passwd *pw = getpwnam ((char *) anonymous_user);
  429. /* log in Mr. A. N. Onymous */
  430.   return pw ? pw_login (pw,NIL,NIL,argc,argv) : NIL;
  431. }
  432. /* Finish log in and environment initialization
  433.  * Accepts: passwd struct for loginpw()
  434.  *     user name (NIL for anonymous)
  435.  *     home directory (NIL for anonymous)
  436.  *     argument count
  437.  *     argument vector
  438.  * Returns: T if successful, NIL if error
  439.  */
  440. long pw_login (struct passwd *pw,char *user,char *home,int argc,char *argv[])
  441. {
  442.   long ret = NIL;
  443.   char *u = user ? cpystr (user) : NIL;
  444.   char *h = home ? cpystr (home) : NIL;
  445.   if (pw->pw_uid && ((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
  446.       (ret = env_init (u,h))) chdir (myhomedir ());
  447.   if (h) fs_give ((void **) &h);/* flush temporary home directory */
  448.   if (u) fs_give ((void **) &u);/* flush temporary user name */
  449.   return ret; /* return status */
  450. }
  451. /* Initialize environment
  452.  * Accepts: user name
  453.  *     home directory name
  454.  * Returns: T, always
  455.  */
  456. long env_init (char *user,char *home)
  457. {
  458.   extern MAILSTREAM CREATEPROTO;
  459.   extern MAILSTREAM EMPTYPROTO;
  460.   struct passwd *pw;
  461.   struct stat sbuf;
  462.   char *s,tmp[MAILTMPLEN];
  463.   if (myUserName) fatal ("env_init called twice!");
  464. /* set up user name */
  465.   myUserName = cpystr (user ? user : (char *) anonymous_user);
  466.   if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
  467.   if (user) { /* remember user name and home directory */
  468.     nslist[0] = &nshome,nslist[1] = &nsamigaother,nslist[2] = &nsshared;
  469.     myHomeDir = cpystr (home); /* use real home directory */
  470.   }
  471.   else { /* anonymous user */
  472.     nslist[0] = nslist[1] = NIL,nslist[2] = &nsftp;
  473.     sprintf (tmp,"%s/INBOX",myHomeDir = cpystr (anonymousHome));
  474.     sysInbox = cpystr (tmp); /* make system INBOX */
  475.     anonymous = T; /* flag as anonymous */
  476.   }
  477.   if (!myLocalHost) mylocalhost ();
  478.   if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
  479.   if (!newsActive) newsActive = cpystr (ACTIVEFILE);
  480.   if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
  481.   if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
  482.   if (!publicHome && (pw = getpwnam ("imappublic")))
  483.     publicHome = cpystr (pw->pw_dir);
  484.   if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
  485.     sharedHome = cpystr (pw->pw_dir);
  486. /* force default prototype to be set */
  487.   if (!createProto) createProto = &CREATEPROTO;
  488.   if (!appendProto) appendProto = &EMPTYPROTO;
  489. /* re-do open action to get flags */
  490.   (*createProto->dtb->open) (NIL);
  491.   endpwent (); /* close pw database */
  492.   return T;
  493. }
  494.  
  495. /* Return my user name
  496.  * Accepts: pointer to optional flags
  497.  * Returns: my user name
  498.  */
  499. char *myusername_full (unsigned long *flags)
  500. {
  501.   char *ret = (char *) unlogged_user;
  502.   if (!myUserName) { /* get user name if don't have it yet */
  503.     struct passwd *pw;
  504.     unsigned long euid = geteuid ();
  505.     char *s = (char *) (euid ? getlogin () : NIL);
  506. /* look up getlogin() user name or EUID */
  507.     if (!((s && *s && (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
  508.   (pw = getpwuid (euid)))) fatal ("Unable to look up user name");
  509. /* init environment if not root */
  510.     if (euid) env_init (pw->pw_name,((s=getenv("HOME")) && *s) ? s:pw->pw_dir);
  511.     else ret = pw->pw_name; /* in case UID 0 user is other than root */
  512.   }
  513.   if (myUserName) { /* logged in? */
  514.     if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
  515.     ret = myUserName; /* return user name */
  516.   }
  517.   else if (flags) *flags = MU_NOTLOGGEDIN;
  518.   return ret;
  519. }
  520. /* Return my local host name
  521.  * Returns: my local host name
  522.  */
  523. char *mylocalhost ()
  524. {
  525.   char tmp[MAILTMPLEN];
  526.   struct hostent *host_name;
  527.   if (!myLocalHost) {
  528.     gethostname(tmp,MAILTMPLEN);/* get local host name */
  529.     myLocalHost = cpystr ((host_name = gethostbyname (tmp)) ?
  530.   host_name->h_name : tmp);
  531.   }
  532.   return myLocalHost;
  533. }
  534. /* Return my home directory name
  535.  * Returns: my home directory name
  536.  */
  537. char *myhomedir ()
  538. {
  539.   if (!myHomeDir) myusername ();/* initialize if first time */
  540.   return myHomeDir ? myHomeDir : "";
  541. }
  542. /* Return system standard INBOX
  543.  * Accepts: buffer string
  544.  */
  545. char *sysinbox ()
  546. {
  547.   char tmp[MAILTMPLEN];
  548.   if (!sysInbox) { /* initialize if first time */
  549.     sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
  550.     sysInbox = cpystr (tmp); /* system inbox is from mail spool */
  551.   }
  552.   return sysInbox;
  553. }
  554. /* Return mailbox directory name
  555.  * Accepts: destination buffer
  556.  *     directory prefix
  557.  *     name in directory
  558.  * Returns: file name or NIL if error
  559.  */
  560. char *mailboxdir (char *dst,char *dir,char *name)
  561. {
  562.   char tmp[MAILTMPLEN];
  563.   if (dir || name) { /* if either argument provided */
  564.     if (dir) strcpy (tmp,dir); /* write directory prefix */
  565.     else tmp[0] = ''; /* otherwise null string */
  566.     if (name) strcat (tmp,name);/* write name in directory */
  567. /* validate name, return its name */
  568.     if (!mailboxfile (dst,tmp)) return NIL;
  569.   }
  570.   else strcpy (dst,myhomedir());/* no arguments, wants home directory */
  571.   return dst; /* return the name */
  572. }
  573. /* Return mailbox file name
  574.  * Accepts: destination buffer
  575.  *     mailbox name
  576.  * Returns: file name or empty string for driver-selected INBOX or NIL if error
  577.  */
  578. char *mailboxfile (char *dst,char *name)
  579. {
  580.   struct passwd *pw;
  581.   char *dir = myhomedir ();
  582.   *dst = ''; /* default to empty string */
  583. /* check invalid name */
  584.   if (!name || !*name || (*name == '{')) return NIL;
  585. /* check for INBOX */
  586.   if (((name[0] == 'I') || (name[0] == 'i')) &&
  587.       ((name[1] == 'N') || (name[1] == 'n')) &&
  588.       ((name[2] == 'B') || (name[2] == 'b')) &&
  589.       ((name[3] == 'O') || (name[3] == 'o')) &&
  590.       ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) {
  591. /* if restricted, canonicalize name of INBOX */
  592.     if (anonymous) name = "INBOX";
  593.     else return dst; /* else driver selects the INBOX name */
  594.   }
  595. /* restricted name? */
  596.   else if ((*name == '#') || anonymous) {
  597.     if (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))
  598.       return NIL; /* none of these allowed when restricted */
  599.     switch (*name) { /* what kind of restricted name? */
  600.     case '#': /* namespace name */
  601.       if (((name[1] == 'f') || (name[1] == 'F')) &&
  602.   ((name[2] == 't') || (name[2] == 'T')) &&
  603.   ((name[3] == 'p') || (name[3] == 'P')) &&
  604.   (name[4] == '/') && (dir = ftpHome)) name += 5;
  605.       else if (((name[1] == 'p') || (name[1] == 'P')) &&
  606.        ((name[2] == 'u') || (name[2] == 'U')) &&
  607.        ((name[3] == 'b') || (name[3] == 'B')) &&
  608.        ((name[4] == 'l') || (name[4] == 'L')) &&
  609.        ((name[5] == 'i') || (name[5] == 'I')) &&
  610.        ((name[6] == 'c') || (name[6] == 'C')) &&
  611.        (name[7] == '/') && (dir = publicHome)) name += 8;
  612.       else if (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
  613.        ((name[2] == 'h') || (name[2] == 'H')) &&
  614.        ((name[3] == 'a') || (name[3] == 'A')) &&
  615.        ((name[4] == 'r') || (name[4] == 'R')) &&
  616.        ((name[5] == 'e') || (name[5] == 'E')) &&
  617.        ((name[6] == 'd') || (name[6] == 'D')) &&
  618.        (name[7] == '/') && (dir = sharedHome)) name += 8;
  619.       else return NIL; /* unknown namespace name */
  620.       break;
  621.     case '/': /* rooted restricted name */
  622.       return NIL; /* anonymous can't do this */
  623.     }
  624.   }
  625. /* absolute path name? */
  626.   else if (*name == '/') return strcpy (dst,name);
  627. /* some home directory? */
  628.   else if ((*name == '~') && *++name) {
  629.     if (*name == '/') name++; /* yes, my home directory? */
  630.     else { /* no, copy user name */
  631.       for (dir = dst; *name && (*name != '/'); *dir++ = *name++);
  632.       *dir++ = ''; /* tie off user name, look up in passwd file */
  633.       if (!((pw = getpwnam (dst)) && (dir = pw->pw_dir))) return NIL;
  634.       if (*name) name++; /* skip past the slash */
  635.     }
  636.   }
  637. /* build resulting name */
  638.   sprintf (dst,"%s/%s",dir,name);
  639.   return dst; /* return it */
  640. }
  641. /* Dot-lock file locker
  642.  * Accepts: file name to lock
  643.  *     destination buffer for lock file name
  644.  *     open file description on file name to lock
  645.  * Returns: T if success, NIL if failure
  646.  */
  647. long dotlock_lock (char *file,DOTLOCK *base,int fd)
  648. {
  649.   int ld,j;
  650.   int i = locktimeout * 60 - 1;
  651.   char *s,hitch[MAILTMPLEN],tmp[MAILTMPLEN];
  652.   time_t t;
  653.   struct stat sb;
  654. /* flush absurd file name */
  655.   if (strlen (file) > 512) return NIL;
  656. /* build lock filename */
  657.   sprintf (base->lock,"%s.lock",file);
  658. /* assume no pipe */
  659.   base->pipei = base->pipeo = -1;
  660. /* until OK or out of tries */
  661.   if (j = chk_notsymlink (base->lock,&sb)) do {
  662.     t = time (0); /* get the time now */
  663. /* time out old locks */
  664.     if ((j > 0) && (t >= (sb.st_ctime + locktimeout * 60))) {
  665.       unlink (base->lock); /* flush extant old lock */
  666.       j = O_WRONLY | O_CREAT; /* try to grab it for ourselves */
  667.     }
  668.     else j = O_WRONLY | O_CREAT | O_EXCL;
  669. /* try to get the lock */
  670.     if ((ld = open (strcpy (hitch,base->lock),j,(int) lock_protection)) >= 0)
  671.       close (ld); /* close the lock file */
  672.     else switch (errno) { /* what happened? */
  673.       case EACCES: /* protection fail */
  674. if (stat (hitch,&sb)) { /* file exists, fall into EEXIST case */
  675.   int pi[2],po[2];
  676. /* make command pipes */
  677.   if (!stat (LOCKPGM,&sb) && pipe (pi) >= 0) {
  678.     if (pipe (po) >= 0) {
  679. /* make inferior process */
  680.       if (!(j = fork ())) {
  681. if (!fork ()) { /* make grandchild so it's inherited by init */
  682.   char *argv[4];/* prepare argument vector for */
  683.   sprintf (tmp,"%d",fd);
  684.   argv[0] = LOCKPGM; argv[1] = tmp;
  685.   argv[2] = file; argv[3] = NIL;
  686. /* set parent's I/O to my O/I */
  687.   dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
  688. /* close all unnecessary descriptors */
  689.   for (j = max (20,max (max (pi[0],pi[1]),max (po[0],po[1])));
  690.        j >= 3; --j) if (j != fd) close (j);
  691. /* be our own process group */
  692.   setpgrp (0,getpid ());
  693. /* now run it */
  694.   execv (argv[0],argv);
  695. }
  696. _exit (1); /* child is done */
  697.       }
  698.       else if (j > 0) { /* reap child; grandchild now owned by init */
  699. grim_pid_reap (j,NIL);
  700. /* read response from locking program */
  701. if ((read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
  702. /* success, record pipes */
  703.   base->pipei = pi[0]; base->pipeo = po[1];
  704. /* close child's side of the pipes */
  705.   close (pi[1]); close (po[0]);
  706.   return LONGT;
  707. }
  708.       }
  709.       close (po[0]); close (po[1]);
  710.     }
  711.     close (pi[0]); close (pi[1]);
  712.   }
  713.   if (lockEaccesError) {/* punt silently if paranoid site */
  714.     sprintf (tmp,"Mailbox vulnerable - directory %.80s",hitch);
  715.     if (s = strrchr (tmp,'/')) *s = '';
  716.     strcat (tmp," must have 1777 protection");
  717.     mm_log (tmp,WARN);
  718.   }
  719.   base->lock[0] = ''; /* give up on lock file */
  720. }
  721.       case EEXIST: /* file already exists */
  722. break; /* try again */
  723.       default: /* some other failure */
  724. sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
  725.  hitch,strerror (errno));
  726. mm_log (tmp,WARN); /* this is probably not good */
  727. base->lock[0] = ''; /* don't use lock files */
  728. break;
  729.       }
  730. /* if failed to make lock file and retry OK */
  731.     if ((ld < 0) && base->lock) {
  732.       if (!(i%15)) { /* time to notify? */
  733. sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
  734.  file,i);
  735. mm_log (tmp,WARN);
  736.       }
  737.       sleep (1); /* wait 1 second before next try */
  738.     }
  739.   } while (i-- && (ld < 0) && base->lock[0]);
  740. /* failed if no longer a lock name */
  741.   if (!base->lock[0]) return NIL;
  742. /* make sure others can break the lock */
  743.   chmod (base->lock,(int) lock_protection);
  744.   return LONGT;
  745. }
  746. /* Dot-lock file unlocker
  747.  * Accepts: lock file name
  748.  * Returns: T if success, NIL if failure
  749.  */
  750. long dotlock_unlock (DOTLOCK *base)
  751. {
  752.   long ret = LONGT;
  753.   if (base && base->lock[0]) {
  754.     if (base->pipei >= 0) { /* if running through a pipe unlocker */
  755.       ret = (write (base->pipeo,"+",1) == 1);
  756. /* nuke the pipes */
  757.       close (base->pipei); close (base->pipeo);
  758.     }
  759.     else ret = !unlink (base->lock);
  760.   }
  761.   return ret;
  762. }
  763. /* Lock file name
  764.  * Accepts: scratch buffer
  765.  *     file name
  766.  *     type of locking operation (LOCK_SH or LOCK_EX)
  767.  *     pointer to return PID of locker
  768.  * Returns: file descriptor of lock or negative if error
  769.  */
  770. int lockname (char *lock,char *fname,int op,long *pid)
  771. {
  772.   struct stat sbuf;
  773.   *pid = 0; /* no locker PID */
  774.   return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
  775. }
  776. /* Lock file descriptor
  777.  * Accepts: file descriptor
  778.  *     lock file name buffer
  779.  *     type of locking operation (LOCK_SH or LOCK_EX)
  780.  * Returns: file descriptor of lock or negative if error
  781.  */
  782. int lockfd (int fd,char *lock,int op)
  783. {
  784.   struct stat sbuf;
  785.   return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
  786. }
  787. /* Lock file name worker
  788.  * Accepts: lock file name
  789.  *     pointer to stat() buffer
  790.  *     type of locking operation (LOCK_SH or LOCK_EX)
  791.  *     pointer to return PID of locker
  792.  * Returns: file descriptor of lock or negative if error
  793.  */
  794. int lock_work (char *lock,void *sb,int op,long *pid)
  795. {
  796.   struct stat lsb,fsb;
  797.   struct stat *sbuf = sb;
  798.   char tmp[MAILTMPLEN];
  799.   long i;
  800.   int fd;
  801.   if (pid) *pid = 0; /* initialize return PID */
  802. /* make temporary lock file name */
  803.   sprintf (lock,"/tmp/.%lx.%lx",(unsigned long) sbuf->st_dev,
  804.    (unsigned long) sbuf->st_ino);
  805.   while (T) { /* until get a good lock */
  806.     do switch ((int) chk_notsymlink (lock,&lsb)) {
  807.     case 1: /* exists just once */
  808.       if (((fd = open (lock,O_RDWR,lock_protection)) >= 0) ||
  809.   (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
  810.     case -1: /* name doesn't exist */
  811.       fd = open (lock,O_RDWR|O_CREAT|O_EXCL,lock_protection);
  812.       break;
  813.     default: /* multiple hard links */
  814.       mm_log ("hard link to lock name",ERROR);
  815.       syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
  816.     case 0: /* symlink (already did syslog) */
  817.       return -1; /* fail: no lock file */
  818.     } while ((fd < 0) && (errno == EEXIST));
  819.     if (fd < 0) { /* failed to get file descriptor */
  820.       syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
  821.       strerror (errno));
  822.       return -1; /* fail: can't open lock file */
  823.     }
  824. /* non-blocking form */
  825.     if (op & LOCK_NB) i = flock (fd,op);
  826.     else { /* blocking form */
  827.       (*mailblocknotify) (BLOCK_FILELOCK,NIL);
  828.       i = flock (fd,op);
  829.       (*mailblocknotify) (BLOCK_NONE,NIL);
  830.     }
  831.     if (i) { /* failed, get other process' PID */
  832.       if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
  833.   (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
  834. *pid = i;
  835.       close (fd); /* failed, give up on lock */
  836.       return -1; /* fail: can't lock */
  837.     }
  838. /* make sure this lock is good for us */
  839.     if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
  840. !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
  841. (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
  842.     close (fd); /* lock not right, drop fd and try again */
  843.   }
  844. /* make sure mode OK (don't use fchmod()) */
  845.   chmod (lock,(int) lock_protection);
  846.   return fd; /* success */
  847. }
  848. /* Check to make sure not a symlink
  849.  * Accepts: file name
  850.  *     stat buffer
  851.  * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
  852.  */
  853. long chk_notsymlink (char *name,void *sb)
  854. {
  855.   struct stat *sbuf = sb;
  856. /* name exists? */
  857.   if (lstat (name,sbuf)) return -1;
  858. /* forbid symbolic link */
  859.   if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
  860.     mm_log ("symbolic link on lock name",ERROR);
  861.     syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
  862.     name);
  863.     return NIL;
  864.   }
  865.   return (long) sbuf->st_nlink; /* return number of hard links */
  866. }
  867. /* Unlock file descriptor
  868.  * Accepts: file descriptor
  869.  *     lock file name from lockfd()
  870.  */
  871. void unlockfd (int fd,char *lock)
  872. {
  873. /* delete the file if no sharers */
  874.   if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
  875.   flock (fd,LOCK_UN); /* unlock it */
  876.   close (fd); /* close it */
  877. }
  878. /* Set proper file protection for mailbox
  879.  * Accepts: mailbox name
  880.  *     actual file path name
  881.  * Returns: T, always
  882.  */
  883. long set_mbx_protections (char *mailbox,char *path)
  884. {
  885.   struct stat sbuf;
  886.   int mode = (int) mbx_protection;
  887.   if (*mailbox == '#') { /* possible namespace? */
  888.       if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
  889.   ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
  890.   ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
  891.   (mailbox[4] == '/')) mode = (int) ftp_protection;
  892.       else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
  893.        ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
  894.        ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
  895.        ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
  896.        ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
  897.        ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
  898.        (mailbox[7] == '/')) mode = (int) public_protection;
  899.       else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
  900.        ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
  901.        ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
  902.        ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
  903.        ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
  904.        ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
  905.        (mailbox[7] == '/')) mode = (int) shared_protection;
  906.   }
  907. /* if a directory */
  908.   if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
  909. /* set owner search if allow read or write */
  910.     if (mode & 0600) mode |= 0100;
  911.     if (mode & 060) mode |= 010;/* set group search if allow read or write */
  912.     if (mode & 06) mode |= 01; /* set world search if allow read or write */
  913.   }
  914.   chmod (path,mode); /* set the new protection, ignore failure */
  915.   return LONGT;
  916. }
  917. /* Determine default prototype stream to user
  918.  * Accepts: type (NIL for create, T for append)
  919.  * Returns: default prototype stream
  920.  */
  921. MAILSTREAM *default_proto (long type)
  922. {
  923.   myusername (); /* make sure initialized */
  924. /* return default driver's prototype */
  925.   return type ? appendProto : createProto;
  926. }
  927. /* Set up user flags for stream
  928.  * Accepts: MAIL stream
  929.  * Returns: MAIL stream with user flags set up
  930.  */
  931. MAILSTREAM *user_flags (MAILSTREAM *stream)
  932. {
  933.   int i;
  934.   myusername (); /* make sure initialized */
  935.   for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
  936.     if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
  937.   return stream;
  938. }
  939. /* Return nth user flag
  940.  * Accepts: user flag number
  941.  * Returns: flag
  942.  */
  943. char *default_user_flag (unsigned long i)
  944. {
  945.   myusername (); /* make sure initialized */
  946.   return userFlags[i];
  947. }
  948. /* Default block notify routine
  949.  * Accepts: reason for calling
  950.  *     data
  951.  * Returns: data
  952.  */
  953. void *mm_blocknotify (int reason,void *data)
  954. {
  955.   void *ret = data;
  956.   switch (reason) {
  957.   case BLOCK_SENSITIVE: /* entering sensitive code */
  958.     data = (void *) max (alarm (0),1);
  959.     break;
  960.   case BLOCK_NONSENSITIVE: /* exiting sensitive code */
  961.     if ((unsigned int) data) alarm ((unsigned int) data);
  962.     break;
  963.   default: /* ignore all other reasons */
  964.     break;
  965.   }
  966.   return ret;
  967. }