imapext-2007

diff src/osdep/amiga/env_ami.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/amiga/env_ami.c	Mon Sep 14 15:17:45 2009 +0900
     1.3 @@ -0,0 +1,1282 @@
     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:	Amiga environment routines
    1.19 + *
    1.20 + * Author:	Mark Crispin
    1.21 + *		UW Technology
    1.22 + *		Seattle, WA  98195
    1.23 + *		Internet: MRC@Washington.EDU
    1.24 + *
    1.25 + * Date:	1 August 1988
    1.26 + * Last Edited:	15 May 2008
    1.27 + */
    1.28 +
    1.29 +#include <grp.h>
    1.30 +#include <signal.h>
    1.31 +#include <sys/wait.h>
    1.32 +
    1.33 +/* c-client environment parameters */
    1.34 +
    1.35 +static char *myUserName = NIL;	/* user name */
    1.36 +static char *myHomeDir = NIL;	/* home directory name */
    1.37 +static char *myMailboxDir = NIL;/* mailbox directory name */
    1.38 +static char *myLocalHost = NIL;	/* local host name */
    1.39 +static char *myNewsrc = NIL;	/* newsrc file name */
    1.40 +static char *mailsubdir = NIL;	/* mail subdirectory name */
    1.41 +static char *sysInbox = NIL;	/* system inbox name */
    1.42 +static char *newsActive = NIL;	/* news active file */
    1.43 +static char *newsSpool = NIL;	/* news spool */
    1.44 +				/* anonymous home directory */
    1.45 +static char *anonymousHome = NIL;
    1.46 +static char *ftpHome = NIL;	/* ftp export home directory */
    1.47 +static char *publicHome = NIL;	/* public home directory */
    1.48 +static char *sharedHome = NIL;	/* shared home directory */
    1.49 +static short anonymous = NIL;	/* is anonymous */
    1.50 +static short restrictBox = NIL;	/* is a restricted box */
    1.51 +static short has_no_life = NIL;	/* is a cretin with no life */
    1.52 +				/* block environment init */
    1.53 +static short block_env_init = NIL;
    1.54 +static short hideDotFiles = NIL;/* hide files whose names start with . */
    1.55 +				/* advertise filesystem root */
    1.56 +static short advertisetheworld = NIL;
    1.57 +				/* disable automatic shared namespaces */
    1.58 +static short noautomaticsharedns = NIL;
    1.59 +static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
    1.60 +static short netfsstatbug = NIL;/* compensate for broken stat() on network
    1.61 +				 * filesystems (AFS and old NFS).  Don't do
    1.62 +				 * this unless you really have to!
    1.63 +				 */
    1.64 +				/* 1 = disable plaintext, 2 = if not SSL */
    1.65 +static long disablePlaintext = NIL;
    1.66 +static long list_max_level = 20;/* maximum level of list recursion */
    1.67 +				/* default file protection */
    1.68 +static long mbx_protection = 0600;
    1.69 +				/* default directory protection */
    1.70 +static long dir_protection = 0700;
    1.71 +				/* default lock file protection */
    1.72 +static long lock_protection = MANDATORYLOCKPROT;
    1.73 +				/* default ftp file protection */
    1.74 +static long ftp_protection = 0644;
    1.75 +static long ftp_dir_protection = 0755;
    1.76 +				/* default public file protection */
    1.77 +static long public_protection = 0666;
    1.78 +static long public_dir_protection = 0777;
    1.79 +				/* default shared file protection */
    1.80 +static long shared_protection = 0660;
    1.81 +static long shared_dir_protection = 0770;
    1.82 +static long locktimeout = 5;	/* default lock timeout */
    1.83 +				/* default prototypes */
    1.84 +static MAILSTREAM *createProto = NIL;
    1.85 +static MAILSTREAM *appendProto = NIL;
    1.86 +				/* default user flags */
    1.87 +static char *userFlags[NUSERFLAGS] = {NIL};
    1.88 +static NAMESPACE *nslist[3];	/* namespace list */
    1.89 +static int logtry = 3;		/* number of server login tries */
    1.90 +				/* block notification */
    1.91 +static blocknotify_t mailblocknotify = mm_blocknotify;
    1.92 +
    1.93 +/* Amiga namespaces */
    1.94 +
    1.95 +				/* personal mh namespace */
    1.96 +static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
    1.97 +static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
    1.98 +				/* home namespace */
    1.99 +static NAMESPACE nshome = {"",'/',NIL,&nsmh};
   1.100 +				/* Amiga other user namespace */
   1.101 +static NAMESPACE nsamigaother = {"~",'/',NIL,NIL};
   1.102 +				/* public (anonymous OK) namespace */
   1.103 +static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
   1.104 +				/* netnews namespace */
   1.105 +static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
   1.106 +				/* FTP export namespace */
   1.107 +static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
   1.108 +				/* shared (no anonymous) namespace */
   1.109 +static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
   1.110 +				/* world namespace */
   1.111 +static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
   1.112 +
   1.113 +#include "write.c"		/* include safe writing routines */
   1.114 +#include "pmatch.c"		/* include wildcard pattern matcher */
   1.115 +
   1.116 +/* Get all authenticators */
   1.117 +
   1.118 +#include "auths.c"
   1.119 +
   1.120 +/* Environment manipulate parameters
   1.121 + * Accepts: function code
   1.122 + *	    function-dependent value
   1.123 + * Returns: function-dependent return value
   1.124 + */
   1.125 +
   1.126 +void *env_parameters (long function,void *value)
   1.127 +{
   1.128 +  void *ret = NIL;
   1.129 +  switch ((int) function) {
   1.130 +  case GET_NAMESPACE:
   1.131 +    ret = (void *) nslist;
   1.132 +    break;
   1.133 +  case SET_USERNAME:
   1.134 +    if (myUserName) fs_give ((void **) &myUserName);
   1.135 +    myUserName = cpystr ((char *) value);
   1.136 +  case GET_USERNAME:
   1.137 +    ret = (void *) myUserName;
   1.138 +    break;
   1.139 +  case SET_HOMEDIR:
   1.140 +    if (myHomeDir) fs_give ((void **) &myHomeDir);
   1.141 +    myHomeDir = cpystr ((char *) value);
   1.142 +  case GET_HOMEDIR:
   1.143 +    ret = (void *) myHomeDir;
   1.144 +    break;
   1.145 +  case SET_LOCALHOST:
   1.146 +    if (myLocalHost) fs_give ((void **) &myLocalHost);
   1.147 +    myLocalHost = cpystr ((char *) value);
   1.148 +  case GET_LOCALHOST:
   1.149 +    ret = (void *) myLocalHost;
   1.150 +    break;
   1.151 +  case SET_NEWSRC:
   1.152 +    if (myNewsrc) fs_give ((void **) &myNewsrc);
   1.153 +    myNewsrc = cpystr ((char *) value);
   1.154 +  case GET_NEWSRC:
   1.155 +    ret = (void *) myNewsrc;
   1.156 +    break;
   1.157 +  case SET_NEWSACTIVE:
   1.158 +    if (newsActive) fs_give ((void **) &newsActive);
   1.159 +    newsActive = cpystr ((char *) value);
   1.160 +  case GET_NEWSACTIVE:
   1.161 +    ret = (void *) newsActive;
   1.162 +    break;
   1.163 +  case SET_NEWSSPOOL:
   1.164 +    if (newsSpool) fs_give ((void **) &newsSpool);
   1.165 +    newsSpool = cpystr ((char *) value);
   1.166 +  case GET_NEWSSPOOL:
   1.167 +    ret = (void *) newsSpool;
   1.168 +    break;
   1.169 +
   1.170 +  case SET_ANONYMOUSHOME:
   1.171 +    if (anonymousHome) fs_give ((void **) &anonymousHome);
   1.172 +    anonymousHome = cpystr ((char *) value);
   1.173 +  case GET_ANONYMOUSHOME:
   1.174 +    if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
   1.175 +    ret = (void *) anonymousHome;
   1.176 +    break;
   1.177 +  case SET_FTPHOME:
   1.178 +    if (ftpHome) fs_give ((void **) &ftpHome);
   1.179 +    ftpHome = cpystr ((char *) value);
   1.180 +  case GET_FTPHOME:
   1.181 +    ret = (void *) ftpHome;
   1.182 +    break;
   1.183 +  case SET_PUBLICHOME:
   1.184 +    if (publicHome) fs_give ((void **) &publicHome);
   1.185 +    publicHome = cpystr ((char *) value);
   1.186 +  case GET_PUBLICHOME:
   1.187 +    ret = (void *) publicHome;
   1.188 +    break;
   1.189 +  case SET_SHAREDHOME:
   1.190 +    if (sharedHome) fs_give ((void **) &sharedHome);
   1.191 +    sharedHome = cpystr ((char *) value);
   1.192 +  case GET_SHAREDHOME:
   1.193 +    ret = (void *) sharedHome;
   1.194 +    break;
   1.195 +  case SET_SYSINBOX:
   1.196 +    if (sysInbox) fs_give ((void **) &sysInbox);
   1.197 +    sysInbox = cpystr ((char *) value);
   1.198 +  case GET_SYSINBOX:
   1.199 +    ret = (void *) sysInbox;
   1.200 +    break;
   1.201 +  case SET_LISTMAXLEVEL:
   1.202 +    list_max_level = (long) value;
   1.203 +  case GET_LISTMAXLEVEL:
   1.204 +    ret = (void *) list_max_level;
   1.205 +    break;
   1.206 +
   1.207 +  case SET_MBXPROTECTION:
   1.208 +    mbx_protection = (long) value;
   1.209 +  case GET_MBXPROTECTION:
   1.210 +    ret = (void *) mbx_protection;
   1.211 +    break;
   1.212 +  case SET_DIRPROTECTION:
   1.213 +    dir_protection = (long) value;
   1.214 +  case GET_DIRPROTECTION:
   1.215 +    ret = (void *) dir_protection;
   1.216 +    break;
   1.217 +  case SET_LOCKPROTECTION:
   1.218 +    lock_protection = (long) value;
   1.219 +  case GET_LOCKPROTECTION:
   1.220 +    ret = (void *) lock_protection;
   1.221 +    break;
   1.222 +  case SET_FTPPROTECTION:
   1.223 +    ftp_protection = (long) value;
   1.224 +  case GET_FTPPROTECTION:
   1.225 +    ret = (void *) ftp_protection;
   1.226 +    break;
   1.227 +  case SET_PUBLICPROTECTION:
   1.228 +    public_protection = (long) value;
   1.229 +  case GET_PUBLICPROTECTION:
   1.230 +    ret = (void *) public_protection;
   1.231 +    break;
   1.232 +  case SET_SHAREDPROTECTION:
   1.233 +    shared_protection = (long) value;
   1.234 +  case GET_SHAREDPROTECTION:
   1.235 +    ret = (void *) shared_protection;
   1.236 +    break;
   1.237 +  case SET_FTPDIRPROTECTION:
   1.238 +    ftp_dir_protection = (long) value;
   1.239 +  case GET_FTPDIRPROTECTION:
   1.240 +    ret = (void *) ftp_dir_protection;
   1.241 +    break;
   1.242 +  case SET_PUBLICDIRPROTECTION:
   1.243 +    public_dir_protection = (long) value;
   1.244 +  case GET_PUBLICDIRPROTECTION:
   1.245 +    ret = (void *) public_dir_protection;
   1.246 +    break;
   1.247 +  case SET_SHAREDDIRPROTECTION:
   1.248 +    shared_dir_protection = (long) value;
   1.249 +  case GET_SHAREDDIRPROTECTION:
   1.250 +    ret = (void *) shared_dir_protection;
   1.251 +    break;
   1.252 +
   1.253 +  case SET_LOCKTIMEOUT:
   1.254 +    locktimeout = (long) value;
   1.255 +  case GET_LOCKTIMEOUT:
   1.256 +    ret = (void *) locktimeout;
   1.257 +    break;
   1.258 +  case SET_HIDEDOTFILES:
   1.259 +    hideDotFiles = value ? T : NIL;
   1.260 +  case GET_HIDEDOTFILES:
   1.261 +    ret = (void *) (hideDotFiles ? VOIDT : NIL);
   1.262 +    break;
   1.263 +  case SET_DISABLEPLAINTEXT:
   1.264 +    disablePlaintext = (long) value;
   1.265 +  case GET_DISABLEPLAINTEXT:
   1.266 +    ret = (void *) disablePlaintext;
   1.267 +    break;
   1.268 +  case SET_ADVERTISETHEWORLD:
   1.269 +    advertisetheworld = value ? T : NIL;
   1.270 +  case GET_ADVERTISETHEWORLD:
   1.271 +    ret = (void *) (advertisetheworld ? VOIDT : NIL);
   1.272 +    break;
   1.273 +  case SET_DISABLEAUTOSHAREDNS:
   1.274 +    noautomaticsharedns = value ? T : NIL;
   1.275 +  case GET_DISABLEAUTOSHAREDNS:
   1.276 +    ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
   1.277 +    break;
   1.278 +  case SET_DISABLE822TZTEXT:
   1.279 +    no822tztext = value ? T : NIL;
   1.280 +  case GET_DISABLE822TZTEXT:
   1.281 +    ret = (void *) (no822tztext ? VOIDT : NIL);
   1.282 +    break;
   1.283 +  case SET_USERHASNOLIFE:
   1.284 +    has_no_life = value ? T : NIL;
   1.285 +  case GET_USERHASNOLIFE:
   1.286 +    ret = (void *) (has_no_life ? VOIDT : NIL);
   1.287 +    break;
   1.288 +  case SET_NETFSSTATBUG:
   1.289 +    netfsstatbug = value ? T : NIL;
   1.290 +  case GET_NETFSSTATBUG:
   1.291 +    ret = (void *) (netfsstatbug ? VOIDT : NIL);
   1.292 +    break;
   1.293 +  case SET_BLOCKENVINIT:
   1.294 +    block_env_init = value ? T : NIL;
   1.295 +  case GET_BLOCKENVINIT:
   1.296 +    ret = (void *) (block_env_init ? VOIDT : NIL);
   1.297 +    break;
   1.298 +  case SET_BLOCKNOTIFY:
   1.299 +    mailblocknotify = (blocknotify_t) value;
   1.300 +  case GET_BLOCKNOTIFY:
   1.301 +    ret = (void *) mailblocknotify;
   1.302 +    break;
   1.303 +  }
   1.304 +  return ret;
   1.305 +}
   1.306 +
   1.307 +/* Write current time
   1.308 + * Accepts: destination string
   1.309 + *	    optional format of day-of-week prefix
   1.310 + *	    format of date and time
   1.311 + *	    flag whether to append symbolic timezone
   1.312 + */
   1.313 +
   1.314 +static void do_date (char *date,char *prefix,char *fmt,int suffix)
   1.315 +{
   1.316 +  time_t tn = time (0);
   1.317 +  struct tm *t = gmtime (&tn);
   1.318 +  int zone = t->tm_hour * 60 + t->tm_min;
   1.319 +  int julian = t->tm_yday;
   1.320 +  t = localtime (&tn);		/* get local time now */
   1.321 +				/* minus UTC minutes since midnight */
   1.322 +  zone = t->tm_hour * 60 + t->tm_min - zone;
   1.323 +  /* julian can be one of:
   1.324 +   *  36x  local time is December 31, UTC is January 1, offset -24 hours
   1.325 +   *    1  local time is 1 day ahead of UTC, offset +24 hours
   1.326 +   *    0  local time is same day as UTC, no offset
   1.327 +   *   -1  local time is 1 day behind UTC, offset -24 hours
   1.328 +   * -36x  local time is January 1, UTC is December 31, offset +24 hours
   1.329 +   */
   1.330 +  if (julian = t->tm_yday -julian)
   1.331 +    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
   1.332 +  if (prefix) {			/* want day of week? */
   1.333 +    sprintf (date,prefix,days[t->tm_wday]);
   1.334 +    date += strlen (date);	/* make next sprintf append */
   1.335 +  }
   1.336 +				/* output the date */
   1.337 +  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
   1.338 +	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
   1.339 +				/* append timezone suffix if desired */
   1.340 +  if (suffix) rfc822_timezone (date,(void *) t);
   1.341 +}
   1.342 +
   1.343 +/* Write current time in RFC 822 format
   1.344 + * Accepts: destination string
   1.345 + */
   1.346 +
   1.347 +void rfc822_date (char *date)
   1.348 +{
   1.349 +  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
   1.350 +	   no822tztext ? NIL : T);
   1.351 +}
   1.352 +
   1.353 +
   1.354 +/* Write current time in fixed-width RFC 822 format
   1.355 + * Accepts: destination string
   1.356 + */
   1.357 +
   1.358 +void rfc822_fixed_date (char *date)
   1.359 +{
   1.360 +  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
   1.361 +}
   1.362 +
   1.363 +
   1.364 +/* Write current time in internal format
   1.365 + * Accepts: destination string
   1.366 + */
   1.367 +
   1.368 +void internal_date (char *date)
   1.369 +{
   1.370 +  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
   1.371 +}
   1.372 +
   1.373 +/* Initialize server
   1.374 + * Accepts: server name for syslog or NIL
   1.375 + *	    /etc/services service name or NIL
   1.376 + *	    alternate /etc/services service name or NIL
   1.377 + *	    clock interrupt handler
   1.378 + *	    kiss-of-death interrupt handler
   1.379 + *	    hangup interrupt handler
   1.380 + *	    termination interrupt handler
   1.381 + */
   1.382 +
   1.383 +void server_init (char *server,char *service,char *sslservice,
   1.384 +		  void *clkint,void *kodint,void *hupint,void *trmint,
   1.385 +		  void *staint)
   1.386 +{
   1.387 +  int onceonly = server && service && sslservice;
   1.388 +  if (onceonly) {		/* set server name in syslog */
   1.389 +    int mask;
   1.390 +    openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
   1.391 +    fclose (stderr);		/* possibly save a process ID */
   1.392 +
   1.393 +    switch (mask = umask (022)){/* check old umask */
   1.394 +    case 0:			/* definitely unreasonable */
   1.395 +    case 022:			/* don't need to change it */
   1.396 +      break;
   1.397 +    default:			/* already was a reasonable value */
   1.398 +      umask (mask);		/* so change it back */
   1.399 +    }
   1.400 +  }
   1.401 +  arm_signal (SIGALRM,clkint);	/* prepare for clock interrupt */
   1.402 +  arm_signal (SIGUSR2,kodint);	/* prepare for Kiss Of Death */
   1.403 +  arm_signal (SIGHUP,hupint);	/* prepare for hangup */
   1.404 +  arm_signal (SIGPIPE,hupint);	/* alternative hangup */
   1.405 +  arm_signal (SIGTERM,trmint);	/* prepare for termination */
   1.406 +				/* status dump */
   1.407 +  if (staint) arm_signal (SIGUSR1,staint);
   1.408 +  if (onceonly) {		/* set up network and maybe SSL */
   1.409 +    long port;
   1.410 +    struct servent *sv;
   1.411 +    /* Use SSL if SSL service, or if server starts with "s" and not service */
   1.412 +    if (((port = tcp_serverport ()) >= 0)) {
   1.413 +      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
   1.414 +	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
   1.415 +      else if ((sv = getservbyname (sslservice,"tcp")) &&
   1.416 +	       (port == ntohs (sv->s_port))) {
   1.417 +	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
   1.418 +		tcp_clientaddr ());
   1.419 +	ssl_server_init (server);
   1.420 +      }
   1.421 +      else {			/* not service or SSL service port */
   1.422 +	syslog (LOG_DEBUG,"port %ld service init from %s",port,
   1.423 +		tcp_clientaddr ());
   1.424 +	if (*server == 's') ssl_server_init (server);
   1.425 +      }
   1.426 +    }
   1.427 +  }
   1.428 +}
   1.429 +
   1.430 +/* Wait for stdin input
   1.431 + * Accepts: timeout in seconds
   1.432 + * Returns: T if have input on stdin, else NIL
   1.433 + */
   1.434 +
   1.435 +long server_input_wait (long seconds)
   1.436 +{
   1.437 +  fd_set rfd,efd;
   1.438 +  struct timeval tmo;
   1.439 +  FD_ZERO (&rfd);
   1.440 +  FD_ZERO (&efd);
   1.441 +  FD_SET (0,&rfd);
   1.442 +  FD_SET (0,&efd);
   1.443 +  tmo.tv_sec = seconds; tmo.tv_usec = 0;
   1.444 +  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
   1.445 +}
   1.446 +
   1.447 +/* Return Amiga password entry for user name
   1.448 + * Accepts: user name string
   1.449 + * Returns: password entry
   1.450 + *
   1.451 + * Tries all-lowercase form of user name if given user name fails
   1.452 + */
   1.453 +
   1.454 +static struct passwd *pwuser (unsigned char *user)
   1.455 +{
   1.456 +  unsigned char *s;
   1.457 +  struct passwd *pw = getpwnam (user);
   1.458 +  if (!pw) {			/* failed, see if any uppercase characters */
   1.459 +    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
   1.460 +    if (*s) {			/* yes, try all lowercase form */
   1.461 +      pw = getpwnam (s = lcase (cpystr (user)));
   1.462 +      fs_give ((void **) &s);
   1.463 +    }
   1.464 +  }
   1.465 +  return pw;
   1.466 +}
   1.467 +
   1.468 +
   1.469 +/* Validate password for user name
   1.470 + * Accepts: user name string
   1.471 + *	    password string
   1.472 + *	    argument count
   1.473 + *	    argument vector
   1.474 + * Returns: password entry if validated
   1.475 + *
   1.476 + * Tries password+1 if password fails and starts with space
   1.477 + */
   1.478 +
   1.479 +static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
   1.480 +{
   1.481 +  char *s;
   1.482 +  struct passwd *pw;
   1.483 +  struct passwd *ret = NIL;
   1.484 +  if (auth_md5.server) {	/* using CRAM-MD5 authentication? */
   1.485 +    if (s = auth_md5_pwd (user)) {
   1.486 +      if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
   1.487 +	ret = pwuser (user);	/* validated, get passwd entry for user */
   1.488 +      memset (s,0,strlen (s));	/* erase sensitive information */
   1.489 +      fs_give ((void **) &s);
   1.490 +    }
   1.491 +  }
   1.492 +  else if (pw = pwuser (user)) {/* can get user? */
   1.493 +    s = cpystr (pw->pw_name);	/* copy returned name in case we need it */
   1.494 +    if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
   1.495 +	(*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
   1.496 +      ret = checkpw (pw,pwd+1,argc,argv);
   1.497 +    fs_give ((void **) &s);	/* don't need copy of name any more */
   1.498 +  }
   1.499 +  return ret;
   1.500 +}
   1.501 +
   1.502 +/* Server log in
   1.503 + * Accepts: user name string
   1.504 + *	    password string
   1.505 + *	    authenticating user name string
   1.506 + *	    argument count
   1.507 + *	    argument vector
   1.508 + * Returns: T if password validated, NIL otherwise
   1.509 + */
   1.510 +
   1.511 +long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
   1.512 +{
   1.513 +  struct passwd *pw = NIL;
   1.514 +  int level = LOG_NOTICE;
   1.515 +  char *err = "failed";
   1.516 +				/* cretins still haven't given up */
   1.517 +  if ((strlen (user) >= NETMAXUSER) ||
   1.518 +      (authuser && (strlen (authuser) >= NETMAXUSER))) {
   1.519 +    level = LOG_ALERT;		/* escalate this alert */
   1.520 +    err = "SYSTEM BREAK-IN ATTEMPT";
   1.521 +    logtry = 0;			/* render this session useless */
   1.522 +  }
   1.523 +  else if (logtry-- <= 0) err = "excessive login failures";
   1.524 +  else if (disablePlaintext) err = "disabled";
   1.525 +  else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
   1.526 +  else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
   1.527 +  if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
   1.528 +  syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
   1.529 +	  user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
   1.530 +  sleep (3);			/* slow down possible cracker */
   1.531 +  return NIL;
   1.532 +}
   1.533 +
   1.534 +/* Authenticated server log in
   1.535 + * Accepts: user name string
   1.536 + *	    authenticating user name string
   1.537 + *	    argument count
   1.538 + *	    argument vector
   1.539 + * Returns: T if password validated, NIL otherwise
   1.540 + */
   1.541 +
   1.542 +long authserver_login (char *user,char *authuser,int argc,char *argv[])
   1.543 +{
   1.544 +  return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
   1.545 +}
   1.546 +
   1.547 +
   1.548 +/* Log in as anonymous daemon
   1.549 + * Accepts: argument count
   1.550 + *	    argument vector
   1.551 + * Returns: T if successful, NIL if error
   1.552 + */
   1.553 +
   1.554 +long anonymous_login (int argc,char *argv[])
   1.555 +{
   1.556 +				/* log in Mr. A. N. Onymous */
   1.557 +  return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
   1.558 +		   (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
   1.559 +		   argc,argv);
   1.560 +}
   1.561 +
   1.562 +/* Finish log in and environment initialization
   1.563 + * Accepts: passwd struct for loginpw()
   1.564 + *	    optional authentication user name
   1.565 + *	    user name (NIL for anonymous)
   1.566 + *	    home directory (NIL to use directory from passwd struct)
   1.567 + *	    argument count
   1.568 + *	    argument vector
   1.569 + * Returns: T if successful, NIL if error
   1.570 + */
   1.571 +
   1.572 +long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
   1.573 +	       char *argv[])
   1.574 +{
   1.575 +  struct group *gr;
   1.576 +  char **t;
   1.577 +  long ret = NIL;
   1.578 +  if (pw && pw->pw_uid) {	/* must have passwd struct for non-UID 0 */
   1.579 +				/* make safe copies of user and home */
   1.580 +    if (user) user = cpystr (pw->pw_name);
   1.581 +    home = cpystr (home ? home : pw->pw_dir);
   1.582 +				/* authorization ID .NE. authentication ID? */
   1.583 +    if (user && auser && *auser && compare_cstring (auser,user)) {
   1.584 +				/* scan list of mail administrators */
   1.585 +      if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
   1.586 +	if (!compare_cstring (auser,*t++))
   1.587 +	  ret = pw_login (pw,NIL,user,home,argc,argv);
   1.588 +      syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
   1.589 +	      ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
   1.590 +    }
   1.591 +				/* normal login */
   1.592 +    else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
   1.593 +	     (ret = env_init (user,home))) chdir (myhomedir ());
   1.594 +    fs_give ((void **) &home);	/* clean up */
   1.595 +    if (user) fs_give ((void **) &user);
   1.596 +  }
   1.597 +  return ret;			/* return status */
   1.598 +}
   1.599 +
   1.600 +/* Initialize environment
   1.601 + * Accepts: user name (NIL for anonymous)
   1.602 + *	    home directory name
   1.603 + * Returns: T, always
   1.604 + */
   1.605 +
   1.606 +long env_init (char *user,char *home)
   1.607 +{
   1.608 +  extern MAILSTREAM CREATEPROTO;
   1.609 +  extern MAILSTREAM EMPTYPROTO;
   1.610 +  struct passwd *pw;
   1.611 +  struct stat sbuf;
   1.612 +  char tmp[MAILTMPLEN];
   1.613 +				/* don't init if blocked */
   1.614 +  if (block_env_init) return LONGT;
   1.615 +  if (myUserName) fatal ("env_init called twice!");
   1.616 +				/* set up user name */
   1.617 +  myUserName = cpystr (user ? user : ANONYMOUSUSER);
   1.618 +  if (user) {			/* remember user name and home directory */
   1.619 +    nslist[0] = &nshome;	/* home namespace */
   1.620 +    nslist[1] = &nsamigaother;
   1.621 +    nslist[2] = advertisetheworld ? &nsworld : &nsshared;
   1.622 +  }
   1.623 +  else {			/* anonymous user */
   1.624 +    nslist[0] = nslist[1] = NIL,nslist[2] = &nsftp;
   1.625 +    sprintf (tmp,"%s/INBOX",
   1.626 +	     home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
   1.627 +    sysInbox = cpystr (tmp);	/* make system INBOX */
   1.628 +    anonymous = T;		/* flag as anonymous */
   1.629 +  }
   1.630 +  myHomeDir = cpystr (home);	/* set home directory */
   1.631 +  if (!noautomaticsharedns) {
   1.632 +				/* #ftp namespace */
   1.633 +    if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
   1.634 +				/* #public namespace */
   1.635 +    if (!publicHome && (pw = getpwnam ("imappublic")))
   1.636 +      publicHome = cpystr (pw->pw_dir);
   1.637 +				/* #shared namespace */
   1.638 +    if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
   1.639 +      sharedHome = cpystr (pw->pw_dir);
   1.640 +  }
   1.641 +  if (!myLocalHost) mylocalhost ();
   1.642 +  if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
   1.643 +  if (!newsActive) newsActive = cpystr (ACTIVEFILE);
   1.644 +  if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
   1.645 +				/* force default prototype to be set */
   1.646 +  if (!createProto) createProto = &CREATEPROTO;
   1.647 +  if (!appendProto) appendProto = &EMPTYPROTO;
   1.648 +				/* re-do open action to get flags */
   1.649 +  (*createProto->dtb->open) (NIL);
   1.650 +  endpwent ();			/* close pw database */
   1.651 +  return T;
   1.652 +}
   1.653 + 
   1.654 +/* Return my user name
   1.655 + * Accepts: pointer to optional flags
   1.656 + * Returns: my user name
   1.657 + */
   1.658 +
   1.659 +char *myusername_full (unsigned long *flags)
   1.660 +{
   1.661 +  struct passwd *pw;
   1.662 +  struct stat sbuf;
   1.663 +  char *s;
   1.664 +  unsigned long euid;
   1.665 +  char *ret = UNLOGGEDUSER;
   1.666 +				/* no user name yet and not root? */
   1.667 +  if (!myUserName && (euid = geteuid ())) {
   1.668 +				/* yes, look up getlogin() user name or EUID */
   1.669 +    if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
   1.670 +	 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
   1.671 +	(pw = getpwuid (euid))) {
   1.672 +      if (block_env_init) {	/* don't env_init if blocked */
   1.673 +	if (flags) *flags = MU_LOGGEDIN;
   1.674 +	return pw->pw_name;
   1.675 +      }
   1.676 +      env_init (pw->pw_name,
   1.677 +		((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
   1.678 +		 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
   1.679 +		s : pw->pw_dir);
   1.680 +    }
   1.681 +    else fatal ("Unable to look up user name");
   1.682 +  }
   1.683 +  if (myUserName) {		/* logged in? */
   1.684 +    if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
   1.685 +    ret = myUserName;		/* return user name */
   1.686 +  }
   1.687 +  else if (flags) *flags = MU_NOTLOGGEDIN;
   1.688 +  return ret;
   1.689 +}
   1.690 +/* Return my local host name
   1.691 + * Returns: my local host name
   1.692 + */
   1.693 +
   1.694 +char *mylocalhost ()
   1.695 +{
   1.696 +  char tmp[MAILTMPLEN];
   1.697 +  struct hostent *host_name;
   1.698 +  if (!myLocalHost) myLocalHost = cpystr (gethostname (tmp,MAILTMPLEN-1) ?
   1.699 +					  "random-pc" : tcp_canonical (tmp));
   1.700 +  return myLocalHost;
   1.701 +}
   1.702 +
   1.703 +/* Return my home directory name
   1.704 + * Returns: my home directory name
   1.705 + */
   1.706 +
   1.707 +char *myhomedir ()
   1.708 +{
   1.709 +  if (!myHomeDir) myusername ();/* initialize if first time */
   1.710 +  return myHomeDir ? myHomeDir : "";
   1.711 +}
   1.712 +
   1.713 +
   1.714 +/* Return my home mailbox name
   1.715 + * Returns: my home directory name
   1.716 + */
   1.717 +
   1.718 +static char *mymailboxdir ()
   1.719 +{
   1.720 +  char *home = myhomedir ();
   1.721 +  if (!myMailboxDir && home) {	/* initialize if first time */
   1.722 +    if (mailsubdir) {
   1.723 +      char tmp[MAILTMPLEN];
   1.724 +      sprintf (tmp,"%s/%s",home,mailsubdir);
   1.725 +      myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
   1.726 +    }
   1.727 +    else myMailboxDir = cpystr (home);
   1.728 +  }
   1.729 +  return myMailboxDir ? myMailboxDir : "";
   1.730 +}
   1.731 +
   1.732 +
   1.733 +/* Return system standard INBOX
   1.734 + * Accepts: buffer string
   1.735 + */
   1.736 +
   1.737 +char *sysinbox ()
   1.738 +{
   1.739 +  char tmp[MAILTMPLEN];
   1.740 +  if (!sysInbox) {		/* initialize if first time */
   1.741 +    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
   1.742 +    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
   1.743 +  }
   1.744 +  return sysInbox;
   1.745 +}
   1.746 +
   1.747 +/* Return mailbox directory name
   1.748 + * Accepts: destination buffer
   1.749 + *	    directory prefix
   1.750 + *	    name in directory
   1.751 + * Returns: file name or NIL if error
   1.752 + */
   1.753 +
   1.754 +char *mailboxdir (char *dst,char *dir,char *name)
   1.755 +{
   1.756 +  char tmp[MAILTMPLEN];
   1.757 +  if (dir || name) {		/* if either argument provided */
   1.758 +    if (dir) {
   1.759 +      if (strlen (dir) > NETMAXMBX) return NIL;
   1.760 +      strcpy (tmp,dir);		/* write directory prefix */
   1.761 +    }
   1.762 +    else tmp[0] = '\0';		/* otherwise null string */
   1.763 +    if (name) {
   1.764 +      if (strlen (name) > NETMAXMBX) return NIL;
   1.765 +      strcat (tmp,name);	/* write name in directory */
   1.766 +    }
   1.767 +				/* validate name, return its name */
   1.768 +    if (!mailboxfile (dst,tmp)) return NIL;
   1.769 +  }
   1.770 +				/* no arguments, wants mailbox directory */
   1.771 +  else strcpy (dst,mymailboxdir ());
   1.772 +  return dst;			/* return the name */
   1.773 +}
   1.774 +
   1.775 +/* Return mailbox file name
   1.776 + * Accepts: destination buffer
   1.777 + *	    mailbox name
   1.778 + * Returns: file name or empty string for driver-selected INBOX or NIL if error
   1.779 + */
   1.780 +
   1.781 +char *mailboxfile (char *dst,char *name)
   1.782 +{
   1.783 +  struct passwd *pw;
   1.784 +  char *s;
   1.785 +  if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
   1.786 +      ((anonymous || restrictBox || (*name == '#')) &&
   1.787 +       (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
   1.788 +    dst = NIL;			/* invalid name */
   1.789 +  else switch (*name) {		/* determine mailbox type based upon name */
   1.790 +  case '#':			/* namespace name */
   1.791 +				/* #ftp/ namespace */
   1.792 +    if (((name[1] == 'f') || (name[1] == 'F')) &&
   1.793 +	((name[2] == 't') || (name[2] == 'T')) &&
   1.794 +	((name[3] == 'p') || (name[3] == 'P')) &&
   1.795 +	(name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
   1.796 +				/* #public/ and #shared/ namespaces */
   1.797 +    else if ((((name[1] == 'p') || (name[1] == 'P')) &&
   1.798 +	      ((name[2] == 'u') || (name[2] == 'U')) &&
   1.799 +	      ((name[3] == 'b') || (name[3] == 'B')) &&
   1.800 +	      ((name[4] == 'l') || (name[4] == 'L')) &&
   1.801 +	      ((name[5] == 'i') || (name[5] == 'I')) &&
   1.802 +	      ((name[6] == 'c') || (name[6] == 'C')) &&
   1.803 +	      (name[7] == '/') && (s = publicHome)) ||
   1.804 +	     (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
   1.805 +	      ((name[2] == 'h') || (name[2] == 'H')) &&
   1.806 +	      ((name[3] == 'a') || (name[3] == 'A')) &&
   1.807 +	      ((name[4] == 'r') || (name[4] == 'R')) &&
   1.808 +	      ((name[5] == 'e') || (name[5] == 'E')) &&
   1.809 +	      ((name[6] == 'd') || (name[6] == 'D')) &&
   1.810 +	      (name[7] == '/') && (s = sharedHome)))
   1.811 +      sprintf (dst,"%s/%s",s,compare_cstring (name,"INBOX") ? name : "INBOX");
   1.812 +    else dst = NIL;		/* unknown namespace */
   1.813 +    break;
   1.814 +
   1.815 +  case '/':			/* root access */
   1.816 +    if (anonymous) dst = NIL;	/* anonymous forbidden to do this */
   1.817 +    else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
   1.818 +      dst = NIL;		/* restricted and not access to sysinbox */
   1.819 +    else strcpy (dst,name);	/* unrestricted, copy root name */
   1.820 +    break;
   1.821 +  case '~':			/* other user access */
   1.822 +				/* bad syntax or anonymous can't win */
   1.823 +    if (!*++name || anonymous) dst = NIL;
   1.824 +				/* ~/ equivalent to ordinary name */
   1.825 +    else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
   1.826 +				/* other user forbidden if restricted */
   1.827 +    else if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
   1.828 +    else {			/* clear box other user */
   1.829 +				/* copy user name */
   1.830 +      for (s = dst; *name && (*name != '/'); *s++ = *name++);
   1.831 +      *s++ = '\0';		/* tie off user name, look up in passwd file */
   1.832 +      if ((pw = getpwnam (dst)) && pw->pw_dir) {
   1.833 +	if (*name) name++;	/* skip past the slash */
   1.834 +				/* canonicalize case of INBOX */
   1.835 +	if (!compare_cstring (name,"INBOX")) name = "INBOX";
   1.836 +				/* remove trailing / from directory */
   1.837 +	if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
   1.838 +				/* don't allow ~root/ if restricted root */
   1.839 +	if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
   1.840 +				/* build final name w/ subdir if needed */
   1.841 +	else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
   1.842 +	else sprintf (dst,"%s/%s",pw->pw_dir,name);
   1.843 +      }
   1.844 +      else dst = NIL;		/* no such user */
   1.845 +    }
   1.846 +    break;
   1.847 +  case 'I': case 'i':		/* possible INBOX */
   1.848 +    if (!compare_cstring (name+1,"NBOX")) {
   1.849 +				/* if anonymous, use INBOX in mailbox dir */
   1.850 +      if (anonymous) sprintf (dst,"%s/INBOX",mymailboxdir ());
   1.851 +      else *dst = '\0';		/* otherwise driver selects the name */
   1.852 +      break;
   1.853 +    }
   1.854 +				/* drop into to ordinary name case */
   1.855 +  default:			/* ordinary name is easy */
   1.856 +    sprintf (dst,"%s/%s",mymailboxdir (),name);
   1.857 +    break;
   1.858 +  }
   1.859 +  return dst;			/* return final name */
   1.860 +}
   1.861 +
   1.862 +/* Dot-lock file locker
   1.863 + * Accepts: file name to lock
   1.864 + *	    destination buffer for lock file name
   1.865 + *	    open file description on file name to lock
   1.866 + * Returns: T if success, NIL if failure
   1.867 + */
   1.868 +
   1.869 +long dotlock_lock (char *file,DOTLOCK *base,int fd)
   1.870 +{
   1.871 +  int i = locktimeout * 60;
   1.872 +  int j,mask,retry,pi[2],po[2];
   1.873 +  char *s,tmp[MAILTMPLEN];
   1.874 +  struct stat sb;
   1.875 +				/* flush absurd file name */
   1.876 +  if (strlen (file) > 512) return NIL;
   1.877 +				/* build lock filename */
   1.878 +  sprintf (base->lock,"%s.lock",file);
   1.879 +				/* assume no pipe */
   1.880 +  base->pipei = base->pipeo = -1;
   1.881 +  do {				/* make sure not symlink */
   1.882 +    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
   1.883 +				/* time out if file older than 5 minutes */
   1.884 +    if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
   1.885 +				/* try to create the lock */
   1.886 +    if ((j = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) lock_protection)) >= 0) {
   1.887 +      close (i);		/* make the file, now close it */
   1.888 +      chmod (base->lock,(int) lock_protection);
   1.889 +      return LONGT;
   1.890 +    }
   1.891 +    if (errno == EEXIST) {	/* already locked? */
   1.892 +      retry = -1;		/* can try again */
   1.893 +      if (!(i%15)) {		/* time to notify? */
   1.894 +	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
   1.895 +		 file,i);
   1.896 +	mm_log (tmp,WARN);
   1.897 +      }
   1.898 +      sleep (1);		/* wait 1 second before next try */
   1.899 +    }
   1.900 +    else retry = i = 0;		/* hard failure, no more retries */
   1.901 +  } while (i--);		/* until out of retries */
   1.902 +  if (retry < 0) {		/* still returning retry after locktimeout? */
   1.903 +    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
   1.904 +    if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
   1.905 +      sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
   1.906 +	       (long) (time (0) - sb.st_ctime));
   1.907 +      mm_log (tmp,WARN);
   1.908 +    }
   1.909 +    mask = umask (0);
   1.910 +    unlink (base->lock);	/* try to remove the old file */
   1.911 +				/* seize the lock */
   1.912 +    if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) lock_protection)) >= 0) {
   1.913 +      close (i);		/* don't need descriptor any more */
   1.914 +      sprintf (tmp,"Mailbox %.80s lock overridden",file);
   1.915 +      mm_log (tmp,NIL);
   1.916 +      chmod (base->lock,(int) lock_protection);
   1.917 +      umask (mask)		/* restore old umask */
   1.918 +      return LONGT;
   1.919 +    }
   1.920 +    umask (mask)		/* restore old umask */
   1.921 +  }
   1.922 +
   1.923 +  if (fd >= 0) switch (errno) {
   1.924 +  case EACCES:			/* protection failure? */
   1.925 +				/* make command pipes */
   1.926 +    if (!stat (LOCKPGM,&sb) && (pipe (pi) >= 0)) {
   1.927 +				/* if input pipes usable create output pipes */
   1.928 +      if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
   1.929 +				/* make sure output pipes are usable */
   1.930 +	if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
   1.931 +				/* all is good, make inferior process */
   1.932 +	else if (!(j = fork ())) {
   1.933 +	  if (!fork ()) {	/* make grandchild so it's inherited by init */
   1.934 +	    long cf;		/* don't change caller vars in case vfork() */
   1.935 +	    char *argv[4],arg[20];
   1.936 +				/* prepare argument vector */
   1.937 +	    sprintf (arg,"%d",fd);
   1.938 +	    argv[0] = LOCKPGM; argv[1] = arg;
   1.939 +	    argv[2] = file; argv[3] = NIL;
   1.940 +				/* set parent's I/O to my O/I */
   1.941 +	    dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
   1.942 +				/* close all unnecessary descriptors */
   1.943 +	    for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
   1.944 +		 cf >= 3; --cf) if (cf != fd) close (cf);
   1.945 +				/* be our own process group */
   1.946 +	    setpgrp (0,getpid ());
   1.947 +				/* now run it */
   1.948 +	    _exit (execv (argv[0],argv));
   1.949 +	  }
   1.950 +	  _exit (1);		/* child is done */
   1.951 +	}
   1.952 +	else if (j > 0) {	/* parent process */
   1.953 +	  fd_set rfd;
   1.954 +	  struct timeval tmo;
   1.955 +	  FD_ZERO (&rfd);
   1.956 +	  FD_SET (pi[0],&rfd);
   1.957 +	  tmo.tv_sec = locktimeout * 60;
   1.958 +	  grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
   1.959 +				/* read response from locking program */
   1.960 +	  if (select (pi[0]+1,&rfd,0,0,&tmo) &&
   1.961 +	      (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
   1.962 +				/* success, record pipes */
   1.963 +	    base->pipei = pi[0]; base->pipeo = po[1];
   1.964 +				/* close child's side of the pipes */
   1.965 +	    close (pi[1]); close (po[0]);
   1.966 +	    return LONGT;
   1.967 +	  }
   1.968 +	}
   1.969 +	close (po[0]); close (po[1]);
   1.970 +      }
   1.971 +      close (pi[0]); close (pi[1]);
   1.972 +    }
   1.973 +				/* find directory/file delimiter */
   1.974 +    if (s = strrchr (base->lock,'/')) {
   1.975 +      *s = '\0';		/* tie off at directory */
   1.976 +      sprintf(tmp,		/* generate default message */
   1.977 +	      "Mailbox vulnerable - directory %.80s must have 1777 protection",
   1.978 +	      base->lock);
   1.979 +				/* definitely not 1777 if can't stat */
   1.980 +      mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
   1.981 +      *s = '/';			/* restore lock name */
   1.982 +      if (mask != 1777) {	/* default warning if not 1777 */
   1.983 +	MM_LOG (tmp,WARN);
   1.984 +	break;
   1.985 +      }
   1.986 +    }
   1.987 +  default:
   1.988 +    sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
   1.989 +	     base->lock,strerror (errno));
   1.990 +    mm_log (tmp,WARN);		/* this is probably not good */
   1.991 +    break;
   1.992 +  }
   1.993 +  base->lock[0] = '\0';		/* don't use lock files */
   1.994 +  return NIL;
   1.995 +}
   1.996 +
   1.997 +/* Dot-lock file unlocker
   1.998 + * Accepts: lock file name
   1.999 + * Returns: T if success, NIL if failure
  1.1000 + */
  1.1001 +
  1.1002 +long dotlock_unlock (DOTLOCK *base)
  1.1003 +{
  1.1004 +  long ret = LONGT;
  1.1005 +  if (base && base->lock[0]) {
  1.1006 +    if (base->pipei >= 0) {	/* if running through a pipe unlocker */
  1.1007 +      ret = (write (base->pipeo,"+",1) == 1);
  1.1008 +				/* nuke the pipes */
  1.1009 +      close (base->pipei); close (base->pipeo);
  1.1010 +    }
  1.1011 +    else ret = !unlink (base->lock);
  1.1012 +  }
  1.1013 +  return ret;
  1.1014 +}
  1.1015 +
  1.1016 +/* Lock file name
  1.1017 + * Accepts: scratch buffer
  1.1018 + *	    file name
  1.1019 + *	    type of locking operation (LOCK_SH or LOCK_EX)
  1.1020 + *	    pointer to return PID of locker
  1.1021 + * Returns: file descriptor of lock or negative if error
  1.1022 + */
  1.1023 +
  1.1024 +int lockname (char *lock,char *fname,int op,long *pid)
  1.1025 +{
  1.1026 +  struct stat sbuf;
  1.1027 +  *pid = 0;			/* no locker PID */
  1.1028 +  return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
  1.1029 +}
  1.1030 +
  1.1031 +
  1.1032 +/* Lock file descriptor
  1.1033 + * Accepts: file descriptor
  1.1034 + *	    lock file name buffer
  1.1035 + *	    type of locking operation (LOCK_SH or LOCK_EX)
  1.1036 + * Returns: file descriptor of lock or negative if error
  1.1037 + */
  1.1038 +
  1.1039 +int lockfd (int fd,char *lock,int op)
  1.1040 +{
  1.1041 +  struct stat sbuf;
  1.1042 +  return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
  1.1043 +}
  1.1044 +
  1.1045 +/* Lock file name worker
  1.1046 + * Accepts: lock file name
  1.1047 + *	    pointer to stat() buffer
  1.1048 + *	    type of locking operation (LOCK_SH or LOCK_EX)
  1.1049 + *	    pointer to return PID of locker
  1.1050 + * Returns: file descriptor of lock or negative if error
  1.1051 + */
  1.1052 +
  1.1053 +int lock_work (char *lock,void *sb,int op,long *pid)
  1.1054 +{
  1.1055 +  struct stat lsb,fsb;
  1.1056 +  struct stat *sbuf = (struct stat *) sb;
  1.1057 +  char tmp[MAILTMPLEN];
  1.1058 +  long i;
  1.1059 +  int fd;
  1.1060 +  int mask = umask (0);
  1.1061 +  if (pid) *pid = 0;		/* initialize return PID */
  1.1062 +				/* make temporary lock file name */
  1.1063 +  sprintf (lock,"%s/.%lx.%lx","/tmp",
  1.1064 +	   (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
  1.1065 +  while (T) {			/* until get a good lock */
  1.1066 +    do switch ((int) chk_notsymlink (lock,&lsb)) {
  1.1067 +    case 1:			/* exists just once */
  1.1068 +      if (((fd = open (lock,O_RDWR,lock_protection)) >= 0) ||
  1.1069 +	  (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
  1.1070 +    case -1:			/* name doesn't exist */
  1.1071 +      fd = open (lock,O_RDWR|O_CREAT|O_EXCL,lock_protection);
  1.1072 +      break;
  1.1073 +    default:			/* multiple hard links */
  1.1074 +      mm_log ("hard link to lock name",ERROR);
  1.1075 +      syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
  1.1076 +    case 0:			/* symlink (already did syslog) */
  1.1077 +      umask (mask);		/* restore old mask */
  1.1078 +      return -1;		/* fail: no lock file */
  1.1079 +    } while ((fd < 0) && (errno == EEXIST));
  1.1080 +    if (fd < 0) {		/* failed to get file descriptor */
  1.1081 +      syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
  1.1082 +	      strerror (errno));
  1.1083 +      if (stat ("/tmp",&lsb))
  1.1084 +	syslog (LOG_CRIT,"SYSTEM ERROR: no /tmp: %s",strerror (errno));
  1.1085 +      else if ((lsb.st_mode & 01777) != 01777)
  1.1086 +	mm_log ("Can't lock for write: /tmp must have 1777 protection",WARN);
  1.1087 +      umask (mask);		/* restore old mask */
  1.1088 +      return -1;		/* fail: can't open lock file */
  1.1089 +    }
  1.1090 +
  1.1091 +				/* non-blocking form */
  1.1092 +    if (op & LOCK_NB) i = flock (fd,op);
  1.1093 +    else {			/* blocking form */
  1.1094 +      (*mailblocknotify) (BLOCK_FILELOCK,NIL);
  1.1095 +      i = flock (fd,op);
  1.1096 +      (*mailblocknotify) (BLOCK_NONE,NIL);
  1.1097 +    }
  1.1098 +    if (i) {			/* failed, get other process' PID */
  1.1099 +      if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
  1.1100 +	  (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
  1.1101 +	*pid = i;
  1.1102 +      close (fd);		/* failed, give up on lock */
  1.1103 +      umask (mask);		/* restore old mask */
  1.1104 +      return -1;		/* fail: can't lock */
  1.1105 +    }
  1.1106 +				/* make sure this lock is good for us */
  1.1107 +    if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
  1.1108 +	!fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
  1.1109 +	(lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
  1.1110 +    close (fd);			/* lock not right, drop fd and try again */
  1.1111 +  }
  1.1112 +				/* make sure mode OK (don't use fchmod()) */
  1.1113 +  chmod (lock,(int) lock_protection);
  1.1114 +  umask (mask);			/* restore old mask */
  1.1115 +  return fd;			/* success */
  1.1116 +}
  1.1117 +
  1.1118 +/* Check to make sure not a symlink
  1.1119 + * Accepts: file name
  1.1120 + *	    stat buffer
  1.1121 + * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
  1.1122 + */
  1.1123 +
  1.1124 +long chk_notsymlink (char *name,void *sb)
  1.1125 +{
  1.1126 +  struct stat *sbuf = (struct stat *) sb;
  1.1127 +				/* name exists? */
  1.1128 +  if (lstat (name,sbuf)) return -1;
  1.1129 +				/* forbid symbolic link */
  1.1130 +  if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
  1.1131 +    mm_log ("symbolic link on lock name",ERROR);
  1.1132 +    syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
  1.1133 +	    name);
  1.1134 +    return NIL;
  1.1135 +  }
  1.1136 +  return (long) sbuf->st_nlink;	/* return number of hard links */
  1.1137 +}
  1.1138 +
  1.1139 +
  1.1140 +/* Unlock file descriptor
  1.1141 + * Accepts: file descriptor
  1.1142 + *	    lock file name from lockfd()
  1.1143 + */
  1.1144 +
  1.1145 +void unlockfd (int fd,char *lock)
  1.1146 +{
  1.1147 +				/* delete the file if no sharers */
  1.1148 +  if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
  1.1149 +  flock (fd,LOCK_UN);		/* unlock it */
  1.1150 +  close (fd);			/* close it */
  1.1151 +}
  1.1152 +
  1.1153 +/* Set proper file protection for mailbox
  1.1154 + * Accepts: mailbox name
  1.1155 + *	    actual file path name
  1.1156 + * Returns: T, always
  1.1157 + */
  1.1158 +
  1.1159 +long set_mbx_protections (char *mailbox,char *path)
  1.1160 +{
  1.1161 +  struct stat sbuf;
  1.1162 +  int mode = (int) mbx_protection;
  1.1163 +  if (*mailbox == '#') {	/* possible namespace? */
  1.1164 +      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
  1.1165 +	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
  1.1166 +	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
  1.1167 +	  (mailbox[4] == '/')) mode = (int) ftp_protection;
  1.1168 +      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
  1.1169 +	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
  1.1170 +	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
  1.1171 +	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
  1.1172 +	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
  1.1173 +	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
  1.1174 +	       (mailbox[7] == '/')) mode = (int) public_protection;
  1.1175 +      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
  1.1176 +	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
  1.1177 +	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
  1.1178 +	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
  1.1179 +	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
  1.1180 +	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
  1.1181 +	       (mailbox[7] == '/')) mode = (int) shared_protection;
  1.1182 +  }
  1.1183 +				/* if a directory */
  1.1184 +  if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
  1.1185 +				/* set owner search if allow read or write */
  1.1186 +    if (mode & 0600) mode |= 0100;
  1.1187 +    if (mode & 060) mode |= 010;/* set group search if allow read or write */
  1.1188 +    if (mode & 06) mode |= 01;	/* set world search if allow read or write */
  1.1189 +				/* preserve directory SGID bit */
  1.1190 +    if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
  1.1191 +  }
  1.1192 +  chmod (path,mode);		/* set the new protection, ignore failure */
  1.1193 +  return LONGT;
  1.1194 +}
  1.1195 +
  1.1196 +/* Get proper directory protection
  1.1197 + * Accepts: mailbox name
  1.1198 + * Returns: directory mode, always
  1.1199 + */
  1.1200 +
  1.1201 +long get_dir_protection (char *mailbox)
  1.1202 +{
  1.1203 +  if (*mailbox == '#') {	/* possible namespace? */
  1.1204 +      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
  1.1205 +	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
  1.1206 +	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
  1.1207 +	  (mailbox[4] == '/')) return ftp_dir_protection;
  1.1208 +      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
  1.1209 +	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
  1.1210 +	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
  1.1211 +	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
  1.1212 +	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
  1.1213 +	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
  1.1214 +	       (mailbox[7] == '/')) return public_dir_protection;
  1.1215 +      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
  1.1216 +	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
  1.1217 +	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
  1.1218 +	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
  1.1219 +	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
  1.1220 +	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
  1.1221 +	       (mailbox[7] == '/')) return shared_dir_protection;
  1.1222 +  }
  1.1223 +  return dir_protection;
  1.1224 +}
  1.1225 +
  1.1226 +/* Determine default prototype stream to user
  1.1227 + * Accepts: type (NIL for create, T for append)
  1.1228 + * Returns: default prototype stream
  1.1229 + */
  1.1230 +
  1.1231 +MAILSTREAM *default_proto (long type)
  1.1232 +{
  1.1233 +  myusername ();		/* make sure initialized */
  1.1234 +				/* return default driver's prototype */
  1.1235 +  return type ? appendProto : createProto;
  1.1236 +}
  1.1237 +
  1.1238 +
  1.1239 +/* Set up user flags for stream
  1.1240 + * Accepts: MAIL stream
  1.1241 + * Returns: MAIL stream with user flags set up
  1.1242 + */
  1.1243 +
  1.1244 +MAILSTREAM *user_flags (MAILSTREAM *stream)
  1.1245 +{
  1.1246 +  int i;
  1.1247 +  myusername ();		/* make sure initialized */
  1.1248 +  for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
  1.1249 +    if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
  1.1250 +  return stream;
  1.1251 +}
  1.1252 +
  1.1253 +
  1.1254 +/* Return nth user flag
  1.1255 + * Accepts: user flag number
  1.1256 + * Returns: flag
  1.1257 + */
  1.1258 +
  1.1259 +char *default_user_flag (unsigned long i)
  1.1260 +{
  1.1261 +  myusername ();		/* make sure initialized */
  1.1262 +  return userFlags[i];
  1.1263 +}
  1.1264 +
  1.1265 +/* Default block notify routine
  1.1266 + * Accepts: reason for calling
  1.1267 + *	    data
  1.1268 + * Returns: data
  1.1269 + */
  1.1270 +
  1.1271 +void *mm_blocknotify (int reason,void *data)
  1.1272 +{
  1.1273 +  void *ret = data;
  1.1274 +  switch (reason) {
  1.1275 +  case BLOCK_SENSITIVE:		/* entering sensitive code */
  1.1276 +    ret = (void *) alarm (0);
  1.1277 +    break;
  1.1278 +  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
  1.1279 +    if ((unsigned int) data) alarm ((unsigned int) data);
  1.1280 +    break;
  1.1281 +  default:			/* ignore all other reasons */
  1.1282 +    break;
  1.1283 +  }
  1.1284 +  return ret;
  1.1285 +}

UW-IMAP'd extensions by yuuji