imapext-2007

annotate src/osdep/unix/env_unix.c @ 4:d741b3ecc917

imapext-2007f
author HIROSE Yuuji <yuuji@gentei.org>
date Thu, 30 Oct 2014 00:03:05 +0900
parents 2366b362676d
children
rev   line source
yuuji@0 1 /* ========================================================================
yuuji@0 2 * Copyright 1988-2008 University of Washington
yuuji@0 3 *
yuuji@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
yuuji@0 5 * you may not use this file except in compliance with the License.
yuuji@0 6 * You may obtain a copy of the License at
yuuji@0 7 *
yuuji@0 8 * http://www.apache.org/licenses/LICENSE-2.0
yuuji@0 9 *
yuuji@0 10 *
yuuji@0 11 * ========================================================================
yuuji@0 12 */
yuuji@0 13
yuuji@0 14 /*
yuuji@0 15 * Program: UNIX environment routines
yuuji@0 16 *
yuuji@0 17 * Author: Mark Crispin
yuuji@0 18 * UW Technology
yuuji@0 19 * University of Washington
yuuji@0 20 * Seattle, WA 98195
yuuji@0 21 * Internet: MRC@Washington.EDU
yuuji@0 22 *
yuuji@0 23 * Date: 1 August 1988
yuuji@3 24 * Last Edited: 23 February 2009
yuuji@0 25 */
yuuji@0 26
yuuji@0 27 #include <grp.h>
yuuji@0 28 #include <signal.h>
yuuji@0 29 #include <sys/wait.h>
yuuji@0 30
yuuji@0 31
yuuji@0 32 /* in case stat.h is ancient */
yuuji@0 33
yuuji@0 34 #ifndef S_IRUSR
yuuji@0 35 #define S_IRUSR S_IREAD
yuuji@0 36 #endif
yuuji@0 37 #ifndef S_IWUSR
yuuji@0 38 #define S_IWUSR S_IWRITE
yuuji@0 39 #endif
yuuji@0 40 #ifndef S_IXUSR
yuuji@0 41 #define S_IXUSR S_IEXEC
yuuji@0 42 #endif
yuuji@0 43 #ifndef S_IRGRP
yuuji@0 44 #define S_IRGRP (S_IREAD >> 3)
yuuji@0 45 #endif
yuuji@0 46 #ifndef S_IWGRP
yuuji@0 47 #define S_IWGRP (S_IWRITE >> 3)
yuuji@0 48 #endif
yuuji@0 49 #ifndef S_IXGRP
yuuji@0 50 #define S_IXGRP (S_IEXEC >> 3)
yuuji@0 51 #endif
yuuji@0 52 #ifndef S_IROTH
yuuji@0 53 #define S_IROTH (S_IREAD >> 6)
yuuji@0 54 #endif
yuuji@0 55 #ifndef S_IWOTH
yuuji@0 56 #define S_IWOTH (S_IWRITE >> 6)
yuuji@0 57 #endif
yuuji@0 58 #ifndef S_IXOTH
yuuji@0 59 #define S_IXOTH (S_IEXEC >> 6)
yuuji@0 60 #endif
yuuji@0 61
yuuji@0 62 /* c-client environment parameters */
yuuji@0 63
yuuji@0 64 static char *myUserName = NIL; /* user name */
yuuji@0 65 static char *myHomeDir = NIL; /* home directory name */
yuuji@0 66 static char *myServerName = NIL;/* server name */
yuuji@0 67 static char *myLocalHost = NIL; /* local host name */
yuuji@0 68 static char *myNewsrc = NIL; /* newsrc file name */
yuuji@0 69 static char *mailsubdir = NIL; /* mailbox subdirectory name */
yuuji@0 70 static char *sysInbox = NIL; /* system inbox name */
yuuji@0 71 static char *newsActive = NIL; /* news active file */
yuuji@0 72 static char *newsSpool = NIL; /* news spool */
yuuji@0 73 static char *blackBoxDir = NIL; /* black box directory name */
yuuji@0 74 /* black box default home directory */
yuuji@0 75 static char *blackBoxDefaultHome = NIL;
yuuji@0 76 static char *sslCApath = NIL; /* non-standard CA path */
yuuji@0 77 static short anonymous = NIL; /* is anonymous */
yuuji@0 78 static short blackBox = NIL; /* is a black box */
yuuji@0 79 static short closedBox = NIL; /* is a closed box (uses chroot() jail) */
yuuji@0 80 static short restrictBox = NIL; /* is a restricted box */
yuuji@0 81 static short has_no_life = NIL; /* is a cretin with no life */
yuuji@0 82 /* block environment init */
yuuji@0 83 static short block_env_init = NIL;
yuuji@0 84 static short hideDotFiles = NIL;/* hide files whose names start with . */
yuuji@0 85 /* advertise filesystem root */
yuuji@0 86 static short advertisetheworld = NIL;
yuuji@0 87 /* only advertise own mailboxes and #shared */
yuuji@0 88 static short limitedadvertise = NIL;
yuuji@0 89 /* disable automatic shared namespaces */
yuuji@0 90 static short noautomaticsharedns = NIL;
yuuji@0 91 static short no822tztext = NIL; /* disable RFC [2]822 timezone text */
yuuji@0 92 /* client principals include service name */
yuuji@0 93 static short kerb_cp_svr_name = NIL;
yuuji@0 94 static long locktimeout = 5; /* default lock timeout in minutes */
yuuji@0 95 /* default prototypes */
yuuji@0 96 static MAILSTREAM *createProto = NIL;
yuuji@0 97 static MAILSTREAM *appendProto = NIL;
yuuji@0 98 /* default user flags */
yuuji@0 99 static char *userFlags[NUSERFLAGS] = {NIL};
yuuji@0 100 static NAMESPACE *nslist[3]; /* namespace list */
yuuji@0 101 static int logtry = 3; /* number of server login tries */
yuuji@0 102 /* block notification */
yuuji@0 103 static blocknotify_t mailblocknotify = mm_blocknotify;
yuuji@0 104 /* logout function */
yuuji@0 105 static logouthook_t maillogouthook = NIL;
yuuji@0 106 /* logout data */
yuuji@0 107 static void *maillogoutdata = NIL;
yuuji@0 108 /* allow user config files */
yuuji@0 109 static short allowuserconfig = NIL;
yuuji@0 110 /* 1 = disable plaintext, 2 = if not SSL */
yuuji@0 111 static long disablePlaintext = NIL;
yuuji@0 112 static long list_max_level = 20;/* maximum level of list recursion */
yuuji@0 113 /* facility for syslog */
yuuji@0 114 static int syslog_facility = LOG_MAIL;
yuuji@0 115
yuuji@0 116 /* Path of the privileged system lock program (mlock). Normally set by
yuuji@0 117 * logic test.
yuuji@0 118 */
yuuji@0 119
yuuji@0 120 static char *lockpgm = LOCKPGM;
yuuji@0 121
yuuji@0 122 /* Directory used for shared locks. MUST be the same for all users of the
yuuji@0 123 * system, and MUST be protected 1777. /var/tmp may be preferable on some
yuuji@0 124 * systems.
yuuji@0 125 */
yuuji@0 126
yuuji@0 127 static const char *tmpdir = "/tmp";
yuuji@0 128
yuuji@0 129 /* Do not change shlock_mode. Doing so can cause mailbox corruption and
yuuji@0 130 * denial of service. It also defeats the entire purpose of the shared
yuuji@0 131 * lock mechanism. The right way to avoid shared locks is to set up a
yuuji@0 132 * closed box (see the closedBox setting).
yuuji@0 133 */
yuuji@0 134
yuuji@0 135 /* shared lock mode */
yuuji@0 136 static const int shlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
yuuji@0 137
yuuji@0 138
yuuji@0 139 /* It is STRONGLY recommended that you do not change dotlock_mode. Doing so
yuuji@0 140 * can cause denial of service with old dot-lock files left lying around.
yuuji@0 141 * However, since dot-locks are only used with traditional UNIX and MMDF
yuuji@0 142 * formats which are not normally shared, it is much less harmful to tamper
yuuji@0 143 * with this than with shlock_mode.
yuuji@0 144 */
yuuji@0 145
yuuji@0 146 /* dot-lock mode */
yuuji@0 147 static long dotlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
yuuji@0 148
yuuji@0 149 /* File/directory access and protection policies */
yuuji@0 150
yuuji@0 151 /* Unlike shlock_mode, the ????_protection modes are intended to be fully
yuuji@0 152 * customizable according to site policy. The values here are recommended
yuuji@0 153 * settings, based upon the documented purposes of the namespaces.
yuuji@0 154 */
yuuji@0 155
yuuji@0 156 /* user space - only owner can read/write */
yuuji@0 157 static char *myMailboxDir = NIL;/* user space directory name */
yuuji@0 158 /* default file protection */
yuuji@0 159 static long mbx_protection = S_IRUSR|S_IWUSR;
yuuji@0 160 /* default directory protection */
yuuji@0 161 static long dir_protection = S_IRUSR|S_IWUSR|S_IXUSR;
yuuji@0 162
yuuji@0 163 /* user space for user "anonymous" */
yuuji@0 164 /* anonymous home directory */
yuuji@0 165 static char *anonymousHome = NIL;
yuuji@0 166
yuuji@0 167 /* #ftp - everybody can read, only owner can write */
yuuji@0 168 static char *ftpHome = NIL; /* ftp export home directory */
yuuji@0 169 /* default ftp file protection */
yuuji@0 170 static long ftp_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
yuuji@0 171 static long ftp_dir_protection =/* default ftp directory protection */
yuuji@0 172 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
yuuji@0 173
yuuji@0 174 /* #public - everybody can read/write */
yuuji@0 175 static char *publicHome = NIL; /* public home directory */
yuuji@0 176 static long public_protection = /* default public file protection */
yuuji@0 177 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
yuuji@0 178 /* default public directory protection */
yuuji@0 179 static long public_dir_protection =
yuuji@0 180 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
yuuji@0 181
yuuji@0 182 /* #shared/ - owner and group members can read/write */
yuuji@0 183 static char *sharedHome = NIL; /* shared home directory */
yuuji@0 184 /* default shared file protection */
yuuji@0 185 static long shared_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
yuuji@0 186 /* default shared directory protection */
yuuji@0 187 static long shared_dir_protection =
yuuji@0 188 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP;
yuuji@0 189
yuuji@0 190 /* OS bug workarounds - should be avoided at all cost */
yuuji@0 191
yuuji@0 192
yuuji@0 193 /* Don't set fcntlhangbug unless you really have to, since it risks mailbox
yuuji@0 194 * corruption. The flocksim.c mechanism is designed to detect NFS access
yuuji@0 195 * and no-op in that cases only, so this flag should be unnecessary.
yuuji@0 196 */
yuuji@0 197
yuuji@0 198 static short fcntlhangbug = NIL;/* flock() emulator using fcntl() is a no-op */
yuuji@0 199
yuuji@0 200
yuuji@0 201 /* Don't set netfsstatbug unless you really have to, since it dramatically
yuuji@0 202 * slows down traditional UNIX and MMDF mailbox performance.
yuuji@0 203 */
yuuji@0 204
yuuji@0 205 static short netfsstatbug = NIL;/* compensate for broken stat() on network
yuuji@0 206 * filesystems (AFS and old NFS)
yuuji@0 207 */
yuuji@0 208
yuuji@0 209
yuuji@0 210 /* Note: setting disableLockWarning means that you assert that the
yuuji@0 211 * so-modified copy of this software will NEVER be used:
yuuji@0 212 * 1) in conjunction with any software which expects .lock files
yuuji@0 213 * 2) to access NFS-mounted files and directories
yuuji@0 214 *
yuuji@0 215 * Unless both of these conditions apply, then do not set this flag.
yuuji@0 216 * Instead, read the FAQ (item 7.10) and either use 1777 protection
yuuji@0 217 * on the mail spool, or install mlock.
yuuji@0 218 *
yuuji@0 219 * In addition, by setting this flag you also agree that you are fully
yuuji@0 220 * legally and morally responsible when (not if) mail files are damaged
yuuji@0 221 * as the result of your choice.
yuuji@0 222 *
yuuji@0 223 * The mlock tool exists for a reason. Use it.
yuuji@0 224 */
yuuji@0 225 /* disable warning if can't make .lock file */
yuuji@0 226 static short disableLockWarning = NIL;
yuuji@0 227
yuuji@0 228 /* UNIX Namespaces */
yuuji@0 229
yuuji@0 230 /* personal mh namespace */
yuuji@0 231 static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
yuuji@0 232 static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
yuuji@0 233 /* home namespace */
yuuji@0 234 static NAMESPACE nshome = {"",'/',NIL,&nsmh};
yuuji@0 235 /* UNIX other user namespace */
yuuji@0 236 static NAMESPACE nsunixother = {"~",'/',NIL,NIL};
yuuji@0 237 /* black box other user namespace */
yuuji@0 238 static NAMESPACE nsblackother = {"/",'/',NIL,NIL};
yuuji@0 239 /* public (anonymous OK) namespace */
yuuji@0 240 static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
yuuji@0 241 /* netnews namespace */
yuuji@0 242 static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
yuuji@0 243 /* FTP export namespace */
yuuji@0 244 static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
yuuji@0 245 /* shared (no anonymous) namespace */
yuuji@0 246 static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
yuuji@0 247 /* world namespace */
yuuji@0 248 static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
yuuji@0 249 /* only shared and public namespaces */
yuuji@0 250 static NAMESPACE nslimited = {"#shared/",'/',NIL,&nspublic};
yuuji@0 251
yuuji@0 252
yuuji@0 253
yuuji@0 254 #include "write.c" /* include safe writing routines */
yuuji@0 255 #include "crexcl.c" /* include exclusive create */
yuuji@0 256 #include "pmatch.c" /* include wildcard pattern matcher */
yuuji@0 257
yuuji@0 258 /* Get all authenticators */
yuuji@0 259
yuuji@0 260 #include "auths.c"
yuuji@0 261
yuuji@0 262 /* Environment manipulate parameters
yuuji@0 263 * Accepts: function code
yuuji@0 264 * function-dependent value
yuuji@0 265 * Returns: function-dependent return value
yuuji@0 266 */
yuuji@0 267
yuuji@0 268 void *env_parameters (long function,void *value)
yuuji@0 269 {
yuuji@0 270 void *ret = NIL;
yuuji@0 271 switch ((int) function) {
yuuji@0 272 case GET_NAMESPACE:
yuuji@0 273 ret = (void *) nslist;
yuuji@0 274 break;
yuuji@0 275 case SET_USERNAME:
yuuji@0 276 if (myUserName) fs_give ((void **) &myUserName);
yuuji@0 277 myUserName = cpystr ((char *) value);
yuuji@0 278 case GET_USERNAME:
yuuji@0 279 ret = (void *) myUserName;
yuuji@0 280 break;
yuuji@0 281 case SET_HOMEDIR:
yuuji@0 282 if (myHomeDir) fs_give ((void **) &myHomeDir);
yuuji@0 283 myHomeDir = cpystr ((char *) value);
yuuji@0 284 case GET_HOMEDIR:
yuuji@0 285 ret = (void *) myHomeDir;
yuuji@0 286 break;
yuuji@0 287 case SET_LOCALHOST:
yuuji@0 288 if (myLocalHost) fs_give ((void **) &myLocalHost);
yuuji@0 289 myLocalHost = cpystr ((char *) value);
yuuji@0 290 case GET_LOCALHOST:
yuuji@0 291 ret = (void *) myLocalHost;
yuuji@0 292 break;
yuuji@0 293 case SET_NEWSRC:
yuuji@0 294 if (myNewsrc) fs_give ((void **) &myNewsrc);
yuuji@0 295 myNewsrc = cpystr ((char *) value);
yuuji@0 296 case GET_NEWSRC:
yuuji@0 297 ret = (void *) myNewsrc;
yuuji@0 298 break;
yuuji@0 299 case SET_NEWSACTIVE:
yuuji@0 300 if (newsActive) fs_give ((void **) &newsActive);
yuuji@0 301 newsActive = cpystr ((char *) value);
yuuji@0 302 case GET_NEWSACTIVE:
yuuji@0 303 ret = (void *) newsActive;
yuuji@0 304 break;
yuuji@0 305 case SET_NEWSSPOOL:
yuuji@0 306 if (newsSpool) fs_give ((void **) &newsSpool);
yuuji@0 307 newsSpool = cpystr ((char *) value);
yuuji@0 308 case GET_NEWSSPOOL:
yuuji@0 309 ret = (void *) newsSpool;
yuuji@0 310 break;
yuuji@0 311
yuuji@0 312 case SET_ANONYMOUSHOME:
yuuji@0 313 if (anonymousHome) fs_give ((void **) &anonymousHome);
yuuji@0 314 anonymousHome = cpystr ((char *) value);
yuuji@0 315 case GET_ANONYMOUSHOME:
yuuji@0 316 if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
yuuji@0 317 ret = (void *) anonymousHome;
yuuji@0 318 break;
yuuji@0 319 case SET_FTPHOME:
yuuji@0 320 if (ftpHome) fs_give ((void **) &ftpHome);
yuuji@0 321 ftpHome = cpystr ((char *) value);
yuuji@0 322 case GET_FTPHOME:
yuuji@0 323 ret = (void *) ftpHome;
yuuji@0 324 break;
yuuji@0 325 case SET_PUBLICHOME:
yuuji@0 326 if (publicHome) fs_give ((void **) &publicHome);
yuuji@0 327 publicHome = cpystr ((char *) value);
yuuji@0 328 case GET_PUBLICHOME:
yuuji@0 329 ret = (void *) publicHome;
yuuji@0 330 break;
yuuji@0 331 case SET_SHAREDHOME:
yuuji@0 332 if (sharedHome) fs_give ((void **) &sharedHome);
yuuji@0 333 sharedHome = cpystr ((char *) value);
yuuji@0 334 case GET_SHAREDHOME:
yuuji@0 335 ret = (void *) sharedHome;
yuuji@0 336 break;
yuuji@0 337 case SET_SYSINBOX:
yuuji@0 338 if (sysInbox) fs_give ((void **) &sysInbox);
yuuji@0 339 sysInbox = cpystr ((char *) value);
yuuji@0 340 case GET_SYSINBOX:
yuuji@0 341 ret = (void *) sysInbox;
yuuji@0 342 break;
yuuji@0 343 case SET_SSLCAPATH: /* this can be set null */
yuuji@0 344 if (sslCApath) fs_give ((void **) &sslCApath);
yuuji@0 345 sslCApath = value ? cpystr ((char *) value) : value;
yuuji@0 346 break;
yuuji@0 347 case GET_SSLCAPATH:
yuuji@0 348 ret = (void *) sslCApath;
yuuji@0 349 break;
yuuji@0 350 case SET_LISTMAXLEVEL:
yuuji@0 351 list_max_level = (long) value;
yuuji@0 352 case GET_LISTMAXLEVEL:
yuuji@0 353 ret = (void *) list_max_level;
yuuji@0 354 break;
yuuji@0 355
yuuji@0 356 case SET_MBXPROTECTION:
yuuji@0 357 mbx_protection = (long) value;
yuuji@0 358 case GET_MBXPROTECTION:
yuuji@0 359 ret = (void *) mbx_protection;
yuuji@0 360 break;
yuuji@0 361 case SET_DIRPROTECTION:
yuuji@0 362 dir_protection = (long) value;
yuuji@0 363 case GET_DIRPROTECTION:
yuuji@0 364 ret = (void *) dir_protection;
yuuji@0 365 break;
yuuji@0 366 case SET_LOCKPROTECTION:
yuuji@0 367 dotlock_mode = (long) value;
yuuji@0 368 case GET_LOCKPROTECTION:
yuuji@0 369 ret = (void *) dotlock_mode;
yuuji@0 370 break;
yuuji@0 371 case SET_FTPPROTECTION:
yuuji@0 372 ftp_protection = (long) value;
yuuji@0 373 case GET_FTPPROTECTION:
yuuji@0 374 ret = (void *) ftp_protection;
yuuji@0 375 break;
yuuji@0 376 case SET_PUBLICPROTECTION:
yuuji@0 377 public_protection = (long) value;
yuuji@0 378 case GET_PUBLICPROTECTION:
yuuji@0 379 ret = (void *) public_protection;
yuuji@0 380 break;
yuuji@0 381 case SET_SHAREDPROTECTION:
yuuji@0 382 shared_protection = (long) value;
yuuji@0 383 case GET_SHAREDPROTECTION:
yuuji@0 384 ret = (void *) shared_protection;
yuuji@0 385 break;
yuuji@0 386 case SET_FTPDIRPROTECTION:
yuuji@0 387 ftp_dir_protection = (long) value;
yuuji@0 388 case GET_FTPDIRPROTECTION:
yuuji@0 389 ret = (void *) ftp_dir_protection;
yuuji@0 390 break;
yuuji@0 391 case SET_PUBLICDIRPROTECTION:
yuuji@0 392 public_dir_protection = (long) value;
yuuji@0 393 case GET_PUBLICDIRPROTECTION:
yuuji@0 394 ret = (void *) public_dir_protection;
yuuji@0 395 break;
yuuji@0 396 case SET_SHAREDDIRPROTECTION:
yuuji@0 397 shared_dir_protection = (long) value;
yuuji@0 398 case GET_SHAREDDIRPROTECTION:
yuuji@0 399 ret = (void *) shared_dir_protection;
yuuji@0 400 break;
yuuji@0 401
yuuji@0 402 case SET_LOCKTIMEOUT:
yuuji@0 403 locktimeout = (long) value;
yuuji@0 404 case GET_LOCKTIMEOUT:
yuuji@0 405 ret = (void *) locktimeout;
yuuji@0 406 break;
yuuji@0 407 case SET_DISABLEFCNTLLOCK:
yuuji@0 408 fcntlhangbug = value ? T : NIL;
yuuji@0 409 case GET_DISABLEFCNTLLOCK:
yuuji@0 410 ret = (void *) (fcntlhangbug ? VOIDT : NIL);
yuuji@0 411 break;
yuuji@0 412 case SET_LOCKEACCESERROR:
yuuji@0 413 disableLockWarning = value ? NIL : T;
yuuji@0 414 case GET_LOCKEACCESERROR:
yuuji@0 415 ret = (void *) (disableLockWarning ? NIL : VOIDT);
yuuji@0 416 break;
yuuji@0 417 case SET_HIDEDOTFILES:
yuuji@0 418 hideDotFiles = value ? T : NIL;
yuuji@0 419 case GET_HIDEDOTFILES:
yuuji@0 420 ret = (void *) (hideDotFiles ? VOIDT : NIL);
yuuji@0 421 break;
yuuji@0 422 case SET_DISABLEPLAINTEXT:
yuuji@0 423 disablePlaintext = (long) value;
yuuji@0 424 case GET_DISABLEPLAINTEXT:
yuuji@4 425 #ifdef RESTRICT_POP
yuuji@4 426 if (getenv("INTRANET") == NIL) disablePlaintext = 1;
yuuji@4 427 else disablePlaintext = NIL;
yuuji@4 428 #endif
yuuji@0 429 ret = (void *) disablePlaintext;
yuuji@0 430 break;
yuuji@0 431 case SET_CHROOTSERVER:
yuuji@0 432 closedBox = value ? T : NIL;
yuuji@0 433 case GET_CHROOTSERVER:
yuuji@0 434 ret = (void *) (closedBox ? VOIDT : NIL);
yuuji@0 435 break;
yuuji@0 436 case SET_ADVERTISETHEWORLD:
yuuji@0 437 advertisetheworld = value ? T : NIL;
yuuji@0 438 case GET_ADVERTISETHEWORLD:
yuuji@0 439 ret = (void *) (advertisetheworld ? VOIDT : NIL);
yuuji@0 440 break;
yuuji@0 441 case SET_LIMITEDADVERTISE:
yuuji@0 442 limitedadvertise = value ? T : NIL;
yuuji@0 443 case GET_LIMITEDADVERTISE:
yuuji@0 444 ret = (void *) (limitedadvertise ? VOIDT : NIL);
yuuji@0 445 break;
yuuji@0 446 case SET_DISABLEAUTOSHAREDNS:
yuuji@0 447 noautomaticsharedns = value ? T : NIL;
yuuji@0 448 case GET_DISABLEAUTOSHAREDNS:
yuuji@0 449 ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
yuuji@0 450 break;
yuuji@0 451 case SET_DISABLE822TZTEXT:
yuuji@0 452 no822tztext = value ? T : NIL;
yuuji@0 453 case GET_DISABLE822TZTEXT:
yuuji@0 454 ret = (void *) (no822tztext ? VOIDT : NIL);
yuuji@0 455 break;
yuuji@0 456
yuuji@0 457 case SET_USERHASNOLIFE:
yuuji@0 458 has_no_life = value ? T : NIL;
yuuji@0 459 case GET_USERHASNOLIFE:
yuuji@0 460 ret = (void *) (has_no_life ? VOIDT : NIL);
yuuji@0 461 break;
yuuji@0 462 case SET_KERBEROS_CP_SVR_NAME:
yuuji@0 463 kerb_cp_svr_name = value ? T : NIL;
yuuji@0 464 case GET_KERBEROS_CP_SVR_NAME:
yuuji@0 465 ret = (void *) (kerb_cp_svr_name ? VOIDT : NIL);
yuuji@0 466 break;
yuuji@0 467 case SET_NETFSSTATBUG:
yuuji@0 468 netfsstatbug = value ? T : NIL;
yuuji@0 469 case GET_NETFSSTATBUG:
yuuji@0 470 ret = (void *) (netfsstatbug ? VOIDT : NIL);
yuuji@0 471 break;
yuuji@0 472 case SET_BLOCKENVINIT:
yuuji@0 473 block_env_init = value ? T : NIL;
yuuji@0 474 case GET_BLOCKENVINIT:
yuuji@0 475 ret = (void *) (block_env_init ? VOIDT : NIL);
yuuji@0 476 break;
yuuji@0 477 case SET_BLOCKNOTIFY:
yuuji@0 478 mailblocknotify = (blocknotify_t) value;
yuuji@0 479 case GET_BLOCKNOTIFY:
yuuji@0 480 ret = (void *) mailblocknotify;
yuuji@0 481 break;
yuuji@0 482 case SET_LOGOUTHOOK:
yuuji@0 483 maillogouthook = (logouthook_t) value;
yuuji@0 484 case GET_LOGOUTHOOK:
yuuji@0 485 ret = maillogouthook;
yuuji@0 486 break;
yuuji@0 487 case SET_LOGOUTDATA:
yuuji@0 488 maillogoutdata = (void *) value;
yuuji@0 489 case GET_LOGOUTDATA:
yuuji@0 490 ret = maillogoutdata;
yuuji@0 491 }
yuuji@0 492 return ret;
yuuji@0 493 }
yuuji@0 494
yuuji@0 495 /* Write current time
yuuji@0 496 * Accepts: destination string
yuuji@0 497 * optional format of day-of-week prefix
yuuji@0 498 * format of date and time
yuuji@0 499 * flag whether to append symbolic timezone
yuuji@0 500 */
yuuji@0 501
yuuji@0 502 static void do_date (char *date,char *prefix,char *fmt,int suffix)
yuuji@0 503 {
yuuji@0 504 time_t tn = time (0);
yuuji@0 505 struct tm *t = gmtime (&tn);
yuuji@0 506 int zone = t->tm_hour * 60 + t->tm_min;
yuuji@0 507 int julian = t->tm_yday;
yuuji@0 508 t = localtime (&tn); /* get local time now */
yuuji@0 509 /* minus UTC minutes since midnight */
yuuji@0 510 zone = t->tm_hour * 60 + t->tm_min - zone;
yuuji@0 511 /* julian can be one of:
yuuji@0 512 * 36x local time is December 31, UTC is January 1, offset -24 hours
yuuji@0 513 * 1 local time is 1 day ahead of UTC, offset +24 hours
yuuji@0 514 * 0 local time is same day as UTC, no offset
yuuji@0 515 * -1 local time is 1 day behind UTC, offset -24 hours
yuuji@0 516 * -36x local time is January 1, UTC is December 31, offset +24 hours
yuuji@0 517 */
yuuji@0 518 if (julian = t->tm_yday -julian)
yuuji@0 519 zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
yuuji@0 520 if (prefix) { /* want day of week? */
yuuji@0 521 sprintf (date,prefix,days[t->tm_wday]);
yuuji@0 522 date += strlen (date); /* make next sprintf append */
yuuji@0 523 }
yuuji@0 524 /* output the date */
yuuji@0 525 sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
yuuji@0 526 t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
yuuji@0 527 /* append timezone suffix if desired */
yuuji@0 528 if (suffix) rfc822_timezone (date,(void *) t);
yuuji@0 529 }
yuuji@0 530
yuuji@0 531 /* Write current time in RFC 822 format
yuuji@0 532 * Accepts: destination string
yuuji@0 533 */
yuuji@0 534
yuuji@0 535 void rfc822_date (char *date)
yuuji@0 536 {
yuuji@0 537 do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
yuuji@0 538 no822tztext ? NIL : T);
yuuji@0 539 }
yuuji@0 540
yuuji@0 541
yuuji@0 542 /* Write current time in fixed-width RFC 822 format
yuuji@0 543 * Accepts: destination string
yuuji@0 544 */
yuuji@0 545
yuuji@0 546 void rfc822_fixed_date (char *date)
yuuji@0 547 {
yuuji@0 548 do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
yuuji@0 549 }
yuuji@0 550
yuuji@0 551
yuuji@0 552 /* Write current time in internal format
yuuji@0 553 * Accepts: destination string
yuuji@0 554 */
yuuji@0 555
yuuji@0 556 void internal_date (char *date)
yuuji@0 557 {
yuuji@0 558 do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
yuuji@0 559 }
yuuji@0 560
yuuji@0 561 /* Initialize server
yuuji@0 562 * Accepts: server name for syslog or NIL
yuuji@0 563 * /etc/services service name or NIL
yuuji@0 564 * alternate /etc/services service name or NIL
yuuji@0 565 * clock interrupt handler
yuuji@0 566 * kiss-of-death interrupt handler
yuuji@0 567 * hangup interrupt handler
yuuji@0 568 * termination interrupt handler
yuuji@0 569 */
yuuji@0 570
yuuji@0 571 void server_init (char *server,char *service,char *sslservice,
yuuji@0 572 void *clkint,void *kodint,void *hupint,void *trmint,
yuuji@0 573 void *staint)
yuuji@0 574 {
yuuji@0 575 int onceonly = server && service && sslservice;
yuuji@0 576 if (onceonly) { /* set server name in syslog */
yuuji@0 577 int mask;
yuuji@0 578 openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
yuuji@0 579 fclose (stderr); /* possibly save a process ID */
yuuji@0 580 dorc (NIL,NIL); /* do systemwide configuration */
yuuji@0 581 switch (mask = umask (022)){/* check old umask */
yuuji@0 582 case 0: /* definitely unreasonable */
yuuji@0 583 case 022: /* don't need to change it */
yuuji@0 584 break;
yuuji@0 585 default: /* already was a reasonable value */
yuuji@0 586 umask (mask); /* so change it back */
yuuji@0 587 }
yuuji@0 588 }
yuuji@0 589 arm_signal (SIGALRM,clkint); /* prepare for clock interrupt */
yuuji@0 590 arm_signal (SIGUSR2,kodint); /* prepare for Kiss Of Death */
yuuji@0 591 arm_signal (SIGHUP,hupint); /* prepare for hangup */
yuuji@0 592 arm_signal (SIGPIPE,hupint); /* alternative hangup */
yuuji@0 593 arm_signal (SIGTERM,trmint); /* prepare for termination */
yuuji@0 594 /* status dump */
yuuji@0 595 if (staint) arm_signal (SIGUSR1,staint);
yuuji@0 596 if (onceonly) { /* set up network and maybe SSL */
yuuji@0 597 long port;
yuuji@0 598 struct servent *sv;
yuuji@0 599 /* Use SSL if SSL service, or if server starts with "s" and not service */
yuuji@0 600 if (((port = tcp_serverport ()) >= 0)) {
yuuji@0 601 if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
yuuji@0 602 syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
yuuji@0 603 else if ((sv = getservbyname (sslservice,"tcp")) &&
yuuji@0 604 (port == ntohs (sv->s_port))) {
yuuji@0 605 syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
yuuji@0 606 tcp_clientaddr ());
yuuji@0 607 ssl_server_init (server);
yuuji@0 608 }
yuuji@0 609 else { /* not service or SSL service port */
yuuji@0 610 syslog (LOG_DEBUG,"port %ld service init from %s",port,
yuuji@0 611 tcp_clientaddr ());
yuuji@0 612 if (*server == 's') ssl_server_init (server);
yuuji@0 613 }
yuuji@0 614 }
yuuji@0 615 }
yuuji@0 616 }
yuuji@0 617
yuuji@0 618 /* Wait for stdin input
yuuji@0 619 * Accepts: timeout in seconds
yuuji@0 620 * Returns: T if have input on stdin, else NIL
yuuji@0 621 */
yuuji@0 622
yuuji@0 623 long server_input_wait (long seconds)
yuuji@0 624 {
yuuji@0 625 fd_set rfd,efd;
yuuji@0 626 struct timeval tmo;
yuuji@0 627 FD_ZERO (&rfd);
yuuji@0 628 FD_ZERO (&efd);
yuuji@0 629 FD_SET (0,&rfd);
yuuji@0 630 FD_SET (0,&efd);
yuuji@0 631 tmo.tv_sec = seconds; tmo.tv_usec = 0;
yuuji@0 632 return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
yuuji@0 633 }
yuuji@0 634
yuuji@0 635 /* Return UNIX password entry for user name
yuuji@0 636 * Accepts: user name string
yuuji@0 637 * Returns: password entry
yuuji@0 638 *
yuuji@0 639 * Tries all-lowercase form of user name if given user name fails
yuuji@0 640 */
yuuji@0 641
yuuji@0 642 static struct passwd *pwuser (unsigned char *user)
yuuji@0 643 {
yuuji@0 644 unsigned char *s;
yuuji@0 645 struct passwd *pw = getpwnam (user);
yuuji@0 646 if (!pw) { /* failed, see if any uppercase characters */
yuuji@0 647 for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
yuuji@0 648 if (*s) { /* yes, try all lowercase form */
yuuji@0 649 pw = getpwnam (s = lcase (cpystr (user)));
yuuji@0 650 fs_give ((void **) &s);
yuuji@0 651 }
yuuji@0 652 }
yuuji@0 653 return pw;
yuuji@0 654 }
yuuji@0 655
yuuji@0 656
yuuji@0 657 /* Validate password for user name
yuuji@0 658 * Accepts: user name string
yuuji@0 659 * password string
yuuji@0 660 * argument count
yuuji@0 661 * argument vector
yuuji@0 662 * Returns: password entry if validated
yuuji@0 663 *
yuuji@0 664 * Tries password+1 if password fails and starts with space
yuuji@0 665 */
yuuji@0 666
yuuji@0 667 static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
yuuji@0 668 {
yuuji@0 669 char *s;
yuuji@0 670 struct passwd *pw;
yuuji@0 671 struct passwd *ret = NIL;
yuuji@4 672 #ifndef QMAIL /* imapext md5 checker run previously. no need to do here */
yuuji@0 673 if (auth_md5.server) { /* using CRAM-MD5 authentication? */
yuuji@0 674 if (s = auth_md5_pwd (user)) {
yuuji@0 675 if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
yuuji@0 676 ret = pwuser (user); /* validated, get passwd entry for user */
yuuji@0 677 memset (s,0,strlen (s)); /* erase sensitive information */
yuuji@0 678 fs_give ((void **) &s);
yuuji@0 679 }
yuuji@0 680 }
yuuji@4 681 else
yuuji@4 682 #endif
yuuji@4 683 if (pw = pwuser (user)) {/* can get user? */
yuuji@0 684 s = cpystr (pw->pw_name); /* copy returned name in case we need it */
yuuji@0 685 if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
yuuji@0 686 (*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
yuuji@0 687 ret = checkpw (pw,pwd+1,argc,argv);
yuuji@0 688 fs_give ((void **) &s); /* don't need copy of name any more */
yuuji@0 689 }
yuuji@0 690 return ret;
yuuji@0 691 }
yuuji@0 692
yuuji@0 693 /* Server log in
yuuji@0 694 * Accepts: user name string
yuuji@0 695 * password string
yuuji@0 696 * authenticating user name string
yuuji@0 697 * argument count
yuuji@0 698 * argument vector
yuuji@0 699 * Returns: T if password validated, NIL otherwise
yuuji@0 700 */
yuuji@0 701
yuuji@0 702 long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
yuuji@0 703 {
yuuji@0 704 struct passwd *pw = NIL;
yuuji@0 705 int level = LOG_NOTICE;
yuuji@0 706 char *err = "failed";
yuuji@4 707 #ifdef QMAIL
yuuji@4 708 char usr[MAILTMPLEN], *apoppswd;
yuuji@4 709 strncpy(usr, user, MAILTMPLEN-1);
yuuji@4 710 #endif
yuuji@0 711 /* cretins still haven't given up */
yuuji@0 712 if ((strlen (user) >= NETMAXUSER) ||
yuuji@0 713 (authuser && (strlen (authuser) >= NETMAXUSER))) {
yuuji@0 714 level = LOG_ALERT; /* escalate this alert */
yuuji@0 715 err = "SYSTEM BREAK-IN ATTEMPT";
yuuji@0 716 logtry = 0; /* render this session useless */
yuuji@0 717 }
yuuji@0 718 else if (logtry-- <= 0) err = "excessive login failures";
yuuji@0 719 else if (disablePlaintext) err = "disabled";
yuuji@4 720 #ifdef QMAIL
yuuji@4 721 else if ((logtry > 0) &&
yuuji@4 722 (apoppswd = auth_md5_pwd(usr))
yuuji@4 723 && !strcmp(apoppswd, pwd)
yuuji@4 724 && (pw = getpwnam(usr))) {
yuuji@4 725 memset(apoppswd, 0, strlen(apoppswd));
yuuji@4 726 fs_give((void**) &apoppswd);
yuuji@4 727 return pw_login(pw, usr, pw->pw_name, pw->pw_dir, argc, argv);
yuuji@4 728 }
yuuji@4 729 #endif
yuuji@0 730 else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
yuuji@0 731 else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
yuuji@0 732 if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
yuuji@0 733 syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
yuuji@0 734 user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
yuuji@0 735 sleep (3); /* slow down possible cracker */
yuuji@0 736 return NIL;
yuuji@0 737 }
yuuji@0 738
yuuji@0 739 /* Authenticated server log in
yuuji@0 740 * Accepts: user name string
yuuji@0 741 * authenticating user name string
yuuji@0 742 * argument count
yuuji@0 743 * argument vector
yuuji@0 744 * Returns: T if password validated, NIL otherwise
yuuji@0 745 */
yuuji@0 746
yuuji@0 747 long authserver_login (char *user,char *authuser,int argc,char *argv[])
yuuji@0 748 {
yuuji@0 749 return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
yuuji@0 750 }
yuuji@0 751
yuuji@4 752 void permitsmtp() /* to update tcp permission */
yuuji@4 753 {
yuuji@4 754 #ifdef POPBEFORESMTP
yuuji@4 755 #include <sys/types.h>
yuuji@4 756 #include <sys/wait.h>
yuuji@4 757 #ifndef POP3RECORDER
yuuji@4 758 # define POP3RECORDER "/usr/local/etc/pop3-record"
yuuji@4 759 #endif
yuuji@4 760 int child;
yuuji@4 761 int wstat;
yuuji@4 762 char *permsmtp = POP3RECORDER;
yuuji@4 763
yuuji@4 764 switch(child = fork())
yuuji@4 765 {
yuuji@4 766 case -1:
yuuji@4 767 syslog (LOG_INFO,"Cannot exec %s", permsmtp);
yuuji@4 768 _exit(111);
yuuji@4 769 break;
yuuji@4 770 case 0:
yuuji@4 771 execl(permsmtp, permsmtp, 0);
yuuji@4 772 syslog (LOG_INFO,"Cannot exec %s", permsmtp);
yuuji@4 773 _exit(111); break;
yuuji@4 774 }
yuuji@4 775 waitpid(child, &wstat, 0);
yuuji@4 776 #endif
yuuji@4 777 }
yuuji@4 778
yuuji@4 779
yuuji@0 780
yuuji@0 781 /* Log in as anonymous daemon
yuuji@0 782 * Accepts: argument count
yuuji@0 783 * argument vector
yuuji@0 784 * Returns: T if successful, NIL if error
yuuji@0 785 */
yuuji@0 786
yuuji@0 787 long anonymous_login (int argc,char *argv[])
yuuji@0 788 {
yuuji@0 789 /* log in Mr. A. N. Onymous */
yuuji@0 790 return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
yuuji@0 791 (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
yuuji@0 792 argc,argv);
yuuji@0 793 }
yuuji@0 794
yuuji@0 795 /* Finish log in and environment initialization
yuuji@0 796 * Accepts: passwd struct for loginpw()
yuuji@0 797 * optional authentication user name
yuuji@0 798 * user name (NIL for anonymous)
yuuji@0 799 * home directory (NIL to use directory from passwd struct)
yuuji@0 800 * argument count
yuuji@0 801 * argument vector
yuuji@0 802 * Returns: T if successful, NIL if error
yuuji@0 803 */
yuuji@0 804
yuuji@0 805 long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
yuuji@0 806 char *argv[])
yuuji@0 807 {
yuuji@0 808 struct group *gr;
yuuji@0 809 char **t;
yuuji@0 810 long ret = NIL;
yuuji@0 811 if (pw && pw->pw_uid) { /* must have passwd struct for non-UID 0 */
yuuji@0 812 /* make safe copies of user and home */
yuuji@0 813 if (user) user = cpystr (pw->pw_name);
yuuji@0 814 home = cpystr (home ? home : pw->pw_dir);
yuuji@0 815 /* authorization ID .NE. authentication ID? */
yuuji@0 816 if (user && auser && *auser && compare_cstring (auser,user)) {
yuuji@0 817 /* scan list of mail administrators */
yuuji@0 818 if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
yuuji@0 819 if (!compare_cstring (auser,*t++))
yuuji@0 820 ret = pw_login (pw,NIL,user,home,argc,argv);
yuuji@0 821 syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
yuuji@0 822 ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
yuuji@0 823 }
yuuji@0 824 else if (closedBox) { /* paranoid site, lock out other directories */
yuuji@0 825 if (chdir (home) || chroot (home))
yuuji@0 826 syslog (LOG_NOTICE|LOG_AUTH,
yuuji@0 827 "Login %s failed: unable to set chroot=%.80s host=%.80s",
yuuji@0 828 pw->pw_name,home,tcp_clienthost ());
yuuji@0 829 else if (loginpw (pw,argc,argv)) ret = env_init (user,NIL);
yuuji@0 830 else fatal ("Login failed after chroot");
yuuji@0 831 }
yuuji@0 832 /* normal login */
yuuji@4 833 #ifdef QMAIL
yuuji@4 834 else if (((pw->pw_uid == geteuid ()) || (permitsmtp(), loginpw (pw,argc,argv
yuuji@4 835 ))) &&
yuuji@4 836 (ret = env_init (user,home))) chdir (myhomedir ());
yuuji@4 837 #else
yuuji@0 838 else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
yuuji@4 839 (ret = env_init (user,home))) chdir (myhomedir ());
yuuji@4 840 #endif
yuuji@0 841 fs_give ((void **) &home); /* clean up */
yuuji@0 842 if (user) fs_give ((void **) &user);
yuuji@0 843 }
yuuji@0 844 endpwent (); /* in case shadow passwords in pw data */
yuuji@0 845 return ret; /* return status */
yuuji@0 846 }
yuuji@0 847
yuuji@0 848 /* Initialize environment
yuuji@0 849 * Accepts: user name (NIL for anonymous)
yuuji@0 850 * home directory name
yuuji@0 851 * Returns: T, always
yuuji@0 852 */
yuuji@0 853
yuuji@0 854 long env_init (char *user,char *home)
yuuji@0 855 {
yuuji@0 856 extern MAILSTREAM CREATEPROTO;
yuuji@0 857 extern MAILSTREAM EMPTYPROTO;
yuuji@0 858 struct passwd *pw;
yuuji@0 859 struct stat sbuf;
yuuji@0 860 char tmp[MAILTMPLEN];
yuuji@0 861 /* don't init if blocked */
yuuji@0 862 if (block_env_init) return LONGT;
yuuji@0 863 if (myUserName) fatal ("env_init called twice!");
yuuji@0 864 /* initially nothing in namespace list */
yuuji@0 865 nslist[0] = nslist[1] = nslist[2] = NIL;
yuuji@0 866 /* myUserName must be set before dorc() call */
yuuji@0 867 myUserName = cpystr (user ? user : ANONYMOUSUSER);
yuuji@0 868 /* force default prototypes to be set */
yuuji@0 869 if (!createProto) createProto = &CREATEPROTO;
yuuji@0 870 if (!appendProto) appendProto = &EMPTYPROTO;
yuuji@0 871 dorc (NIL,NIL); /* do systemwide configuration */
yuuji@0 872 if (!home) { /* closed box server */
yuuji@0 873 /* standard user can only reference home */
yuuji@0 874 if (user) nslist[0] = &nshome;
yuuji@0 875 else { /* anonymous user */
yuuji@0 876 nslist[0] = &nsblackother; /* set root */
yuuji@0 877 anonymous = T; /* flag as anonymous */
yuuji@0 878 }
yuuji@0 879 myHomeDir = cpystr (""); /* home directory is root */
yuuji@0 880 sysInbox = cpystr ("INBOX");/* make system INBOX */
yuuji@0 881 }
yuuji@0 882 else { /* open or black box */
yuuji@0 883 closedBox = NIL; /* definitely not a closed box */
yuuji@0 884 if (user) { /* remember user name and home directory */
yuuji@0 885 if (blackBoxDir) { /* build black box directory name */
yuuji@0 886 sprintf (tmp,"%s/%s",blackBoxDir,myUserName);
yuuji@0 887 /* must exist */
yuuji@0 888 if (!((!stat (home = tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ||
yuuji@0 889 (blackBoxDefaultHome &&
yuuji@0 890 !stat (home = blackBoxDefaultHome,&sbuf) &&
yuuji@0 891 (sbuf.st_mode & S_IFDIR)))) fatal ("no home");
yuuji@0 892 sysInbox = (char *) fs_get (strlen (home) + 7);
yuuji@0 893 /* set system INBOX */
yuuji@0 894 sprintf (sysInbox,"%s/INBOX",home);
yuuji@0 895 blackBox = T; /* mark that it's a black box */
yuuji@0 896 /* mbox meaningless if black box */
yuuji@0 897 mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox");
yuuji@0 898 }
yuuji@0 899 nslist[0] = &nshome; /* home namespace */
yuuji@0 900 /* limited advertise namespaces */
yuuji@0 901 if (limitedadvertise) nslist[2] = &nslimited;
yuuji@0 902 else if (blackBox) { /* black box namespaces */
yuuji@0 903 nslist[1] = &nsblackother;
yuuji@0 904 nslist[2] = &nsshared;
yuuji@0 905 }
yuuji@0 906 else { /* open box namespaces */
yuuji@0 907 nslist[1] = &nsunixother;
yuuji@0 908 nslist[2] = advertisetheworld ? &nsworld : &nsshared;
yuuji@0 909 }
yuuji@0 910 }
yuuji@0 911 else {
yuuji@0 912 nslist[2] = &nsftp; /* anonymous user */
yuuji@0 913 sprintf (tmp,"%s/INBOX",
yuuji@0 914 home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
yuuji@0 915 sysInbox = cpystr (tmp); /* make system INBOX */
yuuji@0 916 anonymous = T; /* flag as anonymous */
yuuji@0 917 }
yuuji@0 918 myHomeDir = cpystr (home); /* set home directory */
yuuji@0 919 }
yuuji@0 920
yuuji@0 921 if (allowuserconfig) { /* allow user config files */
yuuji@0 922 dorc (strcat (strcpy (tmp,myHomeDir),"/.mminit"),T);
yuuji@0 923 dorc (strcat (strcpy (tmp,myHomeDir),"/.imaprc"),NIL);
yuuji@0 924 }
yuuji@0 925 if (!closedBox && !noautomaticsharedns) {
yuuji@0 926 /* #ftp namespace */
yuuji@0 927 if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
yuuji@0 928 /* #public namespace */
yuuji@0 929 if (!publicHome && (pw = getpwnam ("imappublic")))
yuuji@0 930 publicHome = cpystr (pw->pw_dir);
yuuji@0 931 /* #shared namespace */
yuuji@0 932 if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
yuuji@0 933 sharedHome = cpystr (pw->pw_dir);
yuuji@0 934 }
yuuji@0 935 if (!myLocalHost) mylocalhost ();
yuuji@0 936 if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
yuuji@0 937 if (!newsActive) newsActive = cpystr (ACTIVEFILE);
yuuji@0 938 if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
yuuji@0 939 /* re-do open action to get flags */
yuuji@0 940 (*createProto->dtb->open) (NIL);
yuuji@0 941 endpwent (); /* close pw database */
yuuji@0 942 return T;
yuuji@0 943 }
yuuji@0 944
yuuji@0 945 /* Return my user name
yuuji@0 946 * Accepts: pointer to optional flags
yuuji@0 947 * Returns: my user name
yuuji@0 948 */
yuuji@0 949
yuuji@0 950 char *myusername_full (unsigned long *flags)
yuuji@0 951 {
yuuji@0 952 struct passwd *pw;
yuuji@0 953 struct stat sbuf;
yuuji@0 954 char *s;
yuuji@0 955 unsigned long euid;
yuuji@0 956 char *ret = UNLOGGEDUSER;
yuuji@0 957 /* no user name yet and not root? */
yuuji@0 958 if (!myUserName && (euid = geteuid ())) {
yuuji@0 959 /* yes, look up getlogin() user name or EUID */
yuuji@0 960 if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
yuuji@0 961 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
yuuji@0 962 (pw = getpwuid (euid))) {
yuuji@0 963 if (block_env_init) { /* don't env_init if blocked */
yuuji@0 964 if (flags) *flags = MU_LOGGEDIN;
yuuji@0 965 return pw->pw_name;
yuuji@0 966 }
yuuji@0 967 env_init (pw->pw_name,
yuuji@0 968 ((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
yuuji@0 969 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
yuuji@0 970 s : pw->pw_dir);
yuuji@0 971 }
yuuji@0 972 else fatal ("Unable to look up user name");
yuuji@0 973 }
yuuji@0 974 if (myUserName) { /* logged in? */
yuuji@0 975 if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
yuuji@0 976 ret = myUserName; /* return user name */
yuuji@0 977 }
yuuji@0 978 else if (flags) *flags = MU_NOTLOGGEDIN;
yuuji@0 979 return ret;
yuuji@0 980 }
yuuji@0 981
yuuji@0 982
yuuji@0 983 /* Return my local host name
yuuji@0 984 * Returns: my local host name
yuuji@0 985 */
yuuji@0 986
yuuji@0 987 char *mylocalhost ()
yuuji@0 988 {
yuuji@0 989 if (!myLocalHost) {
yuuji@0 990 char *s,tmp[MAILTMPLEN];
yuuji@0 991 char *t = "unknown";
yuuji@0 992 tmp[0] = tmp[MAILTMPLEN-1] = '\0';
yuuji@0 993 if (!gethostname (tmp,MAILTMPLEN-1) && tmp[0]) {
yuuji@0 994 /* sanity check of name */
yuuji@0 995 for (s = tmp; (*s > 0x20) && (*s < 0x7f); ++s);
yuuji@0 996 if (!*s) t = tcp_canonical (tmp);
yuuji@0 997 }
yuuji@0 998 myLocalHost = cpystr (t);
yuuji@0 999 }
yuuji@0 1000 return myLocalHost;
yuuji@0 1001 }
yuuji@0 1002
yuuji@0 1003 /* Return my home directory name
yuuji@0 1004 * Returns: my home directory name
yuuji@0 1005 */
yuuji@0 1006
yuuji@0 1007 char *myhomedir ()
yuuji@0 1008 {
yuuji@0 1009 if (!myHomeDir) myusername ();/* initialize if first time */
yuuji@0 1010 return myHomeDir ? myHomeDir : "";
yuuji@0 1011 }
yuuji@0 1012
yuuji@0 1013
yuuji@0 1014 /* Return my home mailbox name
yuuji@0 1015 * Returns: my home directory name
yuuji@0 1016 */
yuuji@0 1017
yuuji@0 1018 static char *mymailboxdir ()
yuuji@0 1019 {
yuuji@0 1020 char *home = myhomedir ();
yuuji@0 1021 /* initialize if first time */
yuuji@0 1022 if (!myMailboxDir && myHomeDir) {
yuuji@0 1023 if (mailsubdir) {
yuuji@0 1024 char tmp[MAILTMPLEN];
yuuji@0 1025 sprintf (tmp,"%s/%s",home,mailsubdir);
yuuji@0 1026 myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
yuuji@0 1027 }
yuuji@0 1028 else myMailboxDir = cpystr (home);
yuuji@0 1029 }
yuuji@0 1030 return myMailboxDir ? myMailboxDir : "";
yuuji@0 1031 }
yuuji@0 1032
yuuji@0 1033
yuuji@0 1034 /* Return system standard INBOX
yuuji@0 1035 * Accepts: buffer string
yuuji@0 1036 */
yuuji@0 1037
yuuji@0 1038 char *sysinbox ()
yuuji@0 1039 {
yuuji@0 1040 char tmp[MAILTMPLEN];
yuuji@0 1041 if (!sysInbox) { /* initialize if first time */
yuuji@0 1042 sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
yuuji@0 1043 sysInbox = cpystr (tmp); /* system inbox is from mail spool */
yuuji@0 1044 }
yuuji@0 1045 return sysInbox;
yuuji@0 1046 }
yuuji@0 1047
yuuji@0 1048 /* Return mailbox directory name
yuuji@0 1049 * Accepts: destination buffer
yuuji@0 1050 * directory prefix
yuuji@0 1051 * name in directory
yuuji@0 1052 * Returns: file name or NIL if error
yuuji@0 1053 */
yuuji@0 1054
yuuji@0 1055 char *mailboxdir (char *dst,char *dir,char *name)
yuuji@0 1056 {
yuuji@0 1057 char tmp[MAILTMPLEN];
yuuji@0 1058 if (dir || name) { /* if either argument provided */
yuuji@0 1059 if (dir) {
yuuji@0 1060 if (strlen (dir) > NETMAXMBX) return NIL;
yuuji@0 1061 strcpy (tmp,dir); /* write directory prefix */
yuuji@0 1062 }
yuuji@0 1063 else tmp[0] = '\0'; /* otherwise null string */
yuuji@0 1064 if (name) {
yuuji@0 1065 if (strlen (name) > NETMAXMBX) return NIL;
yuuji@0 1066 strcat (tmp,name); /* write name in directory */
yuuji@0 1067 }
yuuji@0 1068 /* validate name, return its name */
yuuji@0 1069 if (!mailboxfile (dst,tmp)) return NIL;
yuuji@0 1070 }
yuuji@0 1071 /* no arguments, wants mailbox directory */
yuuji@0 1072 else strcpy (dst,mymailboxdir ());
yuuji@0 1073 return dst; /* return the name */
yuuji@0 1074 }
yuuji@0 1075
yuuji@0 1076 /* Return mailbox file name
yuuji@0 1077 * Accepts: destination buffer
yuuji@0 1078 * mailbox name
yuuji@0 1079 * Returns: file name or empty string for driver-selected INBOX or NIL if error
yuuji@0 1080 */
yuuji@0 1081
yuuji@0 1082 char *mailboxfile (char *dst,char *name)
yuuji@0 1083 {
yuuji@0 1084 struct passwd *pw;
yuuji@0 1085 char *s;
yuuji@0 1086 if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
yuuji@0 1087 ((anonymous || blackBox || restrictBox || (*name == '#')) &&
yuuji@0 1088 (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
yuuji@0 1089 dst = NIL; /* invalid name */
yuuji@0 1090 else switch (*name) { /* determine mailbox type based upon name */
yuuji@0 1091 case '#': /* namespace name */
yuuji@0 1092 /* #ftp/ namespace */
yuuji@0 1093 if (((name[1] == 'f') || (name[1] == 'F')) &&
yuuji@0 1094 ((name[2] == 't') || (name[2] == 'T')) &&
yuuji@0 1095 ((name[3] == 'p') || (name[3] == 'P')) &&
yuuji@0 1096 (name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
yuuji@0 1097 /* #public/ and #shared/ namespaces */
yuuji@0 1098 else if ((((name[1] == 'p') || (name[1] == 'P')) &&
yuuji@0 1099 ((name[2] == 'u') || (name[2] == 'U')) &&
yuuji@0 1100 ((name[3] == 'b') || (name[3] == 'B')) &&
yuuji@0 1101 ((name[4] == 'l') || (name[4] == 'L')) &&
yuuji@0 1102 ((name[5] == 'i') || (name[5] == 'I')) &&
yuuji@0 1103 ((name[6] == 'c') || (name[6] == 'C')) &&
yuuji@0 1104 (name[7] == '/') && (s = publicHome)) ||
yuuji@0 1105 (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
yuuji@0 1106 ((name[2] == 'h') || (name[2] == 'H')) &&
yuuji@0 1107 ((name[3] == 'a') || (name[3] == 'A')) &&
yuuji@0 1108 ((name[4] == 'r') || (name[4] == 'R')) &&
yuuji@0 1109 ((name[5] == 'e') || (name[5] == 'E')) &&
yuuji@0 1110 ((name[6] == 'd') || (name[6] == 'D')) &&
yuuji@0 1111 (name[7] == '/') && (s = sharedHome)))
yuuji@0 1112 sprintf (dst,"%s/%s",s,compare_cstring (name+8,"INBOX") ?
yuuji@0 1113 name+8 : "INBOX");
yuuji@0 1114 else dst = NIL; /* unknown namespace */
yuuji@0 1115 break;
yuuji@0 1116
yuuji@0 1117 case '/': /* root access */
yuuji@0 1118 if (anonymous) dst = NIL; /* anonymous forbidden to do this */
yuuji@0 1119 else if (blackBox) { /* other user access if blackbox */
yuuji@0 1120 if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
yuuji@0 1121 /* see if other user INBOX */
yuuji@0 1122 else if ((s = strchr (name+1,'/')) && !compare_cstring (s+1,"INBOX")) {
yuuji@0 1123 *s = '\0'; /* temporarily tie off string */
yuuji@0 1124 sprintf (dst,"%s/%s/INBOX",blackBoxDir,name+1);
yuuji@0 1125 *s = '/'; /* in case caller cares */
yuuji@0 1126 }
yuuji@0 1127 else sprintf (dst,"%s/%s",blackBoxDir,name+1);
yuuji@0 1128 }
yuuji@0 1129 else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
yuuji@0 1130 dst = NIL; /* restricted and not access to sysinbox */
yuuji@0 1131 else strcpy (dst,name); /* unrestricted, copy root name */
yuuji@0 1132 break;
yuuji@0 1133 case '~': /* other user access */
yuuji@0 1134 /* bad syntax or anonymous can't win */
yuuji@0 1135 if (!*++name || anonymous) dst = NIL;
yuuji@0 1136 /* ~/ equivalent to ordinary name */
yuuji@0 1137 else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
yuuji@0 1138 /* other user forbidden if closed/restricted */
yuuji@0 1139 else if (closedBox || (restrictBox & RESTRICTOTHERUSER)) dst = NIL;
yuuji@0 1140 else if (blackBox) { /* black box form of other user */
yuuji@0 1141 /* see if other user INBOX */
yuuji@0 1142 if ((s = strchr (name,'/')) && compare_cstring (s+1,"INBOX")) {
yuuji@0 1143 *s = '\0'; /* temporarily tie off string */
yuuji@0 1144 sprintf (dst,"%s/%s/INBOX",blackBoxDir,name);
yuuji@0 1145 *s = '/'; /* in case caller cares */
yuuji@0 1146 }
yuuji@0 1147 else sprintf (dst,"%s/%s",blackBoxDir,name);
yuuji@0 1148 }
yuuji@0 1149 else { /* clear box other user */
yuuji@0 1150 /* copy user name */
yuuji@0 1151 for (s = dst; *name && (*name != '/'); *s++ = *name++);
yuuji@0 1152 *s++ = '\0'; /* tie off user name, look up in passwd file */
yuuji@0 1153 if ((pw = getpwnam (dst)) && pw->pw_dir) {
yuuji@0 1154 if (*name) name++; /* skip past the slash */
yuuji@0 1155 /* canonicalize case of INBOX */
yuuji@0 1156 if (!compare_cstring (name,"INBOX")) name = "INBOX";
yuuji@0 1157 /* remove trailing / from directory */
yuuji@0 1158 if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
yuuji@0 1159 /* don't allow ~root/ if restricted root */
yuuji@0 1160 if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
yuuji@0 1161 /* build final name w/ subdir if needed */
yuuji@0 1162 else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
yuuji@0 1163 else sprintf (dst,"%s/%s",pw->pw_dir,name);
yuuji@0 1164 }
yuuji@0 1165 else dst = NIL; /* no such user */
yuuji@0 1166 }
yuuji@0 1167 break;
yuuji@0 1168
yuuji@0 1169 case 'I': case 'i': /* possible INBOX */
yuuji@0 1170 if (!compare_cstring (name+1,"NBOX")) {
yuuji@0 1171 /* if restricted, use INBOX in mailbox dir */
yuuji@0 1172 if (anonymous || blackBox || closedBox)
yuuji@0 1173 sprintf (dst,"%s/INBOX",mymailboxdir ());
yuuji@0 1174 else *dst = '\0'; /* otherwise driver selects the name */
yuuji@0 1175 break;
yuuji@0 1176 }
yuuji@0 1177 /* drop into to ordinary name case */
yuuji@0 1178 default: /* ordinary name is easy */
yuuji@0 1179 sprintf (dst,"%s/%s",mymailboxdir (),name);
yuuji@0 1180 break;
yuuji@0 1181 }
yuuji@0 1182 return dst; /* return final name */
yuuji@0 1183 }
yuuji@0 1184
yuuji@0 1185 /* Dot-lock file locker
yuuji@0 1186 * Accepts: file name to lock
yuuji@0 1187 * destination buffer for lock file name
yuuji@0 1188 * open file description on file name to lock
yuuji@0 1189 * Returns: T if success, NIL if failure
yuuji@0 1190 */
yuuji@0 1191
yuuji@0 1192 long dotlock_lock (char *file,DOTLOCK *base,int fd)
yuuji@0 1193 {
yuuji@0 1194 int i = locktimeout * 60;
yuuji@0 1195 int j,mask,retry,pi[2],po[2];
yuuji@0 1196 char *s,tmp[MAILTMPLEN];
yuuji@0 1197 struct stat sb;
yuuji@0 1198 /* flush absurd file name */
yuuji@0 1199 if (strlen (file) > 512) return NIL;
yuuji@0 1200 /* build lock filename */
yuuji@0 1201 sprintf (base->lock,"%s.lock",file);
yuuji@0 1202 /* assume no pipe */
yuuji@0 1203 base->pipei = base->pipeo = -1;
yuuji@0 1204 do { /* make sure not symlink */
yuuji@0 1205 if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
yuuji@0 1206 /* time out if file older than 5 minutes */
yuuji@0 1207 if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
yuuji@0 1208 /* try to create the lock */
yuuji@0 1209 switch (retry = crexcl (base->lock)) {
yuuji@0 1210 case -1: /* OK to retry */
yuuji@0 1211 if (!(i%15)) { /* time to notify? */
yuuji@0 1212 sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
yuuji@0 1213 file,i);
yuuji@0 1214 MM_LOG (tmp,WARN);
yuuji@0 1215 }
yuuji@0 1216 sleep (1); /* wait 1 second before next try */
yuuji@0 1217 break;
yuuji@0 1218 case NIL: /* failure, can't retry */
yuuji@0 1219 i = 0;
yuuji@0 1220 break;
yuuji@0 1221 case T: /* success, make sure others can break lock */
yuuji@0 1222 chmod (base->lock,(int) dotlock_mode);
yuuji@0 1223 return LONGT;
yuuji@0 1224 }
yuuji@0 1225 } while (i--); /* until out of retries */
yuuji@0 1226 if (retry < 0) { /* still returning retry after locktimeout? */
yuuji@0 1227 if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
yuuji@0 1228 if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
yuuji@0 1229 sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
yuuji@0 1230 (long) (time (0) - sb.st_ctime));
yuuji@0 1231 MM_LOG (tmp,WARN);
yuuji@0 1232 }
yuuji@0 1233 mask = umask (0); /* want our lock protection */
yuuji@0 1234 unlink (base->lock); /* try to remove the old file */
yuuji@0 1235 /* seize the lock */
yuuji@0 1236 if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) dotlock_mode)) >= 0) {
yuuji@0 1237 close (i); /* don't need descriptor any more */
yuuji@0 1238 sprintf (tmp,"Mailbox %.80s lock overridden",file);
yuuji@0 1239 MM_LOG (tmp,NIL);
yuuji@0 1240 chmod (base->lock,(int) dotlock_mode);
yuuji@0 1241 umask (mask); /* restore old umask */
yuuji@0 1242 return LONGT;
yuuji@0 1243 }
yuuji@0 1244 umask (mask); /* restore old umask */
yuuji@0 1245 }
yuuji@0 1246
yuuji@0 1247 if (fd >= 0) switch (errno) {
yuuji@0 1248 case EACCES: /* protection failure? */
yuuji@0 1249 MM_CRITICAL (NIL); /* go critical */
yuuji@0 1250 if (closedBox || !lockpgm); /* can't do on closed box or disabled */
yuuji@0 1251 else if ((*lockpgm && stat (lockpgm,&sb)) ||
yuuji@0 1252 (!*lockpgm && stat (lockpgm = LOCKPGM1,&sb) &&
yuuji@0 1253 stat (lockpgm = LOCKPGM2,&sb) && stat (lockpgm = LOCKPGM3,&sb)))
yuuji@0 1254 lockpgm = NIL; /* disable if can't find lockpgm */
yuuji@0 1255 else if (pipe (pi) >= 0) { /* make command pipes */
yuuji@0 1256 long cf;
yuuji@0 1257 char *argv[4],arg[20];
yuuji@0 1258 /* if input pipes usable create output pipes */
yuuji@0 1259 if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
yuuji@0 1260 /* make sure output pipes are usable */
yuuji@0 1261 if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
yuuji@0 1262 /* all is good, make inferior process */
yuuji@0 1263 else if (!(j = fork ())) {
yuuji@0 1264 if (!fork ()) { /* make grandchild so it's inherited by init */
yuuji@0 1265 /* prepare argument vector */
yuuji@0 1266 sprintf (arg,"%d",fd);
yuuji@0 1267 argv[0] = lockpgm; argv[1] = arg;
yuuji@0 1268 argv[2] = file; argv[3] = NIL;
yuuji@0 1269 /* set parent's I/O to my O/I */
yuuji@0 1270 dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
yuuji@0 1271 /* close all unnecessary descriptors */
yuuji@0 1272 for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
yuuji@0 1273 cf >= 3; --cf) if (cf != fd) close (cf);
yuuji@0 1274 /* be our own process group */
yuuji@0 1275 setpgrp (0,getpid ());
yuuji@0 1276 /* now run it */
yuuji@0 1277 _exit (execv (argv[0],argv));
yuuji@0 1278 }
yuuji@0 1279 _exit (1); /* child is done */
yuuji@0 1280 }
yuuji@0 1281 else if (j > 0) { /* parent process */
yuuji@0 1282 fd_set rfd;
yuuji@0 1283 struct timeval tmo;
yuuji@0 1284 FD_ZERO (&rfd);
yuuji@0 1285 FD_SET (pi[0],&rfd);
yuuji@0 1286 tmo.tv_sec = locktimeout * 60;
yuuji@0 1287 grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
yuuji@0 1288 /* read response from locking program */
yuuji@0 1289 if (select (pi[0]+1,&rfd,0,0,&tmo) &&
yuuji@0 1290 (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
yuuji@0 1291 /* success, record pipes */
yuuji@0 1292 base->pipei = pi[0]; base->pipeo = po[1];
yuuji@0 1293 /* close child's side of the pipes */
yuuji@0 1294 close (pi[1]); close (po[0]);
yuuji@0 1295 MM_NOCRITICAL (NIL);/* no longer critical */
yuuji@0 1296 return LONGT;
yuuji@0 1297 }
yuuji@0 1298 }
yuuji@0 1299 close (po[0]); close (po[1]);
yuuji@0 1300 }
yuuji@0 1301 close (pi[0]); close (pi[1]);
yuuji@0 1302 }
yuuji@0 1303
yuuji@0 1304 MM_NOCRITICAL (NIL); /* no longer critical */
yuuji@0 1305 /* find directory/file delimiter */
yuuji@0 1306 if (s = strrchr (base->lock,'/')) {
yuuji@0 1307 *s = '\0'; /* tie off at directory */
yuuji@0 1308 sprintf(tmp, /* generate default message */
yuuji@0 1309 "Mailbox vulnerable - directory %.80s must have 1777 protection",
yuuji@0 1310 base->lock);
yuuji@0 1311 /* definitely not 1777 if can't stat */
yuuji@0 1312 mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
yuuji@0 1313 *s = '/'; /* restore lock name */
yuuji@0 1314 if (mask != 1777) { /* default warning if not 1777 */
yuuji@0 1315 if (!disableLockWarning) MM_LOG (tmp,WARN);
yuuji@0 1316 break;
yuuji@0 1317 }
yuuji@0 1318 }
yuuji@0 1319 default:
yuuji@0 1320 sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
yuuji@0 1321 base->lock,strerror (errno));
yuuji@0 1322 if (!disableLockWarning) MM_LOG (tmp,WARN);
yuuji@0 1323 break;
yuuji@0 1324 }
yuuji@0 1325 base->lock[0] = '\0'; /* don't use lock files */
yuuji@0 1326 return NIL;
yuuji@0 1327 }
yuuji@0 1328
yuuji@0 1329 /* Dot-lock file unlocker
yuuji@0 1330 * Accepts: lock file name
yuuji@0 1331 * Returns: T if success, NIL if failure
yuuji@0 1332 */
yuuji@0 1333
yuuji@0 1334 long dotlock_unlock (DOTLOCK *base)
yuuji@0 1335 {
yuuji@0 1336 long ret = LONGT;
yuuji@0 1337 if (base && base->lock[0]) {
yuuji@0 1338 if (base->pipei >= 0) { /* if running through a pipe unlocker */
yuuji@0 1339 ret = (write (base->pipeo,"+",1) == 1);
yuuji@0 1340 /* nuke the pipes */
yuuji@0 1341 close (base->pipei); close (base->pipeo);
yuuji@0 1342 }
yuuji@0 1343 else ret = !unlink (base->lock);
yuuji@0 1344 }
yuuji@0 1345 return ret;
yuuji@0 1346 }
yuuji@0 1347
yuuji@0 1348 /* Lock file name
yuuji@0 1349 * Accepts: scratch buffer
yuuji@0 1350 * file name
yuuji@0 1351 * type of locking operation (LOCK_SH or LOCK_EX)
yuuji@0 1352 * pointer to return PID of locker
yuuji@0 1353 * Returns: file descriptor of lock or negative if error
yuuji@0 1354 */
yuuji@0 1355
yuuji@0 1356 int lockname (char *lock,char *fname,int op,long *pid)
yuuji@0 1357 {
yuuji@0 1358 struct stat sbuf;
yuuji@0 1359 *pid = 0; /* no locker PID */
yuuji@0 1360 return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
yuuji@0 1361 }
yuuji@0 1362
yuuji@0 1363
yuuji@0 1364 /* Lock file descriptor
yuuji@0 1365 * Accepts: file descriptor
yuuji@0 1366 * lock file name buffer
yuuji@0 1367 * type of locking operation (LOCK_SH or LOCK_EX)
yuuji@0 1368 * Returns: file descriptor of lock or negative if error
yuuji@0 1369 */
yuuji@0 1370
yuuji@0 1371 int lockfd (int fd,char *lock,int op)
yuuji@0 1372 {
yuuji@0 1373 struct stat sbuf;
yuuji@0 1374 return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
yuuji@0 1375 }
yuuji@0 1376
yuuji@0 1377 /* Lock file name worker
yuuji@0 1378 * Accepts: lock file name
yuuji@0 1379 * pointer to stat() buffer
yuuji@0 1380 * type of locking operation (LOCK_SH or LOCK_EX)
yuuji@0 1381 * pointer to return PID of locker
yuuji@0 1382 * Returns: file descriptor of lock or negative if error
yuuji@0 1383 */
yuuji@0 1384
yuuji@0 1385 int lock_work (char *lock,void *sb,int op,long *pid)
yuuji@0 1386 {
yuuji@0 1387 struct stat lsb,fsb;
yuuji@0 1388 struct stat *sbuf = (struct stat *) sb;
yuuji@0 1389 char tmp[MAILTMPLEN];
yuuji@0 1390 long i;
yuuji@0 1391 int fd;
yuuji@0 1392 int mask = umask (0);
yuuji@0 1393 if (pid) *pid = 0; /* initialize return PID */
yuuji@0 1394 /* make temporary lock file name */
yuuji@0 1395 sprintf (lock,"%s/.%lx.%lx",closedBox ? "" : tmpdir,
yuuji@0 1396 (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
yuuji@0 1397 while (T) { /* until get a good lock */
yuuji@0 1398 do switch ((int) chk_notsymlink (lock,&lsb)) {
yuuji@0 1399 case 1: /* exists just once */
yuuji@0 1400 if (((fd = open (lock,O_RDWR,shlock_mode)) >= 0) ||
yuuji@0 1401 (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
yuuji@0 1402 case -1: /* name doesn't exist */
yuuji@0 1403 fd = open (lock,O_RDWR|O_CREAT|O_EXCL,shlock_mode);
yuuji@0 1404 break;
yuuji@0 1405 default: /* multiple hard links */
yuuji@0 1406 MM_LOG ("hard link to lock name",ERROR);
yuuji@0 1407 syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
yuuji@0 1408 case 0: /* symlink (already did syslog) */
yuuji@0 1409 umask (mask); /* restore old mask */
yuuji@0 1410 return -1; /* fail: no lock file */
yuuji@0 1411 } while ((fd < 0) && (errno == EEXIST));
yuuji@0 1412 if (fd < 0) { /* failed to get file descriptor */
yuuji@0 1413 syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
yuuji@0 1414 strerror (errno));
yuuji@0 1415 if (!closedBox) { /* more explicit snarl for bad configuration */
yuuji@0 1416 if (stat (tmpdir,&lsb))
yuuji@0 1417 syslog (LOG_CRIT,"SYSTEM ERROR: no %s: %s",tmpdir,strerror (errno));
yuuji@0 1418 else if ((lsb.st_mode & 01777) != 01777) {
yuuji@0 1419 sprintf (tmp,"Can't lock for write: %.80s must have 1777 protection",
yuuji@0 1420 tmpdir);
yuuji@0 1421 MM_LOG (tmp,WARN);
yuuji@0 1422 }
yuuji@0 1423 }
yuuji@0 1424 umask (mask); /* restore old mask */
yuuji@0 1425 return -1; /* fail: can't open lock file */
yuuji@0 1426 }
yuuji@0 1427
yuuji@0 1428 /* non-blocking form */
yuuji@0 1429 if (op & LOCK_NB) i = flock (fd,op);
yuuji@0 1430 else { /* blocking form */
yuuji@0 1431 (*mailblocknotify) (BLOCK_FILELOCK,NIL);
yuuji@0 1432 i = flock (fd,op);
yuuji@0 1433 (*mailblocknotify) (BLOCK_NONE,NIL);
yuuji@0 1434 }
yuuji@0 1435 if (i) { /* failed, get other process' PID */
yuuji@0 1436 if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
yuuji@0 1437 (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
yuuji@0 1438 *pid = i;
yuuji@0 1439 close (fd); /* failed, give up on lock */
yuuji@0 1440 umask (mask); /* restore old mask */
yuuji@0 1441 return -1; /* fail: can't lock */
yuuji@0 1442 }
yuuji@0 1443 /* make sure this lock is good for us */
yuuji@0 1444 if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
yuuji@0 1445 !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
yuuji@0 1446 (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
yuuji@0 1447 close (fd); /* lock not right, drop fd and try again */
yuuji@0 1448 }
yuuji@0 1449 chmod (lock,shlock_mode); /* make sure mode OK (don't use fchmod()) */
yuuji@0 1450 umask (mask); /* restore old mask */
yuuji@0 1451 return fd; /* success */
yuuji@0 1452 }
yuuji@0 1453
yuuji@0 1454 /* Check to make sure not a symlink
yuuji@0 1455 * Accepts: file name
yuuji@0 1456 * stat buffer
yuuji@0 1457 * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
yuuji@0 1458 */
yuuji@0 1459
yuuji@0 1460 long chk_notsymlink (char *name,void *sb)
yuuji@0 1461 {
yuuji@0 1462 struct stat *sbuf = (struct stat *) sb;
yuuji@0 1463 /* name exists? */
yuuji@0 1464 if (lstat (name,sbuf)) return -1;
yuuji@0 1465 /* forbid symbolic link */
yuuji@0 1466 if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
yuuji@0 1467 MM_LOG ("symbolic link on lock name",ERROR);
yuuji@0 1468 syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
yuuji@0 1469 name);
yuuji@0 1470 return NIL;
yuuji@0 1471 }
yuuji@0 1472 return (long) sbuf->st_nlink; /* return number of hard links */
yuuji@0 1473 }
yuuji@0 1474
yuuji@0 1475
yuuji@0 1476 /* Unlock file descriptor
yuuji@0 1477 * Accepts: file descriptor
yuuji@0 1478 * lock file name from lockfd()
yuuji@0 1479 */
yuuji@0 1480
yuuji@0 1481 void unlockfd (int fd,char *lock)
yuuji@0 1482 {
yuuji@0 1483 /* delete the file if no sharers */
yuuji@0 1484 if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
yuuji@0 1485 flock (fd,LOCK_UN); /* unlock it */
yuuji@0 1486 close (fd); /* close it */
yuuji@0 1487 }
yuuji@0 1488
yuuji@0 1489 /* Set proper file protection for mailbox
yuuji@0 1490 * Accepts: mailbox name
yuuji@0 1491 * actual file path name
yuuji@0 1492 * Returns: T, always
yuuji@0 1493 */
yuuji@0 1494
yuuji@0 1495 long set_mbx_protections (char *mailbox,char *path)
yuuji@0 1496 {
yuuji@0 1497 struct stat sbuf;
yuuji@0 1498 int mode = (int) mbx_protection;
yuuji@0 1499 if (*mailbox == '#') { /* possible namespace? */
yuuji@0 1500 if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
yuuji@0 1501 ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
yuuji@0 1502 ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
yuuji@0 1503 (mailbox[4] == '/')) mode = (int) ftp_protection;
yuuji@0 1504 else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
yuuji@0 1505 ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
yuuji@0 1506 ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
yuuji@0 1507 ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
yuuji@0 1508 ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
yuuji@0 1509 ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
yuuji@0 1510 (mailbox[7] == '/')) mode = (int) public_protection;
yuuji@0 1511 else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
yuuji@0 1512 ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
yuuji@0 1513 ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
yuuji@0 1514 ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
yuuji@0 1515 ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
yuuji@0 1516 ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
yuuji@0 1517 (mailbox[7] == '/')) mode = (int) shared_protection;
yuuji@0 1518 }
yuuji@0 1519 /* if a directory */
yuuji@0 1520 if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
yuuji@0 1521 /* set owner search if allow read or write */
yuuji@0 1522 if (mode & 0600) mode |= 0100;
yuuji@0 1523 if (mode & 060) mode |= 010;/* set group search if allow read or write */
yuuji@0 1524 if (mode & 06) mode |= 01; /* set world search if allow read or write */
yuuji@0 1525 /* preserve directory SGID bit */
yuuji@0 1526 if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
yuuji@0 1527 }
yuuji@0 1528 chmod (path,mode); /* set the new protection, ignore failure */
yuuji@0 1529 return LONGT;
yuuji@0 1530 }
yuuji@0 1531
yuuji@0 1532 /* Get proper directory protection
yuuji@0 1533 * Accepts: mailbox name
yuuji@0 1534 * Returns: directory mode, always
yuuji@0 1535 */
yuuji@0 1536
yuuji@0 1537 long get_dir_protection (char *mailbox)
yuuji@0 1538 {
yuuji@0 1539 if (*mailbox == '#') { /* possible namespace? */
yuuji@0 1540 if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
yuuji@0 1541 ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
yuuji@0 1542 ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
yuuji@0 1543 (mailbox[4] == '/')) return ftp_dir_protection;
yuuji@0 1544 else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
yuuji@0 1545 ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
yuuji@0 1546 ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
yuuji@0 1547 ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
yuuji@0 1548 ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
yuuji@0 1549 ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
yuuji@0 1550 (mailbox[7] == '/')) return public_dir_protection;
yuuji@0 1551 else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
yuuji@0 1552 ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
yuuji@0 1553 ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
yuuji@0 1554 ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
yuuji@0 1555 ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
yuuji@0 1556 ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
yuuji@0 1557 (mailbox[7] == '/')) return shared_dir_protection;
yuuji@0 1558 }
yuuji@0 1559 return dir_protection;
yuuji@0 1560 }
yuuji@0 1561
yuuji@0 1562 /* Determine default prototype stream to user
yuuji@0 1563 * Accepts: type (NIL for create, T for append)
yuuji@0 1564 * Returns: default prototype stream
yuuji@0 1565 */
yuuji@0 1566
yuuji@0 1567 MAILSTREAM *default_proto (long type)
yuuji@0 1568 {
yuuji@0 1569 myusername (); /* make sure initialized */
yuuji@0 1570 /* return default driver's prototype */
yuuji@0 1571 return type ? appendProto : createProto;
yuuji@0 1572 }
yuuji@0 1573
yuuji@0 1574
yuuji@0 1575 /* Set up user flags for stream
yuuji@0 1576 * Accepts: MAIL stream
yuuji@0 1577 * Returns: MAIL stream with user flags set up
yuuji@0 1578 */
yuuji@0 1579
yuuji@0 1580 MAILSTREAM *user_flags (MAILSTREAM *stream)
yuuji@0 1581 {
yuuji@0 1582 int i;
yuuji@0 1583 myusername (); /* make sure initialized */
yuuji@0 1584 for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
yuuji@0 1585 if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
yuuji@0 1586 return stream;
yuuji@0 1587 }
yuuji@0 1588
yuuji@0 1589
yuuji@0 1590 /* Return nth user flag
yuuji@0 1591 * Accepts: user flag number
yuuji@0 1592 * Returns: flag
yuuji@0 1593 */
yuuji@0 1594
yuuji@0 1595 char *default_user_flag (unsigned long i)
yuuji@0 1596 {
yuuji@0 1597 myusername (); /* make sure initialized */
yuuji@0 1598 return userFlags[i];
yuuji@0 1599 }
yuuji@0 1600
yuuji@0 1601 /* Process rc file
yuuji@0 1602 * Accepts: file name
yuuji@0 1603 * .mminit flag
yuuji@0 1604 * Don't use this feature.
yuuji@0 1605 */
yuuji@0 1606
yuuji@0 1607 void dorc (char *file,long flag)
yuuji@0 1608 {
yuuji@0 1609 int i;
yuuji@0 1610 char *s,*t,*k,*r,tmp[MAILTMPLEN],tmpx[MAILTMPLEN];
yuuji@0 1611 extern MAILSTREAM CREATEPROTO;
yuuji@0 1612 extern MAILSTREAM EMPTYPROTO;
yuuji@0 1613 DRIVER *d;
yuuji@0 1614 FILE *f;
yuuji@0 1615 if ((f = fopen (file ? file : SYSCONFIG,"r")) &&
yuuji@0 1616 (s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))) do {
yuuji@0 1617 *t++ = '\0'; /* tie off line, find second space */
yuuji@0 1618 if ((k = strchr (s,' ')) && (k = strchr (++k,' '))) {
yuuji@0 1619 *k++ = '\0'; /* tie off two words */
yuuji@0 1620 if (!compare_cstring (s,"set keywords") && !userFlags[0]) {
yuuji@0 1621 /* yes, get first keyword */
yuuji@0 1622 k = strtok_r (k,", ",&r);
yuuji@0 1623 /* copy keyword list */
yuuji@0 1624 for (i = 0; k && i < NUSERFLAGS; ++i) if (strlen (k) <= MAXUSERFLAG) {
yuuji@0 1625 if (userFlags[i]) fs_give ((void **) &userFlags[i]);
yuuji@0 1626 userFlags[i] = cpystr (k);
yuuji@0 1627 k = strtok_r (NIL,", ",&r);
yuuji@0 1628 }
yuuji@0 1629 if (flag) break; /* found "set keywords" in .mminit */
yuuji@0 1630 }
yuuji@0 1631
yuuji@0 1632 else if (!flag) { /* none of these valid in .mminit */
yuuji@0 1633 if (myUserName) { /* only valid if logged in */
yuuji@0 1634 if (!compare_cstring (s,"set new-mailbox-format") ||
yuuji@0 1635 !compare_cstring (s,"set new-folder-format")) {
yuuji@0 1636 if (!compare_cstring (k,"same-as-inbox")) {
yuuji@0 1637 if (d = mail_valid (NIL,"INBOX",NIL)) {
yuuji@0 1638 if (!compare_cstring (d->name,"mbox"))
yuuji@0 1639 d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,
yuuji@0 1640 (void *) "unix");
yuuji@0 1641 else if (!compare_cstring (d->name,"dummy")) d = NIL;
yuuji@0 1642 }
yuuji@0 1643 createProto = d ? ((*d->open) (NIL)) : &CREATEPROTO;
yuuji@0 1644 }
yuuji@0 1645 else if (!compare_cstring (k,"system-standard"))
yuuji@0 1646 createProto = &CREATEPROTO;
yuuji@0 1647 else { /* canonicalize mbox to unix */
yuuji@0 1648 if (!compare_cstring (k,"mbox")) k = "unix";
yuuji@0 1649 /* see if a driver name */
yuuji@0 1650 if (d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,(void *) k))
yuuji@0 1651 createProto = (*d->open) (NIL);
yuuji@0 1652 else { /* duh... */
yuuji@0 1653 sprintf (tmpx,"Unknown new mailbox format in %s: %s",
yuuji@0 1654 file ? file : SYSCONFIG,k);
yuuji@0 1655 MM_LOG (tmpx,WARN);
yuuji@0 1656 }
yuuji@0 1657 }
yuuji@0 1658 }
yuuji@0 1659 if (!compare_cstring (s,"set empty-mailbox-format") ||
yuuji@0 1660 !compare_cstring (s,"set empty-folder-format")) {
yuuji@0 1661 if (!compare_cstring (k,"invalid")) appendProto = NIL;
yuuji@0 1662 else if (!compare_cstring (k,"same-as-inbox"))
yuuji@0 1663 appendProto = ((d = mail_valid (NIL,"INBOX",NIL)) &&
yuuji@0 1664 compare_cstring (d->name,"dummy")) ?
yuuji@0 1665 ((*d->open) (NIL)) : &EMPTYPROTO;
yuuji@0 1666 else if (!compare_cstring (k,"system-standard"))
yuuji@0 1667 appendProto = &EMPTYPROTO;
yuuji@0 1668 else { /* see if a driver name */
yuuji@0 1669 for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
yuuji@0 1670 d && compare_cstring (d->name,k); d = d->next);
yuuji@0 1671 if (d) appendProto = (*d->open) (NIL);
yuuji@0 1672 else { /* duh... */
yuuji@0 1673 sprintf (tmpx,"Unknown empty mailbox format in %s: %s",
yuuji@0 1674 file ? file : SYSCONFIG,k);
yuuji@0 1675 MM_LOG (tmpx,WARN);
yuuji@0 1676 }
yuuji@0 1677 }
yuuji@0 1678 }
yuuji@0 1679 }
yuuji@0 1680
yuuji@0 1681 if (!compare_cstring (s,"set local-host")) {
yuuji@0 1682 fs_give ((void **) &myLocalHost);
yuuji@0 1683 myLocalHost = cpystr (k);
yuuji@0 1684 }
yuuji@0 1685 else if (!compare_cstring (s,"set news-active-file")) {
yuuji@0 1686 fs_give ((void **) &newsActive);
yuuji@0 1687 newsActive = cpystr (k);
yuuji@0 1688 }
yuuji@0 1689 else if (!compare_cstring (s,"set news-spool-directory")) {
yuuji@0 1690 fs_give ((void **) &newsSpool);
yuuji@0 1691 newsSpool = cpystr (k);
yuuji@0 1692 }
yuuji@0 1693 else if (!compare_cstring (s,"set mh-path"))
yuuji@0 1694 mail_parameters (NIL,SET_MHPATH,(void *) k);
yuuji@0 1695 else if (!compare_cstring (s,"set mh-allow-inbox"))
yuuji@0 1696 mail_parameters (NIL,SET_MHALLOWINBOX,(void *) atol (k));
yuuji@0 1697 else if (!compare_cstring (s,"set news-state-file")) {
yuuji@0 1698 fs_give ((void **) &myNewsrc);
yuuji@0 1699 myNewsrc = cpystr (k);
yuuji@0 1700 }
yuuji@0 1701 else if (!compare_cstring (s,"set ftp-export-directory")) {
yuuji@0 1702 fs_give ((void **) &ftpHome);
yuuji@0 1703 ftpHome = cpystr (k);
yuuji@0 1704 }
yuuji@0 1705 else if (!compare_cstring (s,"set public-home-directory")) {
yuuji@0 1706 fs_give ((void **) &publicHome);
yuuji@0 1707 publicHome = cpystr (k);
yuuji@0 1708 }
yuuji@0 1709 else if (!compare_cstring (s,"set shared-home-directory")) {
yuuji@0 1710 fs_give ((void **) &sharedHome);
yuuji@0 1711 sharedHome = cpystr (k);
yuuji@0 1712 }
yuuji@0 1713 else if (!compare_cstring (s,"set system-inbox")) {
yuuji@0 1714 fs_give ((void **) &sysInbox);
yuuji@0 1715 sysInbox = cpystr (k);
yuuji@0 1716 }
yuuji@0 1717 else if (!compare_cstring (s,"set mail-subdirectory")) {
yuuji@0 1718 fs_give ((void **) &mailsubdir);
yuuji@0 1719 mailsubdir = cpystr (k);
yuuji@0 1720 }
yuuji@0 1721 else if (!compare_cstring (s,"set from-widget"))
yuuji@0 1722 mail_parameters (NIL,SET_FROMWIDGET,
yuuji@0 1723 compare_cstring (k,"header-only") ?
yuuji@0 1724 VOIDT : NIL);
yuuji@0 1725
yuuji@0 1726 else if (!compare_cstring (s,"set rsh-command"))
yuuji@0 1727 mail_parameters (NIL,SET_RSHCOMMAND,(void *) k);
yuuji@0 1728 else if (!compare_cstring (s,"set rsh-path"))
yuuji@0 1729 mail_parameters (NIL,SET_RSHPATH,(void *) k);
yuuji@0 1730 else if (!compare_cstring (s,"set ssh-command"))
yuuji@0 1731 mail_parameters (NIL,SET_SSHCOMMAND,(void *) k);
yuuji@0 1732 else if (!compare_cstring (s,"set ssh-path"))
yuuji@0 1733 mail_parameters (NIL,SET_SSHPATH,(void *) k);
yuuji@0 1734 else if (!compare_cstring (s,"set tcp-open-timeout"))
yuuji@0 1735 mail_parameters (NIL,SET_OPENTIMEOUT,(void *) atol (k));
yuuji@0 1736 else if (!compare_cstring (s,"set tcp-read-timeout"))
yuuji@0 1737 mail_parameters (NIL,SET_READTIMEOUT,(void *) atol (k));
yuuji@0 1738 else if (!compare_cstring (s,"set tcp-write-timeout"))
yuuji@0 1739 mail_parameters (NIL,SET_WRITETIMEOUT,(void *) atol (k));
yuuji@0 1740 else if (!compare_cstring (s,"set rsh-timeout"))
yuuji@0 1741 mail_parameters (NIL,SET_RSHTIMEOUT,(void *) atol (k));
yuuji@0 1742 else if (!compare_cstring (s,"set ssh-timeout"))
yuuji@0 1743 mail_parameters (NIL,SET_SSHTIMEOUT,(void *) atol (k));
yuuji@0 1744 else if (!compare_cstring (s,"set maximum-login-trials"))
yuuji@0 1745 mail_parameters (NIL,SET_MAXLOGINTRIALS,(void *) atol (k));
yuuji@0 1746 else if (!compare_cstring (s,"set lookahead"))
yuuji@0 1747 mail_parameters (NIL,SET_LOOKAHEAD,(void *) atol (k));
yuuji@0 1748 else if (!compare_cstring (s,"set prefetch"))
yuuji@0 1749 mail_parameters (NIL,SET_PREFETCH,(void *) atol (k));
yuuji@0 1750 else if (!compare_cstring (s,"set close-on-error"))
yuuji@0 1751 mail_parameters (NIL,SET_CLOSEONERROR,(void *) atol (k));
yuuji@0 1752 else if (!compare_cstring (s,"set imap-port"))
yuuji@0 1753 mail_parameters (NIL,SET_IMAPPORT,(void *) atol (k));
yuuji@0 1754 else if (!compare_cstring (s,"set pop3-port"))
yuuji@0 1755 mail_parameters (NIL,SET_POP3PORT,(void *) atol (k));
yuuji@0 1756 else if (!compare_cstring (s,"set uid-lookahead"))
yuuji@0 1757 mail_parameters (NIL,SET_UIDLOOKAHEAD,(void *) atol (k));
yuuji@0 1758 else if (!compare_cstring (s,"set try-ssl-first"))
yuuji@0 1759 mail_parameters (NIL,SET_TRYSSLFIRST,(void *) atol (k));
yuuji@0 1760
yuuji@0 1761 else if (!compare_cstring (s,"set mailbox-protection"))
yuuji@0 1762 mbx_protection = atol (k);
yuuji@0 1763 else if (!compare_cstring (s,"set directory-protection"))
yuuji@0 1764 dir_protection = atol (k);
yuuji@0 1765 else if (!compare_cstring (s,"set lock-protection"))
yuuji@0 1766 dotlock_mode = atol (k);
yuuji@0 1767 else if (!compare_cstring (s,"set ftp-protection"))
yuuji@0 1768 ftp_protection = atol (k);
yuuji@0 1769 else if (!compare_cstring (s,"set public-protection"))
yuuji@0 1770 public_protection = atol (k);
yuuji@0 1771 else if (!compare_cstring (s,"set shared-protection"))
yuuji@0 1772 shared_protection = atol (k);
yuuji@0 1773 else if (!compare_cstring (s,"set ftp-directory-protection"))
yuuji@0 1774 ftp_dir_protection = atol (k);
yuuji@0 1775 else if (!compare_cstring (s,"set public-directory-protection"))
yuuji@0 1776 public_dir_protection = atol (k);
yuuji@0 1777 else if (!compare_cstring (s,"set shared-directory-protection"))
yuuji@0 1778 shared_dir_protection = atol (k);
yuuji@0 1779 else if (!compare_cstring (s,"set dot-lock-file-timeout"))
yuuji@0 1780 locktimeout = atoi (k);
yuuji@0 1781 else if (!compare_cstring (s,"set disable-fcntl-locking"))
yuuji@0 1782 fcntlhangbug = atoi (k);
yuuji@0 1783 else if (!compare_cstring (s,"set disable-lock-warning"))
yuuji@0 1784 disableLockWarning = atoi (k);
yuuji@0 1785 else if (!compare_cstring (s,"set disable-unix-UIDs-and-keywords"))
yuuji@0 1786 has_no_life = atoi (k);
yuuji@0 1787 else if (!compare_cstring (s,"set hide-dot-files"))
yuuji@0 1788 hideDotFiles = atoi (k);
yuuji@0 1789 else if (!compare_cstring (s,"set list-maximum-level"))
yuuji@0 1790 list_max_level = atol (k);
yuuji@0 1791 else if (!compare_cstring (s,"set trust-dns"))
yuuji@0 1792 mail_parameters (NIL,SET_TRUSTDNS,(void *) atol (k));
yuuji@0 1793 else if (!compare_cstring (s,"set sasl-uses-ptr-name"))
yuuji@0 1794 mail_parameters (NIL,SET_SASLUSESPTRNAME,(void *) atol (k));
yuuji@0 1795 else if (!compare_cstring (s,"set network-filesystem-stat-bug"))
yuuji@0 1796 netfsstatbug = atoi (k);
yuuji@0 1797 else if (!compare_cstring (s,"set nntp-range"))
yuuji@0 1798 mail_parameters (NIL,SET_NNTPRANGE,(void *) atol (k));
yuuji@0 1799
yuuji@0 1800 else if (!file) { /* only allowed in system init */
yuuji@0 1801 if (!compare_cstring (s,"set black-box-directory") &&
yuuji@0 1802 !blackBoxDir) blackBoxDir = cpystr (k);
yuuji@0 1803 else if (!compare_cstring(s,"set black-box-default-home-directory")&&
yuuji@0 1804 blackBoxDir && !blackBoxDefaultHome)
yuuji@0 1805 blackBoxDefaultHome = cpystr (k);
yuuji@0 1806 else if (!compare_cstring (s,"set anonymous-home-directory") &&
yuuji@0 1807 !anonymousHome) anonymousHome = cpystr (k);
yuuji@0 1808 /* It's tempting to allow setting the CA path
yuuji@0 1809 * in a user init. However, that opens up a
yuuji@0 1810 * vector of attack big enough to drive a
yuuji@0 1811 * truck through... Resist the temptation.
yuuji@0 1812 */
yuuji@0 1813 else if (!compare_cstring (s,"set CA-certificate-path"))
yuuji@0 1814 sslCApath = cpystr (k);
yuuji@0 1815 else if (!compare_cstring (s,"set disable-plaintext"))
yuuji@0 1816 disablePlaintext = atoi (k);
yuuji@0 1817 else if (!compare_cstring (s,"set allowed-login-attempts"))
yuuji@0 1818 logtry = atoi (k);
yuuji@0 1819 else if (!compare_cstring (s,"set chroot-server"))
yuuji@0 1820 closedBox = atoi (k);
yuuji@0 1821 else if (!compare_cstring (s,"set restrict-mailbox-access"))
yuuji@0 1822 for (k = strtok_r (k,", ",&r); k; k = strtok_r (NIL,", ",&r)) {
yuuji@0 1823 if (!compare_cstring (k,"root")) restrictBox |= RESTRICTROOT;
yuuji@0 1824 else if (!compare_cstring (k,"otherusers"))
yuuji@0 1825 restrictBox |= RESTRICTOTHERUSER;
yuuji@0 1826 else if (!compare_cstring (k,"all")) restrictBox = -1;
yuuji@0 1827 }
yuuji@0 1828 else if (!compare_cstring (s,"set advertise-the-world"))
yuuji@0 1829 advertisetheworld = atoi (k);
yuuji@0 1830 else if (!compare_cstring (s,"set limited-advertise"))
yuuji@0 1831 limitedadvertise = atoi (k);
yuuji@0 1832 else if (!compare_cstring
yuuji@0 1833 (s,"set disable-automatic-shared-namespaces"))
yuuji@0 1834 noautomaticsharedns = atoi (k);
yuuji@0 1835 else if (!compare_cstring (s,"set allow-user-config"))
yuuji@0 1836 allowuserconfig = atoi (k);
yuuji@0 1837 else if (!compare_cstring (s,"set allow-reverse-dns"))
yuuji@0 1838 mail_parameters (NIL,SET_ALLOWREVERSEDNS,(void *) atol (k));
yuuji@0 1839 else if (!compare_cstring (s,"set k5-cp-uses-service-name"))
yuuji@0 1840 kerb_cp_svr_name = atoi (k);
yuuji@0 1841 /* must appear in file after any
yuuji@0 1842 * "set disable-plaintext" command! */
yuuji@0 1843 else if (!compare_cstring (s,"set plaintext-allowed-clients")) {
yuuji@0 1844 for (k = strtok_r (k,", ",&r); k && !tcp_isclienthost (k);
yuuji@0 1845 k = strtok_r (NIL,", ",&r));
yuuji@0 1846 if (k) disablePlaintext = 0;
yuuji@0 1847 }
yuuji@0 1848 }
yuuji@0 1849 }
yuuji@0 1850 }
yuuji@0 1851 } while ((s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n')));
yuuji@0 1852 if (f) fclose (f); /* flush the file */
yuuji@0 1853 }
yuuji@0 1854
yuuji@0 1855 /* INBOX create function for tmail/dmail use only
yuuji@0 1856 * Accepts: mail stream
yuuji@0 1857 * path name buffer, preloaded with driver-dependent path
yuuji@0 1858 * Returns: T on success, NIL on failure
yuuji@0 1859 *
yuuji@0 1860 * This routine is evil and a truly incredible kludge. It is private for
yuuji@0 1861 * tmail/dmail and is not supported for any other application.
yuuji@0 1862 */
yuuji@0 1863
yuuji@0 1864 long path_create (MAILSTREAM *stream,char *path)
yuuji@0 1865 {
yuuji@0 1866 long ret;
yuuji@0 1867 short rsave = restrictBox;
yuuji@0 1868 restrictBox = NIL; /* can't restrict */
yuuji@0 1869 if (blackBox) { /* if black box */
yuuji@0 1870 /* toss out driver dependent names */
yuuji@3 1871 sprintf (path,"%s/INBOX",mymailboxdir ());
yuuji@0 1872 blackBox = NIL; /* well that's evil - evil is going on */
yuuji@0 1873 ret = mail_create (stream,path);
yuuji@0 1874 blackBox = T; /* restore the box */
yuuji@0 1875 }
yuuji@0 1876 /* easy thing otherwise */
yuuji@0 1877 else ret = mail_create (stream,path);
yuuji@0 1878 restrictBox = rsave; /* restore restrictions */
yuuji@0 1879 return ret;
yuuji@0 1880 }
yuuji@0 1881
yuuji@0 1882 /* Default block notify routine
yuuji@0 1883 * Accepts: reason for calling
yuuji@0 1884 * data
yuuji@0 1885 * Returns: data
yuuji@0 1886 */
yuuji@0 1887
yuuji@0 1888 void *mm_blocknotify (int reason,void *data)
yuuji@0 1889 {
yuuji@0 1890 void *ret = data;
yuuji@0 1891 switch (reason) {
yuuji@0 1892 case BLOCK_SENSITIVE: /* entering sensitive code */
yuuji@0 1893 ret = (void *) (unsigned long) alarm (0);
yuuji@0 1894 break;
yuuji@0 1895 case BLOCK_NONSENSITIVE: /* exiting sensitive code */
yuuji@0 1896 if ((unsigned long) data) alarm ((unsigned long) data);
yuuji@0 1897 break;
yuuji@0 1898 default: /* ignore all other reasons */
yuuji@0 1899 break;
yuuji@0 1900 }
yuuji@0 1901 return ret;
yuuji@0 1902 }

UW-IMAP'd extensions by yuuji