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

网络编程

开发平台:

Unix_Linux

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