home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / pine4.10.tar.gz / pine4.10.tar / pine4.10 / imap / src / osdep / nt / env_nt.c < prev    next >
C/C++ Source or Header  |  1998-12-11  |  17KB  |  562 lines

  1. /*
  2.  * Program:    NT 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:    10 December 1998
  14.  *
  15.  * Copyright 1998 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.  
  36.  
  37. static char *myUserName = NIL;    /* user name */
  38. static char *myLocalHost = NIL;    /* local host name */
  39. static char *myClientHost = NIL;/* client host name */
  40. static char *myServerHost = NIL;/* server host name */
  41. static char *myHomeDir = NIL;    /* home directory name */
  42. static char *myNewsrc = NIL;    /* newsrc file name */
  43. static char *sysInbox = NIL;    /* system inbox name */
  44. static long list_max_level = 5;    /* maximum level of list recursion */
  45.                 /* home namespace */
  46. static NAMESPACE nshome = {"",'\\',NIL,NIL};
  47.                 /* namespace list */
  48. static NAMESPACE *nslist[3] = {&nshome,NIL,NIL};
  49. static long alarm_countdown = 0;/* alarm count down */
  50. static void (*alarm_rang) ();    /* alarm interrupt function */
  51. static unsigned int rndm = 0;    /* initial `random' number */
  52. static int logtry = 3;        /* number of login tries */
  53.                 /* callback to get username */
  54. static userprompt_t mailusername = NIL;
  55. static long is_nt = -1;        /* T if NT, NIL if not NT, -1 unknown */
  56.  
  57. #include "write.c"        /* include safe writing routines */
  58.  
  59.  
  60. /* Get all authenticators */
  61.  
  62. #include "auths.c"
  63.  
  64. /* Environment manipulate parameters
  65.  * Accepts: function code
  66.  *        function-dependent value
  67.  * Returns: function-dependent return value
  68.  */
  69.  
  70. void *env_parameters (long function,void *value)
  71. {
  72.   switch ((int) function) {
  73.   case SET_NAMESPACE:
  74.     fatal ("SET_NAMESPACE not permitted");
  75.   case GET_NAMESPACE:
  76.     value = (void *) nslist;
  77.     break;
  78.   case SET_USERPROMPT :
  79.     mailusername = (userprompt_t) value;
  80.     break;
  81.   case GET_USERPROMPT :
  82.     value = (void *) mailusername;
  83.     break;
  84.   case SET_HOMEDIR:
  85.     if (myHomeDir) fs_give ((void **) &myHomeDir);
  86.     myHomeDir = cpystr ((char *) value);
  87.     break;
  88.   case GET_HOMEDIR:
  89.     value = (void *) myHomeDir;
  90.     break;
  91.   case SET_LOCALHOST:
  92.     myLocalHost = cpystr ((char *) value);
  93.     break;
  94.   case GET_LOCALHOST:
  95.     if (myLocalHost) fs_give ((void **) &myLocalHost);
  96.     value = (void *) myLocalHost;
  97.     break;
  98.   case SET_NEWSRC:
  99.     if (myNewsrc) fs_give ((void **) &myNewsrc);
  100.     myNewsrc = cpystr ((char *) value);
  101.     break;
  102.   case GET_NEWSRC:
  103.     if (!myNewsrc) {        /* set news file name if not defined */
  104.       char tmp[MAILTMPLEN];
  105.       sprintf (tmp,"%s\\NEWSRC",myhomedir ());
  106.       myNewsrc = cpystr (tmp);
  107.     }
  108.     value = (void *) myNewsrc;
  109.     break;
  110.   case SET_SYSINBOX:
  111.     if (sysInbox) fs_give ((void **) &sysInbox);
  112.     sysInbox = cpystr ((char *) value);
  113.     break;
  114.   case GET_SYSINBOX:
  115.     value = (void *) sysInbox;
  116.     break;
  117.   case SET_LISTMAXLEVEL:
  118.     list_max_level = (long) value;
  119.     break;
  120.   case GET_LISTMAXLEVEL:
  121.     value = (void *) list_max_level;
  122.     break;
  123.   default:
  124.     value = NIL;        /* error case */
  125.     break;
  126.   }
  127.   return value;
  128. }
  129.  
  130. /* Write current time
  131.  * Accepts: destination string
  132.  *        optional format of day-of-week prefix
  133.  *        format of date and time
  134.  *        flag whether to append symbolic timezone
  135.  */
  136.  
  137. static void do_date (char *date,char *prefix,char *fmt,int suffix)
  138. {
  139.   time_t tn = time (0);
  140.   struct tm *t = gmtime (&tn);
  141.   int zone = t->tm_hour * 60 + t->tm_min;
  142.   int julian = t->tm_yday;
  143.   t = localtime (&tn);        /* get local time now */
  144.                 /* minus UTC minutes since midnight */
  145.   zone = t->tm_hour * 60 + t->tm_min - zone;
  146.   /* julian can be one of:
  147.    *  36x  local time is December 31, UTC is January 1, offset -24 hours
  148.    *    1  local time is 1 day ahead of UTC, offset +24 hours
  149.    *    0  local time is same day as UTC, no offset
  150.    *   -1  local time is 1 day behind UTC, offset -24 hours
  151.    * -36x  local time is January 1, UTC is December 31, offset +24 hours
  152.    */
  153.   if (julian = t->tm_yday -julian)
  154.     zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
  155.   if (prefix) {            /* want day of week? */
  156.     sprintf (date,prefix,days[t->tm_wday]);
  157.     date += strlen (date);    /* make next sprintf append */
  158.   }
  159.                 /* output the date */
  160.   sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  161.        t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
  162.   if (suffix) {            /* append timezone suffix if desired */
  163.     char *tz;
  164.     tzset ();            /* get timezone from TZ environment stuff */
  165.     tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
  166.     if (tz && tz[0]) sprintf (date + strlen (date)," (%s)",tz);
  167.   }
  168. }
  169.  
  170.  
  171. /* Write current time in RFC 822 format
  172.  * Accepts: destination string
  173.  */
  174.  
  175. void rfc822_date (char *date)
  176. {
  177.   do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",T);
  178. }
  179.  
  180.  
  181. /* Write current time in internal format
  182.  * Accepts: destination string
  183.  */
  184.  
  185. void internal_date (char *date)
  186. {
  187.   do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
  188. }
  189.  
  190. /* Return random number
  191.  */
  192.  
  193. long random (void)
  194. {
  195.   if (!rndm) srand (rndm = (unsigned) time (0L));
  196.   return (long) rand ();
  197. }
  198.  
  199.  
  200. /* Set alarm timer
  201.  * Accepts: new value
  202.  */
  203.  
  204. void alarm (long seconds)
  205. {
  206.   alarm_countdown = seconds;
  207. }
  208.  
  209.  
  210. /* The clock ticked
  211.  */
  212.  
  213. void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser,
  214.                 DWORD dwReserved1,DWORD dwReserved2)
  215. {
  216.   if (alarm_rang && !--alarm_countdown) (*alarm_rang) ();
  217. }
  218.  
  219. /* Initialize server
  220.  * Accepts: server name for syslog or NIL
  221.  *        /etc/services service name or NIL
  222.  *        alternate /etc/services service name or NIL
  223.  *        SASL service name or NIL
  224.  *        clock interrupt handler
  225.  *        kiss-of-death interrupt handler
  226.  *        hangup interrupt handler
  227.  *        termination interrupt handler
  228.  */
  229.  
  230. void server_init (char *server,char *service,char *altservice,char *sasl,
  231.           void *clkint,void *kodint,void *hupint,void *trmint)
  232. {
  233.   if (server) {            /* set server name in syslog */
  234.     openlog (server,LOG_PID,LOG_MAIL);
  235.     fclose (stderr);        /* possibly save a process ID */
  236.   }
  237.                 /* set SASL name */
  238.   if (sasl) mail_parameters (NIL,SET_SERVICENAME,(void *) sasl);
  239.   alarm_rang = clkint;        /* note the clock interrupt */
  240.   timeBeginPeriod (1000);    /* set the timer interval */
  241.   timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC);
  242. }
  243.  
  244.  
  245. /* Wait for stdin input
  246.  * Accepts: timeout in seconds
  247.  * Returns: T if have input on stdin, else NIL
  248.  */
  249.  
  250. long server_input_wait (long seconds)
  251. {
  252.   fd_set rfd;
  253.   struct timeval tmo;
  254.   FD_ZERO (&rfd);
  255.   FD_SET (0,&rfd);
  256.   tmo.tv_sec = seconds; tmo.tv_usec = 0;
  257.   return select (1,&rfd,0,0,&tmo) ? LONGT : NIL;
  258. }
  259.  
  260. /* Server log in
  261.  * Accepts: user name string
  262.  *        password string
  263.  *        argument count
  264.  *        argument vector
  265.  * Returns: T if password validated, NIL otherwise
  266.  */
  267.  
  268. static int gotprivs = NIL;    /* once-only flag to grab privileges */
  269.  
  270. long server_login (char *user,char *pass,int argc,char *argv[])
  271. {
  272.   HANDLE hdl;
  273.   LUID tcbpriv;
  274.   TOKEN_PRIVILEGES tkp;
  275.   char *s;
  276.   if (!gotprivs++) {        /* need to get privileges? */
  277.                 /* yes, note client host if specified */
  278.     if (argc == 2) myClientHost = argv[1];
  279.                 /* get process token and TCB priv value */
  280.     if (!(OpenProcessToken (GetCurrentProcess (),
  281.                 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) &&
  282.       LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv)))
  283.       return NIL;
  284.     tkp.PrivilegeCount = 1;    /* want to enable this privilege */
  285.     tkp.Privileges[0].Luid = tcbpriv;
  286.     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  287.                 /* enable it */
  288.     AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES),
  289.                (PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL);
  290.                 /* make sure it won */
  291.     if (GetLastError() != ERROR_SUCCESS) return NIL;
  292.   }
  293.                 /* cretins still haven't given up */
  294.   if (strlen (user) >= MAILTMPLEN)
  295.     syslog (LOG_ALERT,"System break-in attempt, host=%.80s",tcp_clienthost ());
  296.   else if ((logtry > 0) &&    /* try to login and impersonate the guy */
  297.        ((LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE,
  298.             LOGON32_PROVIDER_DEFAULT,&hdl) ||
  299.          LogonUser (user,".",pass,LOGON32_LOGON_BATCH,
  300.             LOGON32_PROVIDER_DEFAULT,&hdl) ||
  301.          LogonUser (user,".",pass,LOGON32_LOGON_SERVICE,
  302.             LOGON32_PROVIDER_DEFAULT,&hdl)) &&
  303.         ImpersonateLoggedOnUser (hdl))) return env_init (user,NIL);
  304.   s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
  305.                 /* note the failure in the syslog */
  306.   syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
  307.   sleep (3);            /* slow down possible cracker */
  308.   return NIL;
  309. }
  310.  
  311. /* Authenticated server log in
  312.  * Accepts: user name string
  313.  *        argument count
  314.  *        argument vector
  315.  * Returns: T if password validated, NIL otherwise
  316.  */
  317.  
  318. long authserver_login (char *user,int argc,char *argv[])
  319. {
  320.   return server_login (user,NIL,argc,argv);
  321. }
  322.  
  323.  
  324. /* Log in as anonymous daemon
  325.  * Accepts: argument count
  326.  *        argument vector
  327.  * Returns: T if successful, NIL if error
  328.  */
  329.  
  330. long anonymous_login (int argc,char *argv[])
  331. {
  332.   return server_login ("Guest",NIL,argc,argv);
  333. }
  334.  
  335. /* Initialize environment
  336.  * Accepts: user name, or NIL to skip setting user name on (Win9x only)
  337.  *          home directory, or NIL to use user info (NT only)
  338.  * Returns: T, always
  339.  */
  340.  
  341. typedef NET_API_STATUS (CALLBACK *NUGI)
  342.      (LPCWSTR servername,LPCWSTR username,DWORD level,LPBYTE *bufptr);
  343.  
  344.  
  345. long env_init (char *user,char *home)
  346. {
  347.   if (myUserName) fatal ("env_init called twice!");
  348.                 /* remember user name */
  349.   if (user && *user) myUserName = cpystr (user);
  350.   else if (check_nt ()) fatal ("missing user name argument to env_init!");
  351.   if (!myHomeDir) {        /* only if home directory not set up yet */
  352.                 /* remember home directory */
  353.     if (home && *home) myHomeDir = cpystr (home);
  354.     else if (check_nt ()) {    /* get from user info on NT */
  355.       char tmp[MAILTMPLEN];
  356.       PUSER_INFO_1 ui;
  357.       NUGI nugi;
  358.       HINSTANCE nahdl = LoadLibrary ("netapi32.dll");
  359.       if (!(nahdl && (nugi = (NUGI) GetProcAddress (nahdl,"NetUserGetInfo")) &&
  360.         MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1,
  361.                  (WCHAR *) tmp,MAILTMPLEN) &&
  362.         !(*nugi) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) &&
  363.         WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1,
  364.                  tmp,MAILTMPLEN,NIL,NIL) && tmp[0]))
  365.     sprintf (tmp,"%s%s",defaultDrive (),"\\users\\default");
  366.       myHomeDir = cpystr (tmp);    /* remember home directory */
  367.     }
  368.     else fatal ("missing home directory argument to env_init!");
  369.   }
  370.   return T;
  371. }
  372.  
  373.  
  374. /* Check if NT
  375.  * Returns: T if NT, NIL if Win9x
  376.  */
  377.  
  378. int check_nt (void)
  379. {
  380.   if (is_nt < 0) {        /* not yet set up? */
  381.     OSVERSIONINFO ver;
  382.     ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  383.     GetVersionEx (&ver);
  384.     is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL;
  385.   }
  386.   return is_nt;
  387. }
  388.  
  389. /* Return default drive
  390.  * Returns: default drive
  391.  */
  392.  
  393. static char *defaultDrive (void)
  394. {
  395.   char *s;
  396.   return ((s = getenv ("SystemDrive")) && *s) ? s : "C:";
  397. }
  398.  
  399.  
  400. /* Return home path from environment variables
  401.  * Accepts: path to write into
  402.  * Returns: home path, or NIL if it can't be determined (NT only)
  403.  */
  404.  
  405. static char *homePath (char *path)
  406. {
  407.   int i;
  408.   char *s;
  409.                 /* get home drive */
  410.   strcpy (path,((s = getenv ("HOMEDRIVE")) && *s) ? s : defaultDrive ());
  411.                 /* if have a home path */
  412.   if ((s = getenv ("HOMEPATH")) && (i = strlen (s))) {
  413.     if (((s[i-1] == '\\') || (s[i-1] == '/'))) s[i-1] = '\0';
  414.     strcat (path,s);        /* append the home path to the drive */
  415.   }
  416.                 /* return NIL if NT and no home path */
  417.   else if (check_nt ()) return NIL;
  418.   return path;
  419. }
  420.  
  421. /* Return my user name
  422.  * Accepts: pointer to optional flags
  423.  * Returns: my user name
  424.  */
  425.  
  426. char *myusername_full (unsigned long *flags)
  427. {
  428.   HANDLE tok;
  429.   UCHAR tmp[MAILTMPLEN],user[MAILTMPLEN],domain[MAILTMPLEN];
  430.   DWORD len,userlen = MAILTMPLEN,domainlen = MAILTMPLEN;
  431.   SID_NAME_USE snu;
  432.   char *ret = "SYSTEM";
  433.   if (!myUserName) {        /* get user name if don't have it yet */
  434.     if (check_nt ()) {        /* NT lookup user and domain */
  435.       if (!(OpenProcessToken (GetCurrentProcess (),TOKEN_READ,&tok) &&
  436.         GetTokenInformation (tok,TokenUser,tmp,MAILTMPLEN,&len) &&
  437.         LookupAccountSid (NIL,((PTOKEN_USER) tmp)->User.Sid,user,
  438.                   &userlen,domain,&domainlen,&snu)))
  439.     fatal ("Unable to look up user name");
  440.                 /* init environment if not SYSTEM */
  441.       if (_stricmp (user,"SYSTEM")) env_init (user,homePath (tmp));
  442.     }
  443.                 /* Win9x external username */
  444.     else env_init (mailusername ? (*mailusername) () : NIL,homePath (tmp));
  445.   }
  446.   if (myUserName) {        /* logged in? */
  447.     if (flags)            /* Guest is an anonymous user */
  448.       *flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS;
  449.     ret = myUserName;        /* return user name */
  450.   }
  451.   else if (flags) *flags = MU_NOTLOGGEDIN;
  452.   return ret;
  453. }
  454.  
  455.  
  456. /* Return my home directory name
  457.  * Returns: my home directory name
  458.  */
  459.  
  460. char *myhomedir ()
  461. {
  462.   if (!myHomeDir) myusername ();/* initialize if first time */
  463.   return myHomeDir ? myHomeDir : "";
  464. }
  465.  
  466. /* Return system standard INBOX
  467.  * Accepts: buffer string
  468.  */
  469.  
  470. char *sysinbox ()
  471. {
  472.   char tmp[MAILTMPLEN];
  473.   if (!sysInbox) {        /* initialize if first time */
  474.     if (check_nt ()) sprintf (tmp,MAILFILE,myUserName);
  475.     else sprintf (tmp,"%s\\INBOX",myhomedir ());
  476.     sysInbox = cpystr (tmp);    /* system inbox is from mail spool */
  477.   }
  478.   return sysInbox;
  479. }
  480.  
  481.  
  482. /* Return mailbox file name
  483.  * Accepts: destination buffer
  484.  *        mailbox name
  485.  * Returns: file name
  486.  */
  487.  
  488. char *mailboxfile (char *dst,char *name)
  489. {
  490.   char *dir = myhomedir ();
  491.   *dst = '\0';            /* default to empty string */
  492.   if (((name[0] == 'I') || (name[0] == 'i')) &&
  493.       ((name[1] == 'N') || (name[1] == 'n')) &&
  494.       ((name[2] == 'B') || (name[2] == 'b')) &&
  495.       ((name[3] == 'O') || (name[3] == 'o')) &&
  496.       ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) name = NIL;
  497.                 /* reject namespace names or names with / */
  498.   if (name && ((*name == '#') || strchr (name,'/'))) return NIL;
  499.   else if (!name) return dst;    /* driver selects the INBOX name */
  500.                 /* absolute path name? */
  501.   else if ((*name == '\\') || (name[1] == ':')) return strcpy (dst,name);
  502.                 /* build resulting name */
  503.   sprintf (dst,"%s\\%s",dir,name);
  504.   return dst;            /* return it */
  505. }
  506.  
  507. /* Lock file name
  508.  * Accepts: return buffer for file name
  509.  *        file name
  510.  *        locking to be placed on file if non-NIL
  511.  * Returns: file descriptor of lock or -1 if error
  512.  */
  513.  
  514. int lockname (char *lock,char *fname,int op)
  515. {
  516.   int ld;
  517.   char c,*s;
  518.   if (((s = getenv ("TEMP")) && *s) || ((s = getenv ("TMPDIR")) && *s))
  519.     strcpy (lock,s);
  520.   else sprintf (lock,"%s\\TEMP\\",defaultDrive ());
  521.   if ((s = lock + strlen (lock))[-1] != '\\') *s++ ='\\';
  522.   while (c = *fname++) switch (c) {
  523.   case '/':
  524.   case '\\':
  525.   case ':':
  526.     *s++ = '!';
  527.     break;
  528.   default:
  529.     *s++ = c;
  530.     break;
  531.   }
  532.   *s++ = c;
  533.                 /* get the lock */
  534.   if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
  535.     flock (ld,op);        /* apply locking function */
  536.   return ld;            /* return locking file descriptor */
  537. }
  538.  
  539.  
  540. /* Unlock file descriptor
  541.  * Accepts: file descriptor
  542.  *        lock file name from lockfd()
  543.  */
  544.  
  545. void unlockfd (int fd,char *lock)
  546. {
  547.   flock (fd,LOCK_UN);        /* unlock it */
  548.   close (fd);            /* close it */
  549. }
  550.  
  551.  
  552. /* Determine default prototype stream to user
  553.  * Accepts: type (NIL for create, T for append)
  554.  * Returns: default prototype stream
  555.  */
  556.  
  557. MAILSTREAM *default_proto (long type)
  558. {
  559.   extern MAILSTREAM DEFAULTPROTO;
  560.   return &DEFAULTPROTO;        /* return default driver's prototype */
  561. }
  562.