imapext-2007

diff src/osdep/nt/env_nt.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/osdep/nt/env_nt.c	Mon Sep 14 15:17:45 2009 +0900
     1.3 @@ -0,0 +1,774 @@
     1.4 +/* ========================================================================
     1.5 + * Copyright 1988-2008 University of Washington
     1.6 + *
     1.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.8 + * you may not use this file except in compliance with the License.
     1.9 + * You may obtain a copy of the License at
    1.10 + *
    1.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.12 + *
    1.13 + * 
    1.14 + * ========================================================================
    1.15 + */
    1.16 +
    1.17 +/*
    1.18 + * Program:	NT environment routines
    1.19 + *
    1.20 + * Author:	Mark Crispin
    1.21 + *		UW Technology
    1.22 + *		University of Washington
    1.23 + *		Seattle, WA  98195
    1.24 + *		Internet: MRC@Washington.EDU
    1.25 + *
    1.26 + * Date:	1 August 1988
    1.27 + * Last Edited:	15 February 2008
    1.28 + */
    1.29 +
    1.30 +static char *myUserName = NIL;	/* user name */
    1.31 +static char *myLocalHost = NIL;	/* local host name */
    1.32 +static char *myHomeDir = NIL;	/* home directory name */
    1.33 +static char *myNewsrc = NIL;	/* newsrc file name */
    1.34 +static char *sysInbox = NIL;	/* system inbox name */
    1.35 +static long list_max_level = 5;	/* maximum level of list recursion */
    1.36 +				/* block environment init */
    1.37 +static short block_env_init = NIL;
    1.38 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
    1.39 +				/* home namespace */
    1.40 +static NAMESPACE nshome = {"",'\\',NIL,NIL};
    1.41 +				/* UNIX other user namespace */
    1.42 +static NAMESPACE nsother = {"#user.",'\\',NIL,NIL};
    1.43 +				/* namespace list */
    1.44 +static NAMESPACE *nslist[3] = {&nshome,&nsother,NIL};
    1.45 +static long alarm_countdown = 0;/* alarm count down */
    1.46 +static void (*alarm_rang) ();	/* alarm interrupt function */
    1.47 +static unsigned int rndm = 0;	/* initial `random' number */
    1.48 +static int server_nli = 0;	/* server and not logged in */
    1.49 +static int logtry = 3;		/* number of login tries */
    1.50 +				/* block notification */
    1.51 +static blocknotify_t mailblocknotify = mm_blocknotify;
    1.52 +				/* callback to get username */
    1.53 +static userprompt_t mailusername = NIL;
    1.54 +static long is_nt = -1;		/* T if NT, NIL if not NT, -1 unknown */
    1.55 +static HINSTANCE netapi = NIL;
    1.56 +typedef NET_API_STATUS (CALLBACK *GETINFO) (LPCWSTR,LPCWSTR,DWORD,LPBYTE *);
    1.57 +static GETINFO getinfo = NIL;
    1.58 +
    1.59 +#include "write.c"		/* include safe writing routines */
    1.60 +#include "pmatch.c"		/* include wildcard pattern matcher */
    1.61 +
    1.62 +
    1.63 +/* Get all authenticators */
    1.64 +
    1.65 +#include "auths.c"
    1.66 +
    1.67 +/* Environment manipulate parameters
    1.68 + * Accepts: function code
    1.69 + *	    function-dependent value
    1.70 + * Returns: function-dependent return value
    1.71 + */
    1.72 +
    1.73 +void *env_parameters (long function,void *value)
    1.74 +{
    1.75 +  void *ret = NIL;
    1.76 +  switch ((int) function) {
    1.77 +  case GET_NAMESPACE:
    1.78 +    ret = (void *) nslist;
    1.79 +    break;
    1.80 +  case SET_USERPROMPT :
    1.81 +    mailusername = (userprompt_t) value;
    1.82 +  case GET_USERPROMPT :
    1.83 +    ret = (void *) mailusername;
    1.84 +    break;
    1.85 +  case SET_HOMEDIR:
    1.86 +    if (myHomeDir) fs_give ((void **) &myHomeDir);
    1.87 +    myHomeDir = cpystr ((char *) value);
    1.88 +  case GET_HOMEDIR:
    1.89 +    ret = (void *) myHomeDir;
    1.90 +    break;
    1.91 +  case SET_LOCALHOST:
    1.92 +    myLocalHost = cpystr ((char *) value);
    1.93 +  case GET_LOCALHOST:
    1.94 +    if (myLocalHost) fs_give ((void **) &myLocalHost);
    1.95 +    ret = (void *) myLocalHost;
    1.96 +    break;
    1.97 +  case SET_NEWSRC:
    1.98 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
    1.99 +    myNewsrc = cpystr ((char *) value);
   1.100 +  case GET_NEWSRC:
   1.101 +    if (!myNewsrc) {		/* set news file name if not defined */
   1.102 +      char tmp[MAILTMPLEN];
   1.103 +      sprintf (tmp,"%s\\NEWSRC",myhomedir ());
   1.104 +      myNewsrc = cpystr (tmp);
   1.105 +    }
   1.106 +    ret = (void *) myNewsrc;
   1.107 +    break;
   1.108 +  case SET_SYSINBOX:
   1.109 +    if (sysInbox) fs_give ((void **) &sysInbox);
   1.110 +    sysInbox = cpystr ((char *) value);
   1.111 +  case GET_SYSINBOX:
   1.112 +    ret = (void *) sysInbox;
   1.113 +    break;
   1.114 +  case SET_LISTMAXLEVEL:
   1.115 +    list_max_level = (long) value;
   1.116 +  case GET_LISTMAXLEVEL:
   1.117 +    ret = (void *) list_max_level;
   1.118 +    break;
   1.119 +  case SET_DISABLE822TZTEXT:
   1.120 +    no822tztext = value ? T : NIL;
   1.121 +  case GET_DISABLE822TZTEXT:
   1.122 +    ret = (void *) (no822tztext ? VOIDT : NIL);
   1.123 +    break;
   1.124 +  case SET_BLOCKENVINIT:
   1.125 +    block_env_init = value ? T : NIL;
   1.126 +  case GET_BLOCKENVINIT:
   1.127 +    ret = (void *) (block_env_init ? VOIDT : NIL);
   1.128 +    break;
   1.129 +  case SET_BLOCKNOTIFY:
   1.130 +    mailblocknotify = (blocknotify_t) value;
   1.131 +  case GET_BLOCKNOTIFY:
   1.132 +    ret = (void *) mailblocknotify;
   1.133 +    break;
   1.134 +  }
   1.135 +  return ret;
   1.136 +}
   1.137 +
   1.138 +/* Write current time
   1.139 + * Accepts: destination string
   1.140 + *	    optional format of day-of-week prefix
   1.141 + *	    format of date and time
   1.142 + *	    flag whether to append symbolic timezone
   1.143 + */
   1.144 +
   1.145 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
   1.146 +{
   1.147 +  time_t tn = time (0);
   1.148 +  struct tm *t = gmtime (&tn);
   1.149 +  int zone = t->tm_hour * 60 + t->tm_min;
   1.150 +  int julian = t->tm_yday;
   1.151 +  t = localtime (&tn);		/* get local time now */
   1.152 +				/* minus UTC minutes since midnight */
   1.153 +  zone = t->tm_hour * 60 + t->tm_min - zone;
   1.154 +  /* julian can be one of:
   1.155 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
   1.156 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
   1.157 +   *    0  local time is same day as UTC, no offset
   1.158 +   *   -1  local time is 1 day behind UTC, offset -24 hours
   1.159 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
   1.160 +   */
   1.161 +  if (julian = t->tm_yday -julian)
   1.162 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
   1.163 +  if (prefix) {			/* want day of week? */
   1.164 +    sprintf (date,prefix,days[t->tm_wday]);
   1.165 +    date += strlen (date);	/* make next sprintf append */
   1.166 +  }
   1.167 +				/* output the date */
   1.168 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
   1.169 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
   1.170 +  if (suffix) {			/* append timezone suffix if desired */
   1.171 +    char *tz;
   1.172 +    tzset ();			/* get timezone from TZ environment stuff */
   1.173 +    tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
   1.174 +    if (tz && tz[0]) {
   1.175 +      char *s;
   1.176 +      for (s = tz; *s; s++) if (*s & 0x80) return;
   1.177 +      sprintf (date + strlen (date)," (%.50s)",tz);
   1.178 +    }
   1.179 +  }
   1.180 +}
   1.181 +
   1.182 +
   1.183 +/* Write current time in RFC 822 format
   1.184 + * Accepts: destination string
   1.185 + */
   1.186 +
   1.187 +void rfc822_date (char *date)
   1.188 +{
   1.189 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
   1.190 +	   no822tztext ? NIL : T);
   1.191 +}
   1.192 +
   1.193 +
   1.194 +/* Write current time in fixed-width RFC 822 format
   1.195 + * Accepts: destination string
   1.196 + */
   1.197 +
   1.198 +void rfc822_fixed_date (char *date)
   1.199 +{
   1.200 +  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
   1.201 +}
   1.202 +
   1.203 +
   1.204 +/* Write current time in internal format
   1.205 + * Accepts: destination string
   1.206 + */
   1.207 +
   1.208 +void internal_date (char *date)
   1.209 +{
   1.210 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
   1.211 +}
   1.212 +
   1.213 +/* Return random number
   1.214 + */
   1.215 +
   1.216 +long random (void)
   1.217 +{
   1.218 +  if (!rndm) srand (rndm = (unsigned) time (0L));
   1.219 +  return (long) rand ();
   1.220 +}
   1.221 +
   1.222 +
   1.223 +/* Set alarm timer
   1.224 + * Accepts: new value
   1.225 + * Returns: old alarm value
   1.226 + */
   1.227 +
   1.228 +long alarm (long seconds)
   1.229 +{
   1.230 +  long ret = alarm_countdown;
   1.231 +  alarm_countdown = seconds;
   1.232 +  return ret;
   1.233 +}
   1.234 +
   1.235 +
   1.236 +/* The clock ticked
   1.237 + */
   1.238 +
   1.239 +void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser,
   1.240 +			    DWORD dwReserved1,DWORD dwReserved2)
   1.241 +{
   1.242 +  if (alarm_rang && !--alarm_countdown) (*alarm_rang) ();
   1.243 +}
   1.244 +
   1.245 +/* Initialize server
   1.246 + * Accepts: server name for syslog or NIL
   1.247 + *	    /etc/services service name or NIL
   1.248 + *	    alternate /etc/services service name or NIL
   1.249 + *	    clock interrupt handler
   1.250 + *	    kiss-of-death interrupt handler
   1.251 + *	    hangup interrupt handler
   1.252 + *	    termination interrupt handler
   1.253 + */
   1.254 +
   1.255 +void server_init (char *server,char *service,char *sslservice,
   1.256 +		  void *clkint,void *kodint,void *hupint,void *trmint,
   1.257 +		  void *staint)
   1.258 +{
   1.259 +  if (!check_nt ()) {
   1.260 +    if (!auth_md5.server) fatal ("Can't run on Windows without MD5 database");
   1.261 +    server_nli = T;		/* Windows server not logged in */
   1.262 +  }
   1.263 +				/* only do this if for init call */
   1.264 +  if (server && service && sslservice) {
   1.265 +    long port;
   1.266 +    struct servent *sv;
   1.267 +				/* set server name in syslog */
   1.268 +    openlog (server,LOG_PID,LOG_MAIL);
   1.269 +    fclose (stderr);		/* possibly save a process ID */
   1.270 +    /* Use SSL if SSL service, or if server starts with "s" and not service */
   1.271 +    if (((port = tcp_serverport ()) >= 0)) {
   1.272 +      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
   1.273 +	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
   1.274 +      else if ((sv = getservbyname (sslservice,"tcp")) &&
   1.275 +	       (port == ntohs (sv->s_port))) {
   1.276 +	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
   1.277 +		tcp_clientaddr ());
   1.278 +	ssl_server_init (server);
   1.279 +      }
   1.280 +      else {			/* not service or SSL service port */
   1.281 +	syslog (LOG_DEBUG,"port %ld service init from %s",port,
   1.282 +		tcp_clientaddr ());
   1.283 +	if (*server == 's') ssl_server_init (server);
   1.284 +      }
   1.285 +    }
   1.286 +				/* make sure stdout does binary */
   1.287 +    setmode (fileno (stdin),O_BINARY);
   1.288 +    setmode (fileno (stdout),O_BINARY);
   1.289 +  }
   1.290 +  alarm_rang = clkint;		/* note the clock interrupt */
   1.291 +  timeBeginPeriod (1000);	/* set the timer interval */
   1.292 +  timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC);
   1.293 +}
   1.294 +
   1.295 +
   1.296 +/* Wait for stdin input
   1.297 + * Accepts: timeout in seconds
   1.298 + * Returns: T if have input on stdin, else NIL
   1.299 + */
   1.300 +
   1.301 +long server_input_wait (long seconds)
   1.302 +{
   1.303 +  fd_set rfd,efd;
   1.304 +  struct timeval tmo;
   1.305 +  FD_ZERO (&rfd);
   1.306 +  FD_ZERO (&efd);
   1.307 +  FD_SET (0,&rfd);
   1.308 +  FD_SET (0,&efd);
   1.309 +  tmo.tv_sec = seconds; tmo.tv_usec = 0;
   1.310 +  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
   1.311 +}
   1.312 +
   1.313 +/* Server log in
   1.314 + * Accepts: user name string
   1.315 + *	    password string
   1.316 + *	    authenticating user name string
   1.317 + *	    argument count
   1.318 + *	    argument vector
   1.319 + * Returns: T if password validated, NIL otherwise
   1.320 + */
   1.321 +
   1.322 +static int gotprivs = NIL;	/* once-only flag to grab privileges */
   1.323 +
   1.324 +long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
   1.325 +{
   1.326 +  HANDLE hdl;
   1.327 +  LUID tcbpriv;
   1.328 +  TOKEN_PRIVILEGES tkp;
   1.329 +  char *s;
   1.330 +				/* need to get privileges? */
   1.331 +  if (!gotprivs++ && check_nt ()) {
   1.332 +				/* hack for inetlisn */
   1.333 +    if (argc >= 2) myClientHost = argv[1];
   1.334 +				/* get process token and TCB priv value */
   1.335 +    if (!(OpenProcessToken (GetCurrentProcess (),
   1.336 +			    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) &&
   1.337 +	  LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv)))
   1.338 +      return NIL;
   1.339 +    tkp.PrivilegeCount = 1;	/* want to enable this privilege */
   1.340 +    tkp.Privileges[0].Luid = tcbpriv;
   1.341 +    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
   1.342 +				/* enable it */
   1.343 +    AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES),
   1.344 +			   (PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL);
   1.345 +				/* make sure it won */
   1.346 +    if (GetLastError() != ERROR_SUCCESS) return NIL;
   1.347 +  }
   1.348 +
   1.349 +				/* cretins still haven't given up */
   1.350 +  if ((strlen (user) >= MAILTMPLEN) ||
   1.351 +      (authuser && (strlen (authuser) >= MAILTMPLEN)))
   1.352 +    syslog (LOG_ALERT,"SYSTEM BREAK-IN ATTEMPT, host=%.80s",tcp_clienthost ());
   1.353 +  else if (logtry > 0) {	/* still have available logins? */
   1.354 +				/* authentication user not supported */
   1.355 +    if (authuser && *authuser && compare_cstring (authuser,user))
   1.356 +      mm_log ("Authentication id must match authorization id",ERROR);
   1.357 +    if (check_nt ()) {		/* NT: authserver_login() call not supported */
   1.358 +      if (!pass) mm_log ("Unsupported authentication mechanism",ERROR);
   1.359 +      else if ((		/* try to login and impersonate the guy */
   1.360 +#ifdef LOGIN32_LOGON_NETWORK
   1.361 +		LogonUser (user,".",pass,LOGON32_LOGON_NETWORK,
   1.362 +			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
   1.363 +#endif
   1.364 +		LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE,
   1.365 +			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
   1.366 +		LogonUser (user,".",pass,LOGON32_LOGON_BATCH,
   1.367 +			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
   1.368 +		LogonUser (user,".",pass,LOGON32_LOGON_SERVICE,
   1.369 +			   LOGON32_PROVIDER_DEFAULT,&hdl)) &&
   1.370 +	       ImpersonateLoggedOnUser (hdl)) return env_init (user,NIL);
   1.371 +    }
   1.372 +    else {			/* Win9x: done if from authserver_login() */
   1.373 +      if (!pass) server_nli = NIL;
   1.374 +				/* otherwise check MD5 database */
   1.375 +      else if (s = auth_md5_pwd (user)) {
   1.376 +				/* change NLI state based on pwd match */
   1.377 +	server_nli = strcmp (s,pass);
   1.378 +	memset (s,0,strlen (s));/* erase sensitive information */
   1.379 +	fs_give ((void **) &s);	/* flush erased password */
   1.380 +      }
   1.381 +				/* success if no longer NLI */
   1.382 +      if (!server_nli) return env_init (user,NIL);
   1.383 +    }
   1.384 +  }
   1.385 +  s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
   1.386 +				/* note the failure in the syslog */
   1.387 +  syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
   1.388 +  sleep (3);			/* slow down possible cracker */
   1.389 +  return NIL;
   1.390 +}
   1.391 +
   1.392 +/* Authenticated server log in
   1.393 + * Accepts: user name string
   1.394 + *	    authentication user name string
   1.395 + *	    argument count
   1.396 + *	    argument vector
   1.397 + * Returns: T if password validated, NIL otherwise
   1.398 + */
   1.399 +
   1.400 +long authserver_login (char *user,char *authuser,int argc,char *argv[])
   1.401 +{
   1.402 +  return server_login (user,NIL,authuser,argc,argv);
   1.403 +}
   1.404 +
   1.405 +
   1.406 +/* Log in as anonymous daemon
   1.407 + * Accepts: argument count
   1.408 + *	    argument vector
   1.409 + * Returns: T if successful, NIL if error
   1.410 + */
   1.411 +
   1.412 +long anonymous_login (int argc,char *argv[])
   1.413 +{
   1.414 +  return server_login ("Guest",NIL,NIL,argc,argv);
   1.415 +}
   1.416 +
   1.417 +
   1.418 +/* Initialize environment
   1.419 + * Accepts: user name
   1.420 + *          home directory, or NIL to use default
   1.421 + * Returns: T, always
   1.422 + */
   1.423 +
   1.424 +long env_init (char *user,char *home)
   1.425 +{
   1.426 +				/* don't init if blocked */
   1.427 +  if (block_env_init) return LONGT;
   1.428 +  if (myUserName) fatal ("env_init called twice!");
   1.429 +  myUserName = cpystr (user);	/* remember user name */
   1.430 +  if (!myHomeDir)		/* only if home directory not set up yet */
   1.431 +    myHomeDir = (home && *home) ? cpystr (home) : win_homedir (user);
   1.432 +  return T;
   1.433 +}
   1.434 +
   1.435 +/* Check if NT
   1.436 + * Returns: T if NT, NIL if Win9x
   1.437 + */
   1.438 +
   1.439 +int check_nt (void)
   1.440 +{
   1.441 +  if (is_nt < 0) {		/* not yet set up? */
   1.442 +    OSVERSIONINFO ver;
   1.443 +    ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
   1.444 +    GetVersionEx (&ver);
   1.445 +    is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL;
   1.446 +  }
   1.447 +  return is_nt;
   1.448 +}
   1.449 +
   1.450 +
   1.451 +/* Return Windows home directory
   1.452 + * Accepts: user name
   1.453 + * Returns: home directory
   1.454 + */
   1.455 +
   1.456 +char *win_homedir (char *user)
   1.457 +{
   1.458 +  char *s,*t,tmp[MAILTMPLEN];
   1.459 +  PUSER_INFO_1 ui;
   1.460 +				/* Win9x default */
   1.461 +  if (!check_nt ()) sprintf (tmp,"%s\\My Documents",defaultDrive ());
   1.462 +				/* get from user info on NT */
   1.463 +  else if ((netapi || (netapi = LoadLibrary ("netapi32.dll"))) &&
   1.464 +	   (getinfo ||
   1.465 +	    (getinfo = (GETINFO) GetProcAddress (netapi,"NetUserGetInfo"))) &&
   1.466 +	   MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1,
   1.467 +				(WCHAR *) tmp,MAILTMPLEN) &&
   1.468 +	   !(*getinfo) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) &&
   1.469 +	   WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1,
   1.470 +				tmp,MAILTMPLEN,NIL,NIL) && tmp[0]) {
   1.471 +				/* make sure doesn't end with delimiter */
   1.472 +    if ((*(s = tmp + strlen (tmp) - 1) == '\\') || (*s == '/')) *s = '\0';
   1.473 +  }
   1.474 +				/* no home dir, found Win2K user profile? */
   1.475 +  else if ((s = getenv ("USERPROFILE")) && (t = strrchr (s,'\\'))) {      
   1.476 +    strncpy (tmp,s,t-s);	/* copy up to user name */
   1.477 +    sprintf (tmp+(t-s),"\\%.100s\\My Documents",user);
   1.478 +  }
   1.479 +				/* last resort NT default */
   1.480 +  else sprintf (tmp,"%s\\users\\default",defaultDrive ());
   1.481 +  return cpystr (tmp);
   1.482 +}
   1.483 +
   1.484 +
   1.485 +/* Return default drive
   1.486 + * Returns: default drive
   1.487 + */
   1.488 +
   1.489 +static char *defaultDrive (void)
   1.490 +{
   1.491 +  char *s = getenv ("SystemDrive");
   1.492 +  return (s && *s) ? s : "C:";
   1.493 +}
   1.494 +
   1.495 +/* Return my user name
   1.496 + * Accepts: pointer to optional flags
   1.497 + * Returns: my user name
   1.498 + */
   1.499 +
   1.500 +char *myusername_full (unsigned long *flags)
   1.501 +{
   1.502 +  UCHAR usr[MAILTMPLEN];
   1.503 +  DWORD len = MAILTMPLEN;
   1.504 +  char *user,*path,*d,*p,pth[MAILTMPLEN];
   1.505 +  char *ret = "SYSTEM";
   1.506 +				/* get user name if don't have it yet */
   1.507 +  if (!myUserName && !server_nli &&
   1.508 +				/* use callback, else logon name */
   1.509 +      ((mailusername && (user = (char *) (*mailusername) ())) ||
   1.510 +       (GetUserName (usr,&len) && _stricmp (user = (char *) usr,"SYSTEM")))) {
   1.511 +    if (block_env_init) {	/* don't env_init if blocked */
   1.512 +      if (flags) *flags = MU_LOGGEDIN;
   1.513 +      return user;
   1.514 +    }
   1.515 +				/* try HOMEPATH, then HOME */
   1.516 +    if (p = getenv ("HOMEPATH"))
   1.517 +      sprintf (path = pth,"%s%s",
   1.518 +	       (d = getenv ("HOMEDRIVE")) ? d : defaultDrive (),p);
   1.519 +    else if (!(path = getenv ("HOME")))
   1.520 +      sprintf (path = pth,"%s\\My Documents",defaultDrive ());
   1.521 +				/* make sure doesn't end with delimiter */
   1.522 +    if ((*(p = path + strlen (path) -1) == '\\') || (*p == '/')) *p = '\0';
   1.523 +    env_init (user,path);	/* initialize environment */
   1.524 +  }
   1.525 +  if (myUserName) {		/* logged in? */
   1.526 +    if (flags)			/* Guest is an anonymous user */
   1.527 +      *flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS;
   1.528 +    ret = myUserName;		/* return user name */
   1.529 +  }
   1.530 +  else if (flags) *flags = MU_NOTLOGGEDIN;
   1.531 +  return ret;
   1.532 +}
   1.533 +
   1.534 +/* Return my local host name
   1.535 + * Returns: my local host name
   1.536 + */
   1.537 +
   1.538 +char *mylocalhost (void)
   1.539 +{
   1.540 +  if (!myLocalHost) {
   1.541 +    char tmp[MAILTMPLEN];
   1.542 +    if (!wsa_initted++) {	/* init Windows Sockets */
   1.543 +      WSADATA wsock;
   1.544 +      if (WSAStartup (WINSOCK_VERSION,&wsock)) {
   1.545 +	wsa_initted = 0;
   1.546 +	return "random-pc";	/* try again later? */
   1.547 +      }
   1.548 +    }
   1.549 +    myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
   1.550 +			  "random-pc" : tcp_canonical (tmp));
   1.551 +  }
   1.552 +  return myLocalHost;
   1.553 +}
   1.554 +
   1.555 +/* Return my home directory name
   1.556 + * Returns: my home directory name
   1.557 + */
   1.558 +
   1.559 +char *myhomedir ()
   1.560 +{
   1.561 +  if (!myHomeDir) myusername ();/* initialize if first time */
   1.562 +  return myHomeDir ? myHomeDir : "";
   1.563 +}
   1.564 +
   1.565 +
   1.566 +/* Return system standard INBOX
   1.567 + * Accepts: buffer string
   1.568 + */
   1.569 +
   1.570 +char *sysinbox ()
   1.571 +{
   1.572 +  char tmp[MAILTMPLEN];
   1.573 +  if (!sysInbox) {		/* initialize if first time */
   1.574 +    if (check_nt ()) sprintf (tmp,MAILFILE,myUserName);
   1.575 +    else sprintf (tmp,"%s\\INBOX",myhomedir ());
   1.576 +    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
   1.577 +  }
   1.578 +  return sysInbox;
   1.579 +}
   1.580 +
   1.581 +
   1.582 +/* Return mailbox directory name
   1.583 + * Accepts: destination buffer
   1.584 + *	    directory prefix
   1.585 + *	    name in directory
   1.586 + * Returns: file name or NIL if error
   1.587 + */
   1.588 +
   1.589 +char *mailboxdir (char *dst,char *dir,char *name)
   1.590 +{
   1.591 +  char tmp[MAILTMPLEN];
   1.592 +  if (dir || name) {		/* if either argument provided */
   1.593 +    if (dir) {
   1.594 +      if (strlen (dir) > NETMAXMBX) return NIL;
   1.595 +      strcpy (tmp,dir);		/* write directory prefix */
   1.596 +    }
   1.597 +    else tmp[0] = '\0';		/* otherwise null string */
   1.598 +    if (name) {
   1.599 +      if (strlen (name) > NETMAXMBX) return NIL;
   1.600 +      strcat (tmp,name);	/* write name in directory */
   1.601 +    }
   1.602 +				/* validate name, return its name */
   1.603 +    if (!mailboxfile (dst,tmp)) return NIL;
   1.604 +  }
   1.605 +  else strcpy (dst,myhomedir());/* no arguments, wants home directory */
   1.606 +  return dst;			/* return the name */
   1.607 +}
   1.608 +
   1.609 +/* Return mailbox file name
   1.610 + * Accepts: destination buffer
   1.611 + *	    mailbox name
   1.612 + * Returns: file name or empty string for driver-selected INBOX or NIL if error
   1.613 + */
   1.614 +
   1.615 +char *mailboxfile (char *dst,char *name)
   1.616 +{
   1.617 +  char homedev[3];
   1.618 +  char *dir = myhomedir ();
   1.619 +  if (dir[0] && isalpha (dir[0]) && (dir[1] == ':')) {
   1.620 +    homedev[0] = dir[0];	/* copy home device */
   1.621 +    homedev[1] = dir[1];
   1.622 +    homedev[2] = '\0';
   1.623 +  }
   1.624 +  else homedev[0] = '\0';	/* ??no home device?? */
   1.625 +  *dst = '\0';			/* default to empty string */
   1.626 +				/* check for INBOX */
   1.627 +  if (!compare_cstring (name,"INBOX"));
   1.628 +				/* reject names with / */
   1.629 +  else if (strchr (name,'/')) dst = NIL;
   1.630 +  else switch (*name) {
   1.631 +  case '#':			/* namespace names */
   1.632 +    if (((name[1] == 'u') || (name[1] == 'U')) &&
   1.633 +	((name[2] == 's') || (name[2] == 'S')) &&
   1.634 +	((name[3] == 'e') || (name[3] == 'E')) &&
   1.635 +	((name[4] == 'r') || (name[4] == 'R')) && (name[5] == '.')) {
   1.636 +				/* copy user name to destination buffer */
   1.637 +      for (dir = dst,name += 6; *name && (*name != '\\'); *dir++ = *name++);
   1.638 +      *dir++ = '\0';		/* tie off user name */
   1.639 +				/* look up homedir for user name */
   1.640 +      if (dir = win_homedir (dst)) {
   1.641 +				/* build resulting name */
   1.642 +	sprintf (dst,"%s\\%s",dir,name);
   1.643 +	fs_give ((void **) &dir);
   1.644 +      }
   1.645 +      else dst = NIL;
   1.646 +    }
   1.647 +    else dst = NIL;		/* unknown namespace name */
   1.648 +    break;
   1.649 +  case '\\':			/* absolute path on default drive? */
   1.650 +    sprintf (dst,"%s%s",homedev,name);
   1.651 +    break;
   1.652 +  default:			/* any other name */
   1.653 +    if (name[1] == ':') {	/* some other drive? */
   1.654 +      if (name[2] == '\\') strcpy (dst,name);
   1.655 +      else sprintf (dst,"%c:\\%s",name[0],name+2);
   1.656 +    }
   1.657 +				/* build home-directory relative name */
   1.658 +    else sprintf (dst,"%s\\%s",dir,name);
   1.659 +  }
   1.660 +  return dst;			/* return it */
   1.661 +}
   1.662 +
   1.663 +/* Lock file name
   1.664 + * Accepts: return buffer for file name
   1.665 + *	    file name
   1.666 + *	    locking to be placed on file if non-NIL
   1.667 + * Returns: file descriptor of lock or -1 if error
   1.668 + */
   1.669 +
   1.670 +int lockname (char *lock,char *fname,int op)
   1.671 +{
   1.672 +  int ld;
   1.673 +  char c,*s;
   1.674 +				/* Win2K and Win98 have TEMP under windir */
   1.675 +  if (!((s = lockdir (lock,getenv ("windir"),"TEMP")) ||
   1.676 +				/* NT4, NT3.x and Win95 use one of these */
   1.677 +	(s = lockdir (lock,getenv ("TEMP"),NIL)) ||
   1.678 +	(s = lockdir (lock,getenv ("TMP"),NIL)) ||
   1.679 +	(s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
   1.680 +				/* try one of these */
   1.681 +	(s = lockdir (lock,defaultDrive (),"WINNT\\TEMP")) ||
   1.682 +	(s = lockdir (lock,defaultDrive (),"WINDOWS\\TEMP")) ||
   1.683 +				/* C:\TEMP is last resort */
   1.684 +	(s = lockdir (lock,defaultDrive (),"TEMP")))) {
   1.685 +    mm_log ("Unable to find temporary directory",ERROR);
   1.686 +    return -1;
   1.687 +  }
   1.688 +				/* generate file name */
   1.689 +  while (c = *fname++) switch (c) {
   1.690 +  case '/': case '\\': case ':':
   1.691 +    *s++ = '!';			/* convert bad chars to ! */
   1.692 +    break;
   1.693 +  default:
   1.694 +    *s++ = c;
   1.695 +    break;
   1.696 +  }
   1.697 +  *s++ = c;			/* tie off name */
   1.698 +				/* get the lock */
   1.699 +  if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
   1.700 +    flock (ld,op);		/* apply locking function */
   1.701 +  return ld;			/* return locking file descriptor */
   1.702 +}
   1.703 +
   1.704 +/* Build lock directory, check to see if it exists
   1.705 + * Accepts: return buffer for lock directory
   1.706 + *	    first part of possible name
   1.707 + *	    optional second part
   1.708 + * Returns: pointer to end of buffer if buffer has a good name, else NIL
   1.709 + */
   1.710 +
   1.711 +char *lockdir (char *lock,char *first,char *last)
   1.712 +{
   1.713 +  struct stat sbuf;
   1.714 +  char c,*s;
   1.715 +  if (first && *first) {	/* first part must be non-NIL */
   1.716 +				/* copy first part */
   1.717 +    for (s = lock; c = *first++; *s++ = (c == '/') ? '\\' : c);
   1.718 +    if (last && *last) {	/* copy last part if specified */
   1.719 +				/* write trailing \ in case not in first */
   1.720 +      if (s[-1] != '\\') *s++ = '\\';
   1.721 +      while (c = *last++) *s++ = (c == '/') ? '\\' : c;
   1.722 +    }
   1.723 +    if (s[-1] == '\\') --s;	/* delete trailing \ if any */
   1.724 +    *s = s[1] = '\0';		/* tie off name at this point */
   1.725 +    if (!stat (lock,&sbuf)) {	/* does the name exist? */
   1.726 +      *s++ = '\\';		/* yes, reinstall trailing \ */
   1.727 +      return s;			/* return the name */
   1.728 +    }
   1.729 +  }
   1.730 +  return NIL;			/* failed */
   1.731 +}
   1.732 +
   1.733 +
   1.734 +/* Unlock file descriptor
   1.735 + * Accepts: file descriptor
   1.736 + *	    lock file name from lockfd()
   1.737 + */
   1.738 +
   1.739 +void unlockfd (int fd,char *lock)
   1.740 +{
   1.741 +  flock (fd,LOCK_UN);		/* unlock it */
   1.742 +  close (fd);			/* close it */
   1.743 +}
   1.744 +
   1.745 +
   1.746 +/* Determine default prototype stream to user
   1.747 + * Accepts: type (NIL for create, T for append)
   1.748 + * Returns: default prototype stream
   1.749 + */
   1.750 +
   1.751 +MAILSTREAM *default_proto (long type)
   1.752 +{
   1.753 +  extern MAILSTREAM CREATEPROTO,APPENDPROTO;
   1.754 +  return type ? &APPENDPROTO : &CREATEPROTO;
   1.755 +}
   1.756 +
   1.757 +/* Default block notify routine
   1.758 + * Accepts: reason for calling
   1.759 + *	    data
   1.760 + * Returns: data
   1.761 + */
   1.762 +
   1.763 +void *mm_blocknotify (int reason,void *data)
   1.764 +{
   1.765 +  void *ret = data;
   1.766 +  switch (reason) {
   1.767 +  case BLOCK_SENSITIVE:		/* entering sensitive code */
   1.768 +    ret = (void *) alarm (0);
   1.769 +    break;
   1.770 +  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
   1.771 +    if ((unsigned int) data) alarm ((unsigned int) data);
   1.772 +    break;
   1.773 +  default:			/* ignore all other reasons */
   1.774 +    break;
   1.775 +  }
   1.776 +  return ret;
   1.777 +}

UW-IMAP'd extensions by yuuji