imapext-2007

annotate 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
rev   line source
yuuji@0 1 /* ========================================================================
yuuji@0 2 * Copyright 1988-2008 University of Washington
yuuji@0 3 *
yuuji@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
yuuji@0 5 * you may not use this file except in compliance with the License.
yuuji@0 6 * You may obtain a copy of the License at
yuuji@0 7 *
yuuji@0 8 * http://www.apache.org/licenses/LICENSE-2.0
yuuji@0 9 *
yuuji@0 10 *
yuuji@0 11 * ========================================================================
yuuji@0 12 */
yuuji@0 13
yuuji@0 14 /*
yuuji@0 15 * Program: NT environment routines
yuuji@0 16 *
yuuji@0 17 * Author: Mark Crispin
yuuji@0 18 * UW Technology
yuuji@0 19 * University of Washington
yuuji@0 20 * Seattle, WA 98195
yuuji@0 21 * Internet: MRC@Washington.EDU
yuuji@0 22 *
yuuji@0 23 * Date: 1 August 1988
yuuji@0 24 * Last Edited: 15 February 2008
yuuji@0 25 */
yuuji@0 26
yuuji@0 27 static char *myUserName = NIL; /* user name */
yuuji@0 28 static char *myLocalHost = NIL; /* local host name */
yuuji@0 29 static char *myHomeDir = NIL; /* home directory name */
yuuji@0 30 static char *myNewsrc = NIL; /* newsrc file name */
yuuji@0 31 static char *sysInbox = NIL; /* system inbox name */
yuuji@0 32 static long list_max_level = 5; /* maximum level of list recursion */
yuuji@0 33 /* block environment init */
yuuji@0 34 static short block_env_init = NIL;
yuuji@0 35 static short no822tztext = NIL; /* disable RFC [2]822 timezone text */
yuuji@0 36 /* home namespace */
yuuji@0 37 static NAMESPACE nshome = {"",'\\',NIL,NIL};
yuuji@0 38 /* UNIX other user namespace */
yuuji@0 39 static NAMESPACE nsother = {"#user.",'\\',NIL,NIL};
yuuji@0 40 /* namespace list */
yuuji@0 41 static NAMESPACE *nslist[3] = {&nshome,&nsother,NIL};
yuuji@0 42 static long alarm_countdown = 0;/* alarm count down */
yuuji@0 43 static void (*alarm_rang) (); /* alarm interrupt function */
yuuji@0 44 static unsigned int rndm = 0; /* initial `random' number */
yuuji@0 45 static int server_nli = 0; /* server and not logged in */
yuuji@0 46 static int logtry = 3; /* number of login tries */
yuuji@0 47 /* block notification */
yuuji@0 48 static blocknotify_t mailblocknotify = mm_blocknotify;
yuuji@0 49 /* callback to get username */
yuuji@0 50 static userprompt_t mailusername = NIL;
yuuji@0 51 static long is_nt = -1; /* T if NT, NIL if not NT, -1 unknown */
yuuji@0 52 static HINSTANCE netapi = NIL;
yuuji@0 53 typedef NET_API_STATUS (CALLBACK *GETINFO) (LPCWSTR,LPCWSTR,DWORD,LPBYTE *);
yuuji@0 54 static GETINFO getinfo = NIL;
yuuji@0 55
yuuji@0 56 #include "write.c" /* include safe writing routines */
yuuji@0 57 #include "pmatch.c" /* include wildcard pattern matcher */
yuuji@0 58
yuuji@0 59
yuuji@0 60 /* Get all authenticators */
yuuji@0 61
yuuji@0 62 #include "auths.c"
yuuji@0 63
yuuji@0 64 /* Environment manipulate parameters
yuuji@0 65 * Accepts: function code
yuuji@0 66 * function-dependent value
yuuji@0 67 * Returns: function-dependent return value
yuuji@0 68 */
yuuji@0 69
yuuji@0 70 void *env_parameters (long function,void *value)
yuuji@0 71 {
yuuji@0 72 void *ret = NIL;
yuuji@0 73 switch ((int) function) {
yuuji@0 74 case GET_NAMESPACE:
yuuji@0 75 ret = (void *) nslist;
yuuji@0 76 break;
yuuji@0 77 case SET_USERPROMPT :
yuuji@0 78 mailusername = (userprompt_t) value;
yuuji@0 79 case GET_USERPROMPT :
yuuji@0 80 ret = (void *) mailusername;
yuuji@0 81 break;
yuuji@0 82 case SET_HOMEDIR:
yuuji@0 83 if (myHomeDir) fs_give ((void **) &myHomeDir);
yuuji@0 84 myHomeDir = cpystr ((char *) value);
yuuji@0 85 case GET_HOMEDIR:
yuuji@0 86 ret = (void *) myHomeDir;
yuuji@0 87 break;
yuuji@0 88 case SET_LOCALHOST:
yuuji@0 89 myLocalHost = cpystr ((char *) value);
yuuji@0 90 case GET_LOCALHOST:
yuuji@0 91 if (myLocalHost) fs_give ((void **) &myLocalHost);
yuuji@0 92 ret = (void *) myLocalHost;
yuuji@0 93 break;
yuuji@0 94 case SET_NEWSRC:
yuuji@0 95 if (myNewsrc) fs_give ((void **) &myNewsrc);
yuuji@0 96 myNewsrc = cpystr ((char *) value);
yuuji@0 97 case GET_NEWSRC:
yuuji@0 98 if (!myNewsrc) { /* set news file name if not defined */
yuuji@0 99 char tmp[MAILTMPLEN];
yuuji@0 100 sprintf (tmp,"%s\\NEWSRC",myhomedir ());
yuuji@0 101 myNewsrc = cpystr (tmp);
yuuji@0 102 }
yuuji@0 103 ret = (void *) myNewsrc;
yuuji@0 104 break;
yuuji@0 105 case SET_SYSINBOX:
yuuji@0 106 if (sysInbox) fs_give ((void **) &sysInbox);
yuuji@0 107 sysInbox = cpystr ((char *) value);
yuuji@0 108 case GET_SYSINBOX:
yuuji@0 109 ret = (void *) sysInbox;
yuuji@0 110 break;
yuuji@0 111 case SET_LISTMAXLEVEL:
yuuji@0 112 list_max_level = (long) value;
yuuji@0 113 case GET_LISTMAXLEVEL:
yuuji@0 114 ret = (void *) list_max_level;
yuuji@0 115 break;
yuuji@0 116 case SET_DISABLE822TZTEXT:
yuuji@0 117 no822tztext = value ? T : NIL;
yuuji@0 118 case GET_DISABLE822TZTEXT:
yuuji@0 119 ret = (void *) (no822tztext ? VOIDT : NIL);
yuuji@0 120 break;
yuuji@0 121 case SET_BLOCKENVINIT:
yuuji@0 122 block_env_init = value ? T : NIL;
yuuji@0 123 case GET_BLOCKENVINIT:
yuuji@0 124 ret = (void *) (block_env_init ? VOIDT : NIL);
yuuji@0 125 break;
yuuji@0 126 case SET_BLOCKNOTIFY:
yuuji@0 127 mailblocknotify = (blocknotify_t) value;
yuuji@0 128 case GET_BLOCKNOTIFY:
yuuji@0 129 ret = (void *) mailblocknotify;
yuuji@0 130 break;
yuuji@0 131 }
yuuji@0 132 return ret;
yuuji@0 133 }
yuuji@0 134
yuuji@0 135 /* Write current time
yuuji@0 136 * Accepts: destination string
yuuji@0 137 * optional format of day-of-week prefix
yuuji@0 138 * format of date and time
yuuji@0 139 * flag whether to append symbolic timezone
yuuji@0 140 */
yuuji@0 141
yuuji@0 142 static void do_date (char *date,char *prefix,char *fmt,int suffix)
yuuji@0 143 {
yuuji@0 144 time_t tn = time (0);
yuuji@0 145 struct tm *t = gmtime (&tn);
yuuji@0 146 int zone = t->tm_hour * 60 + t->tm_min;
yuuji@0 147 int julian = t->tm_yday;
yuuji@0 148 t = localtime (&tn); /* get local time now */
yuuji@0 149 /* minus UTC minutes since midnight */
yuuji@0 150 zone = t->tm_hour * 60 + t->tm_min - zone;
yuuji@0 151 /* julian can be one of:
yuuji@0 152 * 36x local time is December 31, UTC is January 1, offset -24 hours
yuuji@0 153 * 1 local time is 1 day ahead of UTC, offset +24 hours
yuuji@0 154 * 0 local time is same day as UTC, no offset
yuuji@0 155 * -1 local time is 1 day behind UTC, offset -24 hours
yuuji@0 156 * -36x local time is January 1, UTC is December 31, offset +24 hours
yuuji@0 157 */
yuuji@0 158 if (julian = t->tm_yday -julian)
yuuji@0 159 zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
yuuji@0 160 if (prefix) { /* want day of week? */
yuuji@0 161 sprintf (date,prefix,days[t->tm_wday]);
yuuji@0 162 date += strlen (date); /* make next sprintf append */
yuuji@0 163 }
yuuji@0 164 /* output the date */
yuuji@0 165 sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
yuuji@0 166 t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
yuuji@0 167 if (suffix) { /* append timezone suffix if desired */
yuuji@0 168 char *tz;
yuuji@0 169 tzset (); /* get timezone from TZ environment stuff */
yuuji@0 170 tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
yuuji@0 171 if (tz && tz[0]) {
yuuji@0 172 char *s;
yuuji@0 173 for (s = tz; *s; s++) if (*s & 0x80) return;
yuuji@0 174 sprintf (date + strlen (date)," (%.50s)",tz);
yuuji@0 175 }
yuuji@0 176 }
yuuji@0 177 }
yuuji@0 178
yuuji@0 179
yuuji@0 180 /* Write current time in RFC 822 format
yuuji@0 181 * Accepts: destination string
yuuji@0 182 */
yuuji@0 183
yuuji@0 184 void rfc822_date (char *date)
yuuji@0 185 {
yuuji@0 186 do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
yuuji@0 187 no822tztext ? NIL : T);
yuuji@0 188 }
yuuji@0 189
yuuji@0 190
yuuji@0 191 /* Write current time in fixed-width RFC 822 format
yuuji@0 192 * Accepts: destination string
yuuji@0 193 */
yuuji@0 194
yuuji@0 195 void rfc822_fixed_date (char *date)
yuuji@0 196 {
yuuji@0 197 do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
yuuji@0 198 }
yuuji@0 199
yuuji@0 200
yuuji@0 201 /* Write current time in internal format
yuuji@0 202 * Accepts: destination string
yuuji@0 203 */
yuuji@0 204
yuuji@0 205 void internal_date (char *date)
yuuji@0 206 {
yuuji@0 207 do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
yuuji@0 208 }
yuuji@0 209
yuuji@0 210 /* Return random number
yuuji@0 211 */
yuuji@0 212
yuuji@0 213 long random (void)
yuuji@0 214 {
yuuji@0 215 if (!rndm) srand (rndm = (unsigned) time (0L));
yuuji@0 216 return (long) rand ();
yuuji@0 217 }
yuuji@0 218
yuuji@0 219
yuuji@0 220 /* Set alarm timer
yuuji@0 221 * Accepts: new value
yuuji@0 222 * Returns: old alarm value
yuuji@0 223 */
yuuji@0 224
yuuji@0 225 long alarm (long seconds)
yuuji@0 226 {
yuuji@0 227 long ret = alarm_countdown;
yuuji@0 228 alarm_countdown = seconds;
yuuji@0 229 return ret;
yuuji@0 230 }
yuuji@0 231
yuuji@0 232
yuuji@0 233 /* The clock ticked
yuuji@0 234 */
yuuji@0 235
yuuji@0 236 void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser,
yuuji@0 237 DWORD dwReserved1,DWORD dwReserved2)
yuuji@0 238 {
yuuji@0 239 if (alarm_rang && !--alarm_countdown) (*alarm_rang) ();
yuuji@0 240 }
yuuji@0 241
yuuji@0 242 /* Initialize server
yuuji@0 243 * Accepts: server name for syslog or NIL
yuuji@0 244 * /etc/services service name or NIL
yuuji@0 245 * alternate /etc/services service name or NIL
yuuji@0 246 * clock interrupt handler
yuuji@0 247 * kiss-of-death interrupt handler
yuuji@0 248 * hangup interrupt handler
yuuji@0 249 * termination interrupt handler
yuuji@0 250 */
yuuji@0 251
yuuji@0 252 void server_init (char *server,char *service,char *sslservice,
yuuji@0 253 void *clkint,void *kodint,void *hupint,void *trmint,
yuuji@0 254 void *staint)
yuuji@0 255 {
yuuji@0 256 if (!check_nt ()) {
yuuji@0 257 if (!auth_md5.server) fatal ("Can't run on Windows without MD5 database");
yuuji@0 258 server_nli = T; /* Windows server not logged in */
yuuji@0 259 }
yuuji@0 260 /* only do this if for init call */
yuuji@0 261 if (server && service && sslservice) {
yuuji@0 262 long port;
yuuji@0 263 struct servent *sv;
yuuji@0 264 /* set server name in syslog */
yuuji@0 265 openlog (server,LOG_PID,LOG_MAIL);
yuuji@0 266 fclose (stderr); /* possibly save a process ID */
yuuji@0 267 /* Use SSL if SSL service, or if server starts with "s" and not service */
yuuji@0 268 if (((port = tcp_serverport ()) >= 0)) {
yuuji@0 269 if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
yuuji@0 270 syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
yuuji@0 271 else if ((sv = getservbyname (sslservice,"tcp")) &&
yuuji@0 272 (port == ntohs (sv->s_port))) {
yuuji@0 273 syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
yuuji@0 274 tcp_clientaddr ());
yuuji@0 275 ssl_server_init (server);
yuuji@0 276 }
yuuji@0 277 else { /* not service or SSL service port */
yuuji@0 278 syslog (LOG_DEBUG,"port %ld service init from %s",port,
yuuji@0 279 tcp_clientaddr ());
yuuji@0 280 if (*server == 's') ssl_server_init (server);
yuuji@0 281 }
yuuji@0 282 }
yuuji@0 283 /* make sure stdout does binary */
yuuji@0 284 setmode (fileno (stdin),O_BINARY);
yuuji@0 285 setmode (fileno (stdout),O_BINARY);
yuuji@0 286 }
yuuji@0 287 alarm_rang = clkint; /* note the clock interrupt */
yuuji@0 288 timeBeginPeriod (1000); /* set the timer interval */
yuuji@0 289 timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC);
yuuji@0 290 }
yuuji@0 291
yuuji@0 292
yuuji@0 293 /* Wait for stdin input
yuuji@0 294 * Accepts: timeout in seconds
yuuji@0 295 * Returns: T if have input on stdin, else NIL
yuuji@0 296 */
yuuji@0 297
yuuji@0 298 long server_input_wait (long seconds)
yuuji@0 299 {
yuuji@0 300 fd_set rfd,efd;
yuuji@0 301 struct timeval tmo;
yuuji@0 302 FD_ZERO (&rfd);
yuuji@0 303 FD_ZERO (&efd);
yuuji@0 304 FD_SET (0,&rfd);
yuuji@0 305 FD_SET (0,&efd);
yuuji@0 306 tmo.tv_sec = seconds; tmo.tv_usec = 0;
yuuji@0 307 return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
yuuji@0 308 }
yuuji@0 309
yuuji@0 310 /* Server log in
yuuji@0 311 * Accepts: user name string
yuuji@0 312 * password string
yuuji@0 313 * authenticating user name string
yuuji@0 314 * argument count
yuuji@0 315 * argument vector
yuuji@0 316 * Returns: T if password validated, NIL otherwise
yuuji@0 317 */
yuuji@0 318
yuuji@0 319 static int gotprivs = NIL; /* once-only flag to grab privileges */
yuuji@0 320
yuuji@0 321 long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
yuuji@0 322 {
yuuji@0 323 HANDLE hdl;
yuuji@0 324 LUID tcbpriv;
yuuji@0 325 TOKEN_PRIVILEGES tkp;
yuuji@0 326 char *s;
yuuji@0 327 /* need to get privileges? */
yuuji@0 328 if (!gotprivs++ && check_nt ()) {
yuuji@0 329 /* hack for inetlisn */
yuuji@0 330 if (argc >= 2) myClientHost = argv[1];
yuuji@0 331 /* get process token and TCB priv value */
yuuji@0 332 if (!(OpenProcessToken (GetCurrentProcess (),
yuuji@0 333 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) &&
yuuji@0 334 LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv)))
yuuji@0 335 return NIL;
yuuji@0 336 tkp.PrivilegeCount = 1; /* want to enable this privilege */
yuuji@0 337 tkp.Privileges[0].Luid = tcbpriv;
yuuji@0 338 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
yuuji@0 339 /* enable it */
yuuji@0 340 AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES),
yuuji@0 341 (PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL);
yuuji@0 342 /* make sure it won */
yuuji@0 343 if (GetLastError() != ERROR_SUCCESS) return NIL;
yuuji@0 344 }
yuuji@0 345
yuuji@0 346 /* cretins still haven't given up */
yuuji@0 347 if ((strlen (user) >= MAILTMPLEN) ||
yuuji@0 348 (authuser && (strlen (authuser) >= MAILTMPLEN)))
yuuji@0 349 syslog (LOG_ALERT,"SYSTEM BREAK-IN ATTEMPT, host=%.80s",tcp_clienthost ());
yuuji@0 350 else if (logtry > 0) { /* still have available logins? */
yuuji@0 351 /* authentication user not supported */
yuuji@0 352 if (authuser && *authuser && compare_cstring (authuser,user))
yuuji@0 353 mm_log ("Authentication id must match authorization id",ERROR);
yuuji@0 354 if (check_nt ()) { /* NT: authserver_login() call not supported */
yuuji@0 355 if (!pass) mm_log ("Unsupported authentication mechanism",ERROR);
yuuji@0 356 else if (( /* try to login and impersonate the guy */
yuuji@0 357 #ifdef LOGIN32_LOGON_NETWORK
yuuji@0 358 LogonUser (user,".",pass,LOGON32_LOGON_NETWORK,
yuuji@0 359 LOGON32_PROVIDER_DEFAULT,&hdl) ||
yuuji@0 360 #endif
yuuji@0 361 LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE,
yuuji@0 362 LOGON32_PROVIDER_DEFAULT,&hdl) ||
yuuji@0 363 LogonUser (user,".",pass,LOGON32_LOGON_BATCH,
yuuji@0 364 LOGON32_PROVIDER_DEFAULT,&hdl) ||
yuuji@0 365 LogonUser (user,".",pass,LOGON32_LOGON_SERVICE,
yuuji@0 366 LOGON32_PROVIDER_DEFAULT,&hdl)) &&
yuuji@0 367 ImpersonateLoggedOnUser (hdl)) return env_init (user,NIL);
yuuji@0 368 }
yuuji@0 369 else { /* Win9x: done if from authserver_login() */
yuuji@0 370 if (!pass) server_nli = NIL;
yuuji@0 371 /* otherwise check MD5 database */
yuuji@0 372 else if (s = auth_md5_pwd (user)) {
yuuji@0 373 /* change NLI state based on pwd match */
yuuji@0 374 server_nli = strcmp (s,pass);
yuuji@0 375 memset (s,0,strlen (s));/* erase sensitive information */
yuuji@0 376 fs_give ((void **) &s); /* flush erased password */
yuuji@0 377 }
yuuji@0 378 /* success if no longer NLI */
yuuji@0 379 if (!server_nli) return env_init (user,NIL);
yuuji@0 380 }
yuuji@0 381 }
yuuji@0 382 s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
yuuji@0 383 /* note the failure in the syslog */
yuuji@0 384 syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
yuuji@0 385 sleep (3); /* slow down possible cracker */
yuuji@0 386 return NIL;
yuuji@0 387 }
yuuji@0 388
yuuji@0 389 /* Authenticated server log in
yuuji@0 390 * Accepts: user name string
yuuji@0 391 * authentication user name string
yuuji@0 392 * argument count
yuuji@0 393 * argument vector
yuuji@0 394 * Returns: T if password validated, NIL otherwise
yuuji@0 395 */
yuuji@0 396
yuuji@0 397 long authserver_login (char *user,char *authuser,int argc,char *argv[])
yuuji@0 398 {
yuuji@0 399 return server_login (user,NIL,authuser,argc,argv);
yuuji@0 400 }
yuuji@0 401
yuuji@0 402
yuuji@0 403 /* Log in as anonymous daemon
yuuji@0 404 * Accepts: argument count
yuuji@0 405 * argument vector
yuuji@0 406 * Returns: T if successful, NIL if error
yuuji@0 407 */
yuuji@0 408
yuuji@0 409 long anonymous_login (int argc,char *argv[])
yuuji@0 410 {
yuuji@0 411 return server_login ("Guest",NIL,NIL,argc,argv);
yuuji@0 412 }
yuuji@0 413
yuuji@0 414
yuuji@0 415 /* Initialize environment
yuuji@0 416 * Accepts: user name
yuuji@0 417 * home directory, or NIL to use default
yuuji@0 418 * Returns: T, always
yuuji@0 419 */
yuuji@0 420
yuuji@0 421 long env_init (char *user,char *home)
yuuji@0 422 {
yuuji@0 423 /* don't init if blocked */
yuuji@0 424 if (block_env_init) return LONGT;
yuuji@0 425 if (myUserName) fatal ("env_init called twice!");
yuuji@0 426 myUserName = cpystr (user); /* remember user name */
yuuji@0 427 if (!myHomeDir) /* only if home directory not set up yet */
yuuji@0 428 myHomeDir = (home && *home) ? cpystr (home) : win_homedir (user);
yuuji@0 429 return T;
yuuji@0 430 }
yuuji@0 431
yuuji@0 432 /* Check if NT
yuuji@0 433 * Returns: T if NT, NIL if Win9x
yuuji@0 434 */
yuuji@0 435
yuuji@0 436 int check_nt (void)
yuuji@0 437 {
yuuji@0 438 if (is_nt < 0) { /* not yet set up? */
yuuji@0 439 OSVERSIONINFO ver;
yuuji@0 440 ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
yuuji@0 441 GetVersionEx (&ver);
yuuji@0 442 is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL;
yuuji@0 443 }
yuuji@0 444 return is_nt;
yuuji@0 445 }
yuuji@0 446
yuuji@0 447
yuuji@0 448 /* Return Windows home directory
yuuji@0 449 * Accepts: user name
yuuji@0 450 * Returns: home directory
yuuji@0 451 */
yuuji@0 452
yuuji@0 453 char *win_homedir (char *user)
yuuji@0 454 {
yuuji@0 455 char *s,*t,tmp[MAILTMPLEN];
yuuji@0 456 PUSER_INFO_1 ui;
yuuji@0 457 /* Win9x default */
yuuji@0 458 if (!check_nt ()) sprintf (tmp,"%s\\My Documents",defaultDrive ());
yuuji@0 459 /* get from user info on NT */
yuuji@0 460 else if ((netapi || (netapi = LoadLibrary ("netapi32.dll"))) &&
yuuji@0 461 (getinfo ||
yuuji@0 462 (getinfo = (GETINFO) GetProcAddress (netapi,"NetUserGetInfo"))) &&
yuuji@0 463 MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1,
yuuji@0 464 (WCHAR *) tmp,MAILTMPLEN) &&
yuuji@0 465 !(*getinfo) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) &&
yuuji@0 466 WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1,
yuuji@0 467 tmp,MAILTMPLEN,NIL,NIL) && tmp[0]) {
yuuji@0 468 /* make sure doesn't end with delimiter */
yuuji@0 469 if ((*(s = tmp + strlen (tmp) - 1) == '\\') || (*s == '/')) *s = '\0';
yuuji@0 470 }
yuuji@0 471 /* no home dir, found Win2K user profile? */
yuuji@0 472 else if ((s = getenv ("USERPROFILE")) && (t = strrchr (s,'\\'))) {
yuuji@0 473 strncpy (tmp,s,t-s); /* copy up to user name */
yuuji@0 474 sprintf (tmp+(t-s),"\\%.100s\\My Documents",user);
yuuji@0 475 }
yuuji@0 476 /* last resort NT default */
yuuji@0 477 else sprintf (tmp,"%s\\users\\default",defaultDrive ());
yuuji@0 478 return cpystr (tmp);
yuuji@0 479 }
yuuji@0 480
yuuji@0 481
yuuji@0 482 /* Return default drive
yuuji@0 483 * Returns: default drive
yuuji@0 484 */
yuuji@0 485
yuuji@0 486 static char *defaultDrive (void)
yuuji@0 487 {
yuuji@0 488 char *s = getenv ("SystemDrive");
yuuji@0 489 return (s && *s) ? s : "C:";
yuuji@0 490 }
yuuji@0 491
yuuji@0 492 /* Return my user name
yuuji@0 493 * Accepts: pointer to optional flags
yuuji@0 494 * Returns: my user name
yuuji@0 495 */
yuuji@0 496
yuuji@0 497 char *myusername_full (unsigned long *flags)
yuuji@0 498 {
yuuji@0 499 UCHAR usr[MAILTMPLEN];
yuuji@0 500 DWORD len = MAILTMPLEN;
yuuji@0 501 char *user,*path,*d,*p,pth[MAILTMPLEN];
yuuji@0 502 char *ret = "SYSTEM";
yuuji@0 503 /* get user name if don't have it yet */
yuuji@0 504 if (!myUserName && !server_nli &&
yuuji@0 505 /* use callback, else logon name */
yuuji@0 506 ((mailusername && (user = (char *) (*mailusername) ())) ||
yuuji@0 507 (GetUserName (usr,&len) && _stricmp (user = (char *) usr,"SYSTEM")))) {
yuuji@0 508 if (block_env_init) { /* don't env_init if blocked */
yuuji@0 509 if (flags) *flags = MU_LOGGEDIN;
yuuji@0 510 return user;
yuuji@0 511 }
yuuji@0 512 /* try HOMEPATH, then HOME */
yuuji@0 513 if (p = getenv ("HOMEPATH"))
yuuji@0 514 sprintf (path = pth,"%s%s",
yuuji@0 515 (d = getenv ("HOMEDRIVE")) ? d : defaultDrive (),p);
yuuji@0 516 else if (!(path = getenv ("HOME")))
yuuji@0 517 sprintf (path = pth,"%s\\My Documents",defaultDrive ());
yuuji@0 518 /* make sure doesn't end with delimiter */
yuuji@0 519 if ((*(p = path + strlen (path) -1) == '\\') || (*p == '/')) *p = '\0';
yuuji@0 520 env_init (user,path); /* initialize environment */
yuuji@0 521 }
yuuji@0 522 if (myUserName) { /* logged in? */
yuuji@0 523 if (flags) /* Guest is an anonymous user */
yuuji@0 524 *flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS;
yuuji@0 525 ret = myUserName; /* return user name */
yuuji@0 526 }
yuuji@0 527 else if (flags) *flags = MU_NOTLOGGEDIN;
yuuji@0 528 return ret;
yuuji@0 529 }
yuuji@0 530
yuuji@0 531 /* Return my local host name
yuuji@0 532 * Returns: my local host name
yuuji@0 533 */
yuuji@0 534
yuuji@0 535 char *mylocalhost (void)
yuuji@0 536 {
yuuji@0 537 if (!myLocalHost) {
yuuji@0 538 char tmp[MAILTMPLEN];
yuuji@0 539 if (!wsa_initted++) { /* init Windows Sockets */
yuuji@0 540 WSADATA wsock;
yuuji@0 541 if (WSAStartup (WINSOCK_VERSION,&wsock)) {
yuuji@0 542 wsa_initted = 0;
yuuji@0 543 return "random-pc"; /* try again later? */
yuuji@0 544 }
yuuji@0 545 }
yuuji@0 546 myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
yuuji@0 547 "random-pc" : tcp_canonical (tmp));
yuuji@0 548 }
yuuji@0 549 return myLocalHost;
yuuji@0 550 }
yuuji@0 551
yuuji@0 552 /* Return my home directory name
yuuji@0 553 * Returns: my home directory name
yuuji@0 554 */
yuuji@0 555
yuuji@0 556 char *myhomedir ()
yuuji@0 557 {
yuuji@0 558 if (!myHomeDir) myusername ();/* initialize if first time */
yuuji@0 559 return myHomeDir ? myHomeDir : "";
yuuji@0 560 }
yuuji@0 561
yuuji@0 562
yuuji@0 563 /* Return system standard INBOX
yuuji@0 564 * Accepts: buffer string
yuuji@0 565 */
yuuji@0 566
yuuji@0 567 char *sysinbox ()
yuuji@0 568 {
yuuji@0 569 char tmp[MAILTMPLEN];
yuuji@0 570 if (!sysInbox) { /* initialize if first time */
yuuji@0 571 if (check_nt ()) sprintf (tmp,MAILFILE,myUserName);
yuuji@0 572 else sprintf (tmp,"%s\\INBOX",myhomedir ());
yuuji@0 573 sysInbox = cpystr (tmp); /* system inbox is from mail spool */
yuuji@0 574 }
yuuji@0 575 return sysInbox;
yuuji@0 576 }
yuuji@0 577
yuuji@0 578
yuuji@0 579 /* Return mailbox directory name
yuuji@0 580 * Accepts: destination buffer
yuuji@0 581 * directory prefix
yuuji@0 582 * name in directory
yuuji@0 583 * Returns: file name or NIL if error
yuuji@0 584 */
yuuji@0 585
yuuji@0 586 char *mailboxdir (char *dst,char *dir,char *name)
yuuji@0 587 {
yuuji@0 588 char tmp[MAILTMPLEN];
yuuji@0 589 if (dir || name) { /* if either argument provided */
yuuji@0 590 if (dir) {
yuuji@0 591 if (strlen (dir) > NETMAXMBX) return NIL;
yuuji@0 592 strcpy (tmp,dir); /* write directory prefix */
yuuji@0 593 }
yuuji@0 594 else tmp[0] = '\0'; /* otherwise null string */
yuuji@0 595 if (name) {
yuuji@0 596 if (strlen (name) > NETMAXMBX) return NIL;
yuuji@0 597 strcat (tmp,name); /* write name in directory */
yuuji@0 598 }
yuuji@0 599 /* validate name, return its name */
yuuji@0 600 if (!mailboxfile (dst,tmp)) return NIL;
yuuji@0 601 }
yuuji@0 602 else strcpy (dst,myhomedir());/* no arguments, wants home directory */
yuuji@0 603 return dst; /* return the name */
yuuji@0 604 }
yuuji@0 605
yuuji@0 606 /* Return mailbox file name
yuuji@0 607 * Accepts: destination buffer
yuuji@0 608 * mailbox name
yuuji@0 609 * Returns: file name or empty string for driver-selected INBOX or NIL if error
yuuji@0 610 */
yuuji@0 611
yuuji@0 612 char *mailboxfile (char *dst,char *name)
yuuji@0 613 {
yuuji@0 614 char homedev[3];
yuuji@0 615 char *dir = myhomedir ();
yuuji@0 616 if (dir[0] && isalpha (dir[0]) && (dir[1] == ':')) {
yuuji@0 617 homedev[0] = dir[0]; /* copy home device */
yuuji@0 618 homedev[1] = dir[1];
yuuji@0 619 homedev[2] = '\0';
yuuji@0 620 }
yuuji@0 621 else homedev[0] = '\0'; /* ??no home device?? */
yuuji@0 622 *dst = '\0'; /* default to empty string */
yuuji@0 623 /* check for INBOX */
yuuji@0 624 if (!compare_cstring (name,"INBOX"));
yuuji@0 625 /* reject names with / */
yuuji@0 626 else if (strchr (name,'/')) dst = NIL;
yuuji@0 627 else switch (*name) {
yuuji@0 628 case '#': /* namespace names */
yuuji@0 629 if (((name[1] == 'u') || (name[1] == 'U')) &&
yuuji@0 630 ((name[2] == 's') || (name[2] == 'S')) &&
yuuji@0 631 ((name[3] == 'e') || (name[3] == 'E')) &&
yuuji@0 632 ((name[4] == 'r') || (name[4] == 'R')) && (name[5] == '.')) {
yuuji@0 633 /* copy user name to destination buffer */
yuuji@0 634 for (dir = dst,name += 6; *name && (*name != '\\'); *dir++ = *name++);
yuuji@0 635 *dir++ = '\0'; /* tie off user name */
yuuji@0 636 /* look up homedir for user name */
yuuji@0 637 if (dir = win_homedir (dst)) {
yuuji@0 638 /* build resulting name */
yuuji@0 639 sprintf (dst,"%s\\%s",dir,name);
yuuji@0 640 fs_give ((void **) &dir);
yuuji@0 641 }
yuuji@0 642 else dst = NIL;
yuuji@0 643 }
yuuji@0 644 else dst = NIL; /* unknown namespace name */
yuuji@0 645 break;
yuuji@0 646 case '\\': /* absolute path on default drive? */
yuuji@0 647 sprintf (dst,"%s%s",homedev,name);
yuuji@0 648 break;
yuuji@0 649 default: /* any other name */
yuuji@0 650 if (name[1] == ':') { /* some other drive? */
yuuji@0 651 if (name[2] == '\\') strcpy (dst,name);
yuuji@0 652 else sprintf (dst,"%c:\\%s",name[0],name+2);
yuuji@0 653 }
yuuji@0 654 /* build home-directory relative name */
yuuji@0 655 else sprintf (dst,"%s\\%s",dir,name);
yuuji@0 656 }
yuuji@0 657 return dst; /* return it */
yuuji@0 658 }
yuuji@0 659
yuuji@0 660 /* Lock file name
yuuji@0 661 * Accepts: return buffer for file name
yuuji@0 662 * file name
yuuji@0 663 * locking to be placed on file if non-NIL
yuuji@0 664 * Returns: file descriptor of lock or -1 if error
yuuji@0 665 */
yuuji@0 666
yuuji@0 667 int lockname (char *lock,char *fname,int op)
yuuji@0 668 {
yuuji@0 669 int ld;
yuuji@0 670 char c,*s;
yuuji@0 671 /* Win2K and Win98 have TEMP under windir */
yuuji@0 672 if (!((s = lockdir (lock,getenv ("windir"),"TEMP")) ||
yuuji@0 673 /* NT4, NT3.x and Win95 use one of these */
yuuji@0 674 (s = lockdir (lock,getenv ("TEMP"),NIL)) ||
yuuji@0 675 (s = lockdir (lock,getenv ("TMP"),NIL)) ||
yuuji@0 676 (s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
yuuji@0 677 /* try one of these */
yuuji@0 678 (s = lockdir (lock,defaultDrive (),"WINNT\\TEMP")) ||
yuuji@0 679 (s = lockdir (lock,defaultDrive (),"WINDOWS\\TEMP")) ||
yuuji@0 680 /* C:\TEMP is last resort */
yuuji@0 681 (s = lockdir (lock,defaultDrive (),"TEMP")))) {
yuuji@0 682 mm_log ("Unable to find temporary directory",ERROR);
yuuji@0 683 return -1;
yuuji@0 684 }
yuuji@0 685 /* generate file name */
yuuji@0 686 while (c = *fname++) switch (c) {
yuuji@0 687 case '/': case '\\': case ':':
yuuji@0 688 *s++ = '!'; /* convert bad chars to ! */
yuuji@0 689 break;
yuuji@0 690 default:
yuuji@0 691 *s++ = c;
yuuji@0 692 break;
yuuji@0 693 }
yuuji@0 694 *s++ = c; /* tie off name */
yuuji@0 695 /* get the lock */
yuuji@0 696 if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
yuuji@0 697 flock (ld,op); /* apply locking function */
yuuji@0 698 return ld; /* return locking file descriptor */
yuuji@0 699 }
yuuji@0 700
yuuji@0 701 /* Build lock directory, check to see if it exists
yuuji@0 702 * Accepts: return buffer for lock directory
yuuji@0 703 * first part of possible name
yuuji@0 704 * optional second part
yuuji@0 705 * Returns: pointer to end of buffer if buffer has a good name, else NIL
yuuji@0 706 */
yuuji@0 707
yuuji@0 708 char *lockdir (char *lock,char *first,char *last)
yuuji@0 709 {
yuuji@0 710 struct stat sbuf;
yuuji@0 711 char c,*s;
yuuji@0 712 if (first && *first) { /* first part must be non-NIL */
yuuji@0 713 /* copy first part */
yuuji@0 714 for (s = lock; c = *first++; *s++ = (c == '/') ? '\\' : c);
yuuji@0 715 if (last && *last) { /* copy last part if specified */
yuuji@0 716 /* write trailing \ in case not in first */
yuuji@0 717 if (s[-1] != '\\') *s++ = '\\';
yuuji@0 718 while (c = *last++) *s++ = (c == '/') ? '\\' : c;
yuuji@0 719 }
yuuji@0 720 if (s[-1] == '\\') --s; /* delete trailing \ if any */
yuuji@0 721 *s = s[1] = '\0'; /* tie off name at this point */
yuuji@0 722 if (!stat (lock,&sbuf)) { /* does the name exist? */
yuuji@0 723 *s++ = '\\'; /* yes, reinstall trailing \ */
yuuji@0 724 return s; /* return the name */
yuuji@0 725 }
yuuji@0 726 }
yuuji@0 727 return NIL; /* failed */
yuuji@0 728 }
yuuji@0 729
yuuji@0 730
yuuji@0 731 /* Unlock file descriptor
yuuji@0 732 * Accepts: file descriptor
yuuji@0 733 * lock file name from lockfd()
yuuji@0 734 */
yuuji@0 735
yuuji@0 736 void unlockfd (int fd,char *lock)
yuuji@0 737 {
yuuji@0 738 flock (fd,LOCK_UN); /* unlock it */
yuuji@0 739 close (fd); /* close it */
yuuji@0 740 }
yuuji@0 741
yuuji@0 742
yuuji@0 743 /* Determine default prototype stream to user
yuuji@0 744 * Accepts: type (NIL for create, T for append)
yuuji@0 745 * Returns: default prototype stream
yuuji@0 746 */
yuuji@0 747
yuuji@0 748 MAILSTREAM *default_proto (long type)
yuuji@0 749 {
yuuji@0 750 extern MAILSTREAM CREATEPROTO,APPENDPROTO;
yuuji@0 751 return type ? &APPENDPROTO : &CREATEPROTO;
yuuji@0 752 }
yuuji@0 753
yuuji@0 754 /* Default block notify routine
yuuji@0 755 * Accepts: reason for calling
yuuji@0 756 * data
yuuji@0 757 * Returns: data
yuuji@0 758 */
yuuji@0 759
yuuji@0 760 void *mm_blocknotify (int reason,void *data)
yuuji@0 761 {
yuuji@0 762 void *ret = data;
yuuji@0 763 switch (reason) {
yuuji@0 764 case BLOCK_SENSITIVE: /* entering sensitive code */
yuuji@0 765 ret = (void *) alarm (0);
yuuji@0 766 break;
yuuji@0 767 case BLOCK_NONSENSITIVE: /* exiting sensitive code */
yuuji@0 768 if ((unsigned int) data) alarm ((unsigned int) data);
yuuji@0 769 break;
yuuji@0 770 default: /* ignore all other reasons */
yuuji@0 771 break;
yuuji@0 772 }
yuuji@0 773 return ret;
yuuji@0 774 }

UW-IMAP'd extensions by yuuji