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 +}