1c2aa98e2SPeter Wemm /*- 2c2aa98e2SPeter Wemm * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3c2aa98e2SPeter Wemm * Copyright (c) 1990, 1993, 1994 4c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 5c2aa98e2SPeter Wemm * 6c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 7c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 8c2aa98e2SPeter Wemm * the sendmail distribution. 9c2aa98e2SPeter Wemm * 10c2aa98e2SPeter Wemm */ 11c2aa98e2SPeter Wemm 12c2aa98e2SPeter Wemm #ifndef lint 13c2aa98e2SPeter Wemm static char copyright[] = 14c2aa98e2SPeter Wemm "@(#) Copyright (c) 1990, 1993, 1994\n\ 15c2aa98e2SPeter Wemm The Regents of the University of California. All rights reserved.\n"; 16c2aa98e2SPeter Wemm #endif /* not lint */ 17c2aa98e2SPeter Wemm 18c2aa98e2SPeter Wemm #ifndef lint 19c2aa98e2SPeter Wemm static char sccsid[] = "@(#)mail.local.c 8.78 (Berkeley) 5/19/98"; 20c2aa98e2SPeter Wemm #endif /* not lint */ 21c2aa98e2SPeter Wemm 22c2aa98e2SPeter Wemm /* 23c2aa98e2SPeter Wemm * This is not intended to work on System V derived systems 24c2aa98e2SPeter Wemm * such as Solaris or HP-UX, since they use a totally different 25c2aa98e2SPeter Wemm * approach to mailboxes (essentially, they have a setgid program 26c2aa98e2SPeter Wemm * rather than setuid, and they rely on the ability to "give away" 27c2aa98e2SPeter Wemm * files to do their work). IT IS NOT A BUG that this doesn't 28c2aa98e2SPeter Wemm * work on such architectures. 29c2aa98e2SPeter Wemm */ 30c2aa98e2SPeter Wemm 31c2aa98e2SPeter Wemm #include <sys/param.h> 32c2aa98e2SPeter Wemm #include <sys/stat.h> 33c2aa98e2SPeter Wemm #include <sys/socket.h> 34c2aa98e2SPeter Wemm #include <sys/file.h> 35c2aa98e2SPeter Wemm 36c2aa98e2SPeter Wemm #include <netinet/in.h> 37c2aa98e2SPeter Wemm 38c2aa98e2SPeter Wemm #include <errno.h> 39c2aa98e2SPeter Wemm #include <fcntl.h> 40c2aa98e2SPeter Wemm #include <netdb.h> 41c2aa98e2SPeter Wemm #include <pwd.h> 42c2aa98e2SPeter Wemm #include <stdio.h> 43c2aa98e2SPeter Wemm #include <stdlib.h> 44c2aa98e2SPeter Wemm #include <string.h> 45c2aa98e2SPeter Wemm #include <syslog.h> 46c2aa98e2SPeter Wemm #include <time.h> 47c2aa98e2SPeter Wemm #include <unistd.h> 48c2aa98e2SPeter Wemm #ifdef EX_OK 49c2aa98e2SPeter Wemm # undef EX_OK /* unistd.h may have another use for this */ 50c2aa98e2SPeter Wemm #endif 51c2aa98e2SPeter Wemm #include <sysexits.h> 52c2aa98e2SPeter Wemm #include <ctype.h> 53c2aa98e2SPeter Wemm 54c2aa98e2SPeter Wemm #ifdef __STDC__ 55c2aa98e2SPeter Wemm #include <stdarg.h> 56c2aa98e2SPeter Wemm #else 57c2aa98e2SPeter Wemm #include <varargs.h> 58c2aa98e2SPeter Wemm #endif 59c2aa98e2SPeter Wemm 60c2aa98e2SPeter Wemm #if (defined(sun) && defined(__svr4__)) || defined(__SVR4) 61c2aa98e2SPeter Wemm # define USE_LOCKF 1 62c2aa98e2SPeter Wemm # define USE_SETEUID 1 63c2aa98e2SPeter Wemm # define _PATH_MAILDIR "/var/mail" 64c2aa98e2SPeter Wemm #endif 65c2aa98e2SPeter Wemm 66c2aa98e2SPeter Wemm #if (defined(sun) && !defined(__svr4__)) && !defined(__SVR4) 67c2aa98e2SPeter Wemm # ifdef __dead 68c2aa98e2SPeter Wemm # undef __dead 69c2aa98e2SPeter Wemm # define __dead 70c2aa98e2SPeter Wemm # endif 71c2aa98e2SPeter Wemm #endif 72c2aa98e2SPeter Wemm 73c2aa98e2SPeter Wemm #if defined(_AIX) 74c2aa98e2SPeter Wemm # define USE_LOCKF 1 75c2aa98e2SPeter Wemm # define USE_SETEUID 1 76c2aa98e2SPeter Wemm # define USE_VSYSLOG 0 77c2aa98e2SPeter Wemm #endif 78c2aa98e2SPeter Wemm 79c2aa98e2SPeter Wemm #if defined(__hpux) 80c2aa98e2SPeter Wemm # define USE_LOCKF 1 81c2aa98e2SPeter Wemm # define USE_SETRESUID 1 82c2aa98e2SPeter Wemm # define USE_VSYSLOG 0 83c2aa98e2SPeter Wemm # ifdef __dead 84c2aa98e2SPeter Wemm # undef __dead 85c2aa98e2SPeter Wemm # define __dead 86c2aa98e2SPeter Wemm # endif 87c2aa98e2SPeter Wemm #endif 88c2aa98e2SPeter Wemm 89c2aa98e2SPeter Wemm #if defined(_CRAY) 90c2aa98e2SPeter Wemm # if !defined(MAXPATHLEN) 91c2aa98e2SPeter Wemm # define MAXPATHLEN PATHSIZE 92c2aa98e2SPeter Wemm # endif 93c2aa98e2SPeter Wemm # define USE_VSYSLOG 0 94c2aa98e2SPeter Wemm # define _PATH_MAILDIR "/usr/spool/mail" 95c2aa98e2SPeter Wemm #endif 96c2aa98e2SPeter Wemm 97c2aa98e2SPeter Wemm #if defined(ultrix) 98c2aa98e2SPeter Wemm # define USE_VSYSLOG 0 99c2aa98e2SPeter Wemm #endif 100c2aa98e2SPeter Wemm 101c2aa98e2SPeter Wemm #if defined(__osf__) 102c2aa98e2SPeter Wemm # define USE_VSYSLOG 0 103c2aa98e2SPeter Wemm #endif 104c2aa98e2SPeter Wemm 105c2aa98e2SPeter Wemm #if defined(NeXT) 106c2aa98e2SPeter Wemm # include <libc.h> 107c2aa98e2SPeter Wemm # define _PATH_MAILDIR "/usr/spool/mail" 108c2aa98e2SPeter Wemm # define __dead /* empty */ 109c2aa98e2SPeter Wemm # define S_IRUSR S_IREAD 110c2aa98e2SPeter Wemm # define S_IWUSR S_IWRITE 111c2aa98e2SPeter Wemm #endif 112c2aa98e2SPeter Wemm 113c2aa98e2SPeter Wemm #if defined(IRIX64) || defined(IRIX5) || defined(IRIX6) 114c2aa98e2SPeter Wemm # include <paths.h> 115c2aa98e2SPeter Wemm # define HASSTRERROR 1 /* has strerror(3) */ 116c2aa98e2SPeter Wemm #endif 117c2aa98e2SPeter Wemm 118c2aa98e2SPeter Wemm /* 119c2aa98e2SPeter Wemm * If you don't have flock, you could try using lockf instead. 120c2aa98e2SPeter Wemm */ 121c2aa98e2SPeter Wemm 122c2aa98e2SPeter Wemm #ifdef USE_LOCKF 123c2aa98e2SPeter Wemm # define flock(a, b) lockf(a, b, 0) 124c2aa98e2SPeter Wemm # define LOCK_EX F_LOCK 125c2aa98e2SPeter Wemm #endif 126c2aa98e2SPeter Wemm 127c2aa98e2SPeter Wemm #ifndef USE_VSYSLOG 128c2aa98e2SPeter Wemm # define USE_VSYSLOG 1 129c2aa98e2SPeter Wemm #endif 130c2aa98e2SPeter Wemm 131c2aa98e2SPeter Wemm #ifndef LOCK_EX 132c2aa98e2SPeter Wemm # include <sys/file.h> 133c2aa98e2SPeter Wemm #endif 134c2aa98e2SPeter Wemm 135c2aa98e2SPeter Wemm #if defined(BSD4_4) || defined(__GLIBC__) 136c2aa98e2SPeter Wemm # include "pathnames.h" 137c2aa98e2SPeter Wemm #endif 138c2aa98e2SPeter Wemm 139c2aa98e2SPeter Wemm #ifndef __P 140c2aa98e2SPeter Wemm # ifdef __STDC__ 141c2aa98e2SPeter Wemm # define __P(protos) protos 142c2aa98e2SPeter Wemm # else 143c2aa98e2SPeter Wemm # define __P(protos) () 144c2aa98e2SPeter Wemm # define const 145c2aa98e2SPeter Wemm # endif 146c2aa98e2SPeter Wemm #endif 147c2aa98e2SPeter Wemm #ifndef __dead 148c2aa98e2SPeter Wemm # if defined(__GNUC__) && (__GNUC__ < 2 || __GNUC_MINOR__ < 5) && !defined(__STRICT_ANSI__) 149c2aa98e2SPeter Wemm # define __dead __volatile 150c2aa98e2SPeter Wemm # else 151c2aa98e2SPeter Wemm # define __dead 152c2aa98e2SPeter Wemm # endif 153c2aa98e2SPeter Wemm #endif 154c2aa98e2SPeter Wemm 155c2aa98e2SPeter Wemm #ifdef BSD4_4 156c2aa98e2SPeter Wemm # define HAS_ST_GEN 1 157c2aa98e2SPeter Wemm #else 158c2aa98e2SPeter Wemm # ifndef _BSD_VA_LIST_ 159c2aa98e2SPeter Wemm # define _BSD_VA_LIST_ va_list 160c2aa98e2SPeter Wemm # endif 161c2aa98e2SPeter Wemm #endif 162c2aa98e2SPeter Wemm 163c2aa98e2SPeter Wemm #if defined(BSD4_4) || defined(linux) 164c2aa98e2SPeter Wemm # define HASSNPRINTF 1 165c2aa98e2SPeter Wemm #else 166c2aa98e2SPeter Wemm # ifndef ultrix 167c2aa98e2SPeter Wemm extern FILE *fdopen __P((int, const char *)); 168c2aa98e2SPeter Wemm # endif 169c2aa98e2SPeter Wemm #endif 170c2aa98e2SPeter Wemm 171c2aa98e2SPeter Wemm #if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) 172c2aa98e2SPeter Wemm # define HASSNPRINTF 1 /* has snprintf starting in 2.6 */ 173c2aa98e2SPeter Wemm #endif 174c2aa98e2SPeter Wemm 175c2aa98e2SPeter Wemm #if !HASSNPRINTF 176c2aa98e2SPeter Wemm extern int snprintf __P((char *, size_t, const char *, ...)); 177c2aa98e2SPeter Wemm # ifndef _CRAY 178c2aa98e2SPeter Wemm extern int vsnprintf __P((char *, size_t, const char *, ...)); 179c2aa98e2SPeter Wemm # endif 180c2aa98e2SPeter Wemm #endif 181c2aa98e2SPeter Wemm 182c2aa98e2SPeter Wemm #if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) 183c2aa98e2SPeter Wemm # ifndef HASSTRERROR 184c2aa98e2SPeter Wemm # define HASSTRERROR 1 185c2aa98e2SPeter Wemm # endif 186c2aa98e2SPeter Wemm #endif 187c2aa98e2SPeter Wemm 188c2aa98e2SPeter Wemm #if !HASSTRERROR 189c2aa98e2SPeter Wemm extern char *strerror __P((int)); 190c2aa98e2SPeter Wemm #endif 191c2aa98e2SPeter Wemm 192c2aa98e2SPeter Wemm /* 193c2aa98e2SPeter Wemm * If you don't have setreuid, and you have saved uids, and you have 194c2aa98e2SPeter Wemm * a seteuid() call that doesn't try to emulate using setuid(), then 195c2aa98e2SPeter Wemm * you can try defining USE_SETEUID. 196c2aa98e2SPeter Wemm */ 197c2aa98e2SPeter Wemm #ifdef USE_SETEUID 198c2aa98e2SPeter Wemm # define setreuid(r, e) seteuid(e) 199c2aa98e2SPeter Wemm #endif 200c2aa98e2SPeter Wemm 201c2aa98e2SPeter Wemm /* 202c2aa98e2SPeter Wemm * And of course on hpux you have setresuid() 203c2aa98e2SPeter Wemm */ 204c2aa98e2SPeter Wemm #ifdef USE_SETRESUID 205c2aa98e2SPeter Wemm # define setreuid(r, e) setresuid(-1, e, -1) 206c2aa98e2SPeter Wemm #endif 207c2aa98e2SPeter Wemm 208c2aa98e2SPeter Wemm #ifndef _PATH_LOCTMP 209c2aa98e2SPeter Wemm # define _PATH_LOCTMP "/tmp/local.XXXXXX" 210c2aa98e2SPeter Wemm #endif 211c2aa98e2SPeter Wemm #ifndef _PATH_MAILDIR 212c2aa98e2SPeter Wemm # define _PATH_MAILDIR "/var/spool/mail" 213c2aa98e2SPeter Wemm #endif 214c2aa98e2SPeter Wemm 215c2aa98e2SPeter Wemm #ifndef S_ISREG 216c2aa98e2SPeter Wemm # define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG) 217c2aa98e2SPeter Wemm #endif 218c2aa98e2SPeter Wemm 219c2aa98e2SPeter Wemm int eval = EX_OK; /* sysexits.h error value. */ 220c2aa98e2SPeter Wemm int lmtpmode = 0; 221c2aa98e2SPeter Wemm u_char tTdvect[100]; 222c2aa98e2SPeter Wemm 223d615a192SPeter Wemm void deliver __P((int, char *, int, int)); 224c2aa98e2SPeter Wemm void e_to_sys __P((int)); 225d615a192SPeter Wemm void err __P((const char *, ...)) __dead2; 226c2aa98e2SPeter Wemm void notifybiff __P((char *)); 227c2aa98e2SPeter Wemm int store __P((char *, int)); 228c2aa98e2SPeter Wemm void usage __P((void)); 229c2aa98e2SPeter Wemm void vwarn __P((const char *, _BSD_VA_LIST_)); 230c2aa98e2SPeter Wemm void warn __P((const char *, ...)); 231c2aa98e2SPeter Wemm void lockmbox __P((char *)); 232c2aa98e2SPeter Wemm void unlockmbox __P((void)); 233c2aa98e2SPeter Wemm void mailerr __P((const char *, const char *, ...)); 234d615a192SPeter Wemm void dolmtp __P((int, int)); 235c2aa98e2SPeter Wemm 236c2aa98e2SPeter Wemm int 237c2aa98e2SPeter Wemm main(argc, argv) 238c2aa98e2SPeter Wemm int argc; 239c2aa98e2SPeter Wemm char *argv[]; 240c2aa98e2SPeter Wemm { 241c2aa98e2SPeter Wemm struct passwd *pw; 242d615a192SPeter Wemm int ch, fd, nobiff, nofsync; 243c2aa98e2SPeter Wemm uid_t uid; 244c2aa98e2SPeter Wemm char *from; 245c2aa98e2SPeter Wemm extern char *optarg; 246c2aa98e2SPeter Wemm extern int optind; 247c2aa98e2SPeter Wemm 248c2aa98e2SPeter Wemm /* make sure we have some open file descriptors */ 249c2aa98e2SPeter Wemm for (fd = 10; fd < 30; fd++) 250c2aa98e2SPeter Wemm (void) close(fd); 251c2aa98e2SPeter Wemm 252c2aa98e2SPeter Wemm /* use a reasonable umask */ 253c2aa98e2SPeter Wemm (void) umask(0077); 254c2aa98e2SPeter Wemm 255c2aa98e2SPeter Wemm #ifdef LOG_MAIL 256c2aa98e2SPeter Wemm openlog("mail.local", 0, LOG_MAIL); 257c2aa98e2SPeter Wemm #else 258c2aa98e2SPeter Wemm openlog("mail.local", 0); 259c2aa98e2SPeter Wemm #endif 260c2aa98e2SPeter Wemm 261c2aa98e2SPeter Wemm from = NULL; 262d615a192SPeter Wemm nobiff = 0; 263d615a192SPeter Wemm nofsync = 0; 264d615a192SPeter Wemm while ((ch = getopt(argc, argv, "bdf:r:ls")) != -1) 265c2aa98e2SPeter Wemm switch(ch) { 266d615a192SPeter Wemm case 'b': 267d615a192SPeter Wemm nobiff++; 268d615a192SPeter Wemm break; 269c2aa98e2SPeter Wemm case 'd': /* Backward compatible. */ 270c2aa98e2SPeter Wemm break; 271c2aa98e2SPeter Wemm case 'f': 272c2aa98e2SPeter Wemm case 'r': /* Backward compatible. */ 273c2aa98e2SPeter Wemm if (from != NULL) { 274c2aa98e2SPeter Wemm warn("multiple -f options"); 275c2aa98e2SPeter Wemm usage(); 276c2aa98e2SPeter Wemm } 277c2aa98e2SPeter Wemm from = optarg; 278c2aa98e2SPeter Wemm break; 279c2aa98e2SPeter Wemm case 'l': 280c2aa98e2SPeter Wemm lmtpmode++; 281c2aa98e2SPeter Wemm break; 282d615a192SPeter Wemm case 's': 283d615a192SPeter Wemm nofsync++; 284d615a192SPeter Wemm break; 285c2aa98e2SPeter Wemm case '?': 286c2aa98e2SPeter Wemm default: 287c2aa98e2SPeter Wemm usage(); 288c2aa98e2SPeter Wemm } 289c2aa98e2SPeter Wemm argc -= optind; 290c2aa98e2SPeter Wemm argv += optind; 291c2aa98e2SPeter Wemm 292c2aa98e2SPeter Wemm if (lmtpmode) 293d615a192SPeter Wemm dolmtp(nobiff, nofsync); 294c2aa98e2SPeter Wemm 295c2aa98e2SPeter Wemm if (!*argv) 296c2aa98e2SPeter Wemm usage(); 297c2aa98e2SPeter Wemm 298c2aa98e2SPeter Wemm /* 299c2aa98e2SPeter Wemm * If from not specified, use the name from getlogin() if the 300c2aa98e2SPeter Wemm * uid matches, otherwise, use the name from the password file 301c2aa98e2SPeter Wemm * corresponding to the uid. 302c2aa98e2SPeter Wemm */ 303c2aa98e2SPeter Wemm uid = getuid(); 304c2aa98e2SPeter Wemm if (!from && (!(from = getlogin()) || 305c2aa98e2SPeter Wemm !(pw = getpwnam(from)) || pw->pw_uid != uid)) 306c2aa98e2SPeter Wemm from = (pw = getpwuid(uid)) ? pw->pw_name : "???"; 307c2aa98e2SPeter Wemm 308c2aa98e2SPeter Wemm /* 309c2aa98e2SPeter Wemm * There is no way to distinguish the error status of one delivery 310c2aa98e2SPeter Wemm * from the rest of the deliveries. So, if we failed hard on one 311c2aa98e2SPeter Wemm * or more deliveries, but had no failures on any of the others, we 312c2aa98e2SPeter Wemm * return a hard failure. If we failed temporarily on one or more 313c2aa98e2SPeter Wemm * deliveries, we return a temporary failure regardless of the other 314c2aa98e2SPeter Wemm * failures. This results in the delivery being reattempted later 315c2aa98e2SPeter Wemm * at the expense of repeated failures and multiple deliveries. 316c2aa98e2SPeter Wemm */ 317c2aa98e2SPeter Wemm for (fd = store(from, 0); *argv; ++argv) 318d615a192SPeter Wemm deliver(fd, *argv, nobiff, nofsync); 319c2aa98e2SPeter Wemm exit(eval); 320c2aa98e2SPeter Wemm } 321c2aa98e2SPeter Wemm 322c2aa98e2SPeter Wemm char * 323c2aa98e2SPeter Wemm parseaddr(s) 324c2aa98e2SPeter Wemm char *s; 325c2aa98e2SPeter Wemm { 326c2aa98e2SPeter Wemm char *p; 327c2aa98e2SPeter Wemm int len; 328c2aa98e2SPeter Wemm 329c2aa98e2SPeter Wemm if (*s++ != '<') 330c2aa98e2SPeter Wemm return NULL; 331c2aa98e2SPeter Wemm 332c2aa98e2SPeter Wemm p = s; 333c2aa98e2SPeter Wemm 334c2aa98e2SPeter Wemm /* at-domain-list */ 335c2aa98e2SPeter Wemm while (*p == '@') { 336c2aa98e2SPeter Wemm p++; 337c2aa98e2SPeter Wemm if (*p == '[') { 338c2aa98e2SPeter Wemm p++; 339c2aa98e2SPeter Wemm while (isascii(*p) && 340c2aa98e2SPeter Wemm (isalnum(*p) || *p == '.' || 341c2aa98e2SPeter Wemm *p == '-' || *p == ':')) 342c2aa98e2SPeter Wemm p++; 343c2aa98e2SPeter Wemm if (*p++ != ']') 344c2aa98e2SPeter Wemm return NULL; 345c2aa98e2SPeter Wemm } else { 346c2aa98e2SPeter Wemm while ((isascii(*p) && isalnum(*p)) || 347c2aa98e2SPeter Wemm *p == '.' || *p == '-') 348c2aa98e2SPeter Wemm p++; 349c2aa98e2SPeter Wemm } 350c2aa98e2SPeter Wemm if (*p == ',' && p[1] == '@') 351c2aa98e2SPeter Wemm p++; 352c2aa98e2SPeter Wemm else if (*p == ':' && p[1] != '@') 353c2aa98e2SPeter Wemm p++; 354c2aa98e2SPeter Wemm else 355c2aa98e2SPeter Wemm return NULL; 356c2aa98e2SPeter Wemm } 357c2aa98e2SPeter Wemm 358c2aa98e2SPeter Wemm /* local-part */ 359c2aa98e2SPeter Wemm if (*p == '\"') { 360c2aa98e2SPeter Wemm p++; 361c2aa98e2SPeter Wemm while (*p && *p != '\"') { 362c2aa98e2SPeter Wemm if (*p == '\\') { 363c2aa98e2SPeter Wemm if (!*++p) 364c2aa98e2SPeter Wemm return NULL; 365c2aa98e2SPeter Wemm } 366c2aa98e2SPeter Wemm p++; 367c2aa98e2SPeter Wemm } 368c2aa98e2SPeter Wemm if (!*p++) 369c2aa98e2SPeter Wemm return NULL; 370c2aa98e2SPeter Wemm } else { 371c2aa98e2SPeter Wemm while (*p && *p != '@' && *p != '>') { 372c2aa98e2SPeter Wemm if (*p == '\\') { 373c2aa98e2SPeter Wemm if (!*++p) 374c2aa98e2SPeter Wemm return NULL; 375c2aa98e2SPeter Wemm } else { 376c2aa98e2SPeter Wemm if (*p <= ' ' || (*p & 128) || 377c2aa98e2SPeter Wemm strchr("<>()[]\\,;:\"", *p)) 378c2aa98e2SPeter Wemm return NULL; 379c2aa98e2SPeter Wemm } 380c2aa98e2SPeter Wemm p++; 381c2aa98e2SPeter Wemm } 382c2aa98e2SPeter Wemm } 383c2aa98e2SPeter Wemm 384c2aa98e2SPeter Wemm /* @domain */ 385c2aa98e2SPeter Wemm if (*p == '@') { 386c2aa98e2SPeter Wemm p++; 387c2aa98e2SPeter Wemm if (*p == '[') { 388c2aa98e2SPeter Wemm p++; 389c2aa98e2SPeter Wemm while (isascii(*p) && 390c2aa98e2SPeter Wemm (isalnum(*p) || *p == '.' || 391c2aa98e2SPeter Wemm *p == '-' || *p == ':')) 392c2aa98e2SPeter Wemm p++; 393c2aa98e2SPeter Wemm if (*p++ != ']') 394c2aa98e2SPeter Wemm return NULL; 395c2aa98e2SPeter Wemm } else { 396c2aa98e2SPeter Wemm while ((isascii(*p) && isalnum(*p)) || 397c2aa98e2SPeter Wemm *p == '.' || *p == '-') 398c2aa98e2SPeter Wemm p++; 399c2aa98e2SPeter Wemm } 400c2aa98e2SPeter Wemm } 401c2aa98e2SPeter Wemm 402c2aa98e2SPeter Wemm if (*p++ != '>') 403c2aa98e2SPeter Wemm return NULL; 404c2aa98e2SPeter Wemm if (*p && *p != ' ') 405c2aa98e2SPeter Wemm return NULL; 406c2aa98e2SPeter Wemm len = p - s - 1; 407c2aa98e2SPeter Wemm 408c2aa98e2SPeter Wemm p = malloc(len + 1); 409c2aa98e2SPeter Wemm if (p == NULL) { 410c2aa98e2SPeter Wemm printf("421 4.3.0 memory exhausted\r\n"); 411c2aa98e2SPeter Wemm exit(EX_TEMPFAIL); 412c2aa98e2SPeter Wemm } 413c2aa98e2SPeter Wemm 414c2aa98e2SPeter Wemm strncpy(p, s, len); 415c2aa98e2SPeter Wemm p[len] = '\0'; 416c2aa98e2SPeter Wemm return p; 417c2aa98e2SPeter Wemm } 418c2aa98e2SPeter Wemm 419c2aa98e2SPeter Wemm char * 420c2aa98e2SPeter Wemm process_recipient(addr) 421c2aa98e2SPeter Wemm char *addr; 422c2aa98e2SPeter Wemm { 423c2aa98e2SPeter Wemm if (getpwnam(addr) == NULL) { 424c2aa98e2SPeter Wemm return "550 5.1.1 user unknown"; 425c2aa98e2SPeter Wemm } 426c2aa98e2SPeter Wemm 427c2aa98e2SPeter Wemm return NULL; 428c2aa98e2SPeter Wemm } 429c2aa98e2SPeter Wemm 430c2aa98e2SPeter Wemm 431c2aa98e2SPeter Wemm #define RCPT_GROW 30 432c2aa98e2SPeter Wemm 433c2aa98e2SPeter Wemm void 434d615a192SPeter Wemm dolmtp(nobiff, nofsync) 435d615a192SPeter Wemm int nobiff, nofsync; 436c2aa98e2SPeter Wemm { 437c2aa98e2SPeter Wemm char *return_path = NULL; 438c2aa98e2SPeter Wemm char **rcpt_addr = NULL; 439c2aa98e2SPeter Wemm int rcpt_num = 0; 440c2aa98e2SPeter Wemm int rcpt_alloc = 0; 441c2aa98e2SPeter Wemm char myhostname[1024]; 442c2aa98e2SPeter Wemm char buf[4096]; 443c2aa98e2SPeter Wemm char *err; 444c2aa98e2SPeter Wemm int msgfd; 445c2aa98e2SPeter Wemm char *p; 446c2aa98e2SPeter Wemm int i; 447c2aa98e2SPeter Wemm 448c2aa98e2SPeter Wemm gethostname(myhostname, sizeof myhostname - 1); 449c2aa98e2SPeter Wemm 450c2aa98e2SPeter Wemm printf("220 %s LMTP ready\r\n", myhostname); 451c2aa98e2SPeter Wemm for (;;) { 452c2aa98e2SPeter Wemm fflush(stdout); 453c2aa98e2SPeter Wemm if (fgets(buf, sizeof(buf)-1, stdin) == NULL) { 454c2aa98e2SPeter Wemm exit(EX_OK); 455c2aa98e2SPeter Wemm } 456c2aa98e2SPeter Wemm p = buf + strlen(buf) - 1; 457c2aa98e2SPeter Wemm if (p >= buf && *p == '\n') 458c2aa98e2SPeter Wemm *p-- = '\0'; 459c2aa98e2SPeter Wemm if (p >= buf && *p == '\r') 460c2aa98e2SPeter Wemm *p-- = '\0'; 461c2aa98e2SPeter Wemm 462c2aa98e2SPeter Wemm switch (buf[0]) { 463c2aa98e2SPeter Wemm 464c2aa98e2SPeter Wemm case 'd': 465c2aa98e2SPeter Wemm case 'D': 466c2aa98e2SPeter Wemm if (strcasecmp(buf, "data") == 0) { 467c2aa98e2SPeter Wemm if (rcpt_num == 0) { 468c2aa98e2SPeter Wemm printf("503 5.5.1 No recipients\r\n"); 469c2aa98e2SPeter Wemm continue; 470c2aa98e2SPeter Wemm } 471c2aa98e2SPeter Wemm msgfd = store(return_path, rcpt_num); 472c2aa98e2SPeter Wemm if (msgfd == -1) 473c2aa98e2SPeter Wemm continue; 474c2aa98e2SPeter Wemm 475c2aa98e2SPeter Wemm for (i = 0; i < rcpt_num; i++) { 476c2aa98e2SPeter Wemm p = strchr(rcpt_addr[i], '+'); 477c2aa98e2SPeter Wemm if (p != NULL) 478c2aa98e2SPeter Wemm *p++ = '\0'; 479d615a192SPeter Wemm deliver(msgfd, rcpt_addr[i], nobiff, 480d615a192SPeter Wemm nofsync); 481c2aa98e2SPeter Wemm } 482c2aa98e2SPeter Wemm close(msgfd); 483c2aa98e2SPeter Wemm goto rset; 484c2aa98e2SPeter Wemm } 485c2aa98e2SPeter Wemm goto syntaxerr; 486c2aa98e2SPeter Wemm 487c2aa98e2SPeter Wemm case 'l': 488c2aa98e2SPeter Wemm case 'L': 489c2aa98e2SPeter Wemm if (strncasecmp(buf, "lhlo ", 5) == 0) { 490c2aa98e2SPeter Wemm printf("250-%s\r\n250-8BITMIME\r\n250-ENHANCEDSTATUSCODES\r\n250 PIPELINING\r\n", 491c2aa98e2SPeter Wemm myhostname); 492c2aa98e2SPeter Wemm continue; 493c2aa98e2SPeter Wemm } 494c2aa98e2SPeter Wemm goto syntaxerr; 495c2aa98e2SPeter Wemm 496c2aa98e2SPeter Wemm case 'm': 497c2aa98e2SPeter Wemm case 'M': 498c2aa98e2SPeter Wemm if (strncasecmp(buf, "mail ", 5) == 0) { 499c2aa98e2SPeter Wemm if (return_path != NULL) { 500c2aa98e2SPeter Wemm printf("503 5.5.1 Nested MAIL command\r\n"); 501c2aa98e2SPeter Wemm continue; 502c2aa98e2SPeter Wemm } 503c2aa98e2SPeter Wemm if (strncasecmp(buf+5, "from:", 5) != 0 || 504c2aa98e2SPeter Wemm ((return_path = parseaddr(buf+10)) == NULL)) { 505c2aa98e2SPeter Wemm printf("501 5.5.4 Syntax error in parameters\r\n"); 506c2aa98e2SPeter Wemm continue; 507c2aa98e2SPeter Wemm } 508c2aa98e2SPeter Wemm printf("250 2.5.0 ok\r\n"); 509c2aa98e2SPeter Wemm continue; 510c2aa98e2SPeter Wemm } 511c2aa98e2SPeter Wemm goto syntaxerr; 512c2aa98e2SPeter Wemm 513c2aa98e2SPeter Wemm case 'n': 514c2aa98e2SPeter Wemm case 'N': 515c2aa98e2SPeter Wemm if (strcasecmp(buf, "noop") == 0) { 516c2aa98e2SPeter Wemm printf("250 2.0.0 ok\r\n"); 517c2aa98e2SPeter Wemm continue; 518c2aa98e2SPeter Wemm } 519c2aa98e2SPeter Wemm goto syntaxerr; 520c2aa98e2SPeter Wemm 521c2aa98e2SPeter Wemm case 'q': 522c2aa98e2SPeter Wemm case 'Q': 523c2aa98e2SPeter Wemm if (strcasecmp(buf, "quit") == 0) { 524c2aa98e2SPeter Wemm printf("221 2.0.0 bye\r\n"); 525c2aa98e2SPeter Wemm exit(EX_OK); 526c2aa98e2SPeter Wemm } 527c2aa98e2SPeter Wemm goto syntaxerr; 528c2aa98e2SPeter Wemm 529c2aa98e2SPeter Wemm case 'r': 530c2aa98e2SPeter Wemm case 'R': 531c2aa98e2SPeter Wemm if (strncasecmp(buf, "rcpt ", 5) == 0) { 532c2aa98e2SPeter Wemm if (return_path == NULL) { 533c2aa98e2SPeter Wemm printf("503 5.5.1 Need MAIL command\r\n"); 534c2aa98e2SPeter Wemm continue; 535c2aa98e2SPeter Wemm } 536c2aa98e2SPeter Wemm if (rcpt_num >= rcpt_alloc) { 537c2aa98e2SPeter Wemm rcpt_alloc += RCPT_GROW; 538c2aa98e2SPeter Wemm rcpt_addr = (char **) 539c2aa98e2SPeter Wemm realloc((char *)rcpt_addr, 540c2aa98e2SPeter Wemm rcpt_alloc * sizeof(char **)); 541c2aa98e2SPeter Wemm if (rcpt_addr == NULL) { 542c2aa98e2SPeter Wemm printf("421 4.3.0 memory exhausted\r\n"); 543c2aa98e2SPeter Wemm exit(EX_TEMPFAIL); 544c2aa98e2SPeter Wemm } 545c2aa98e2SPeter Wemm } 546c2aa98e2SPeter Wemm if (strncasecmp(buf+5, "to:", 3) != 0 || 547c2aa98e2SPeter Wemm ((rcpt_addr[rcpt_num] = parseaddr(buf+8)) == NULL)) { 548c2aa98e2SPeter Wemm printf("501 5.5.4 Syntax error in parameters\r\n"); 549c2aa98e2SPeter Wemm continue; 550c2aa98e2SPeter Wemm } 551c2aa98e2SPeter Wemm if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) { 552c2aa98e2SPeter Wemm printf("%s\r\n", err); 553c2aa98e2SPeter Wemm continue; 554c2aa98e2SPeter Wemm } 555c2aa98e2SPeter Wemm rcpt_num++; 556c2aa98e2SPeter Wemm printf("250 2.1.5 ok\r\n"); 557c2aa98e2SPeter Wemm continue; 558c2aa98e2SPeter Wemm } 559c2aa98e2SPeter Wemm else if (strcasecmp(buf, "rset") == 0) { 560c2aa98e2SPeter Wemm printf("250 2.0.0 ok\r\n"); 561c2aa98e2SPeter Wemm 562c2aa98e2SPeter Wemm rset: 563c2aa98e2SPeter Wemm while (rcpt_num) { 564c2aa98e2SPeter Wemm free(rcpt_addr[--rcpt_num]); 565c2aa98e2SPeter Wemm } 566c2aa98e2SPeter Wemm if (return_path != NULL) 567c2aa98e2SPeter Wemm free(return_path); 568c2aa98e2SPeter Wemm return_path = NULL; 569c2aa98e2SPeter Wemm continue; 570c2aa98e2SPeter Wemm } 571c2aa98e2SPeter Wemm goto syntaxerr; 572c2aa98e2SPeter Wemm 573c2aa98e2SPeter Wemm case 'v': 574c2aa98e2SPeter Wemm case 'V': 575c2aa98e2SPeter Wemm if (strncasecmp(buf, "vrfy ", 5) == 0) { 576c2aa98e2SPeter Wemm printf("252 2.3.3 try RCPT to attempt delivery\r\n"); 577c2aa98e2SPeter Wemm continue; 578c2aa98e2SPeter Wemm } 579c2aa98e2SPeter Wemm goto syntaxerr; 580c2aa98e2SPeter Wemm 581c2aa98e2SPeter Wemm default: 582c2aa98e2SPeter Wemm syntaxerr: 583c2aa98e2SPeter Wemm printf("500 5.5.2 Syntax error\r\n"); 584c2aa98e2SPeter Wemm continue; 585c2aa98e2SPeter Wemm } 586c2aa98e2SPeter Wemm } 587c2aa98e2SPeter Wemm } 588c2aa98e2SPeter Wemm 589c2aa98e2SPeter Wemm int 590c2aa98e2SPeter Wemm store(from, lmtprcpts) 591c2aa98e2SPeter Wemm char *from; 592c2aa98e2SPeter Wemm int lmtprcpts; 593c2aa98e2SPeter Wemm { 594c2aa98e2SPeter Wemm FILE *fp; 595c2aa98e2SPeter Wemm time_t tval; 596c2aa98e2SPeter Wemm int fd, eline; 597c2aa98e2SPeter Wemm char line[2048]; 598c2aa98e2SPeter Wemm char tmpbuf[sizeof _PATH_LOCTMP + 1]; 599c2aa98e2SPeter Wemm 600c2aa98e2SPeter Wemm strcpy(tmpbuf, _PATH_LOCTMP); 601c2aa98e2SPeter Wemm if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) { 602c2aa98e2SPeter Wemm if (lmtprcpts) { 603c2aa98e2SPeter Wemm printf("451 4.3.0 unable to open temporary file\r\n"); 604c2aa98e2SPeter Wemm return -1; 605c2aa98e2SPeter Wemm } else { 606c2aa98e2SPeter Wemm e_to_sys(errno); 607c2aa98e2SPeter Wemm err("unable to open temporary file"); 608c2aa98e2SPeter Wemm } 609c2aa98e2SPeter Wemm } 610c2aa98e2SPeter Wemm (void)unlink(tmpbuf); 611c2aa98e2SPeter Wemm 612c2aa98e2SPeter Wemm if (lmtpmode) { 613c2aa98e2SPeter Wemm printf("354 go ahead\r\n"); 614c2aa98e2SPeter Wemm fflush(stdout); 615c2aa98e2SPeter Wemm } 616c2aa98e2SPeter Wemm 617c2aa98e2SPeter Wemm (void)time(&tval); 618c2aa98e2SPeter Wemm (void)fprintf(fp, "From %s %s", from, ctime(&tval)); 619c2aa98e2SPeter Wemm 620c2aa98e2SPeter Wemm line[0] = '\0'; 621c2aa98e2SPeter Wemm for (eline = 1; fgets(line, sizeof(line), stdin);) { 622c2aa98e2SPeter Wemm if (line[strlen(line)-2] == '\r') { 623c2aa98e2SPeter Wemm strcpy(line+strlen(line)-2, "\n"); 624c2aa98e2SPeter Wemm } 625c2aa98e2SPeter Wemm if (lmtprcpts && line[0] == '.') { 626c2aa98e2SPeter Wemm if (line[1] == '\n') 627c2aa98e2SPeter Wemm goto lmtpdot; 628c2aa98e2SPeter Wemm strcpy(line, line+1); 629c2aa98e2SPeter Wemm } 630c2aa98e2SPeter Wemm if (line[0] == '\n') 631c2aa98e2SPeter Wemm eline = 1; 632c2aa98e2SPeter Wemm else { 633c2aa98e2SPeter Wemm if (eline && line[0] == 'F' && 634c2aa98e2SPeter Wemm !memcmp(line, "From ", 5)) 635c2aa98e2SPeter Wemm (void)putc('>', fp); 636c2aa98e2SPeter Wemm eline = 0; 637c2aa98e2SPeter Wemm } 638c2aa98e2SPeter Wemm (void)fprintf(fp, "%s", line); 639c2aa98e2SPeter Wemm if (ferror(fp)) { 640c2aa98e2SPeter Wemm if (lmtprcpts) { 641c2aa98e2SPeter Wemm while (lmtprcpts--) { 642c2aa98e2SPeter Wemm printf("451 4.3.0 temporary file write error\r\n"); 643c2aa98e2SPeter Wemm } 644c2aa98e2SPeter Wemm fclose(fp); 645c2aa98e2SPeter Wemm return -1; 646c2aa98e2SPeter Wemm } else { 647c2aa98e2SPeter Wemm e_to_sys(errno); 648c2aa98e2SPeter Wemm err("temporary file write error"); 649c2aa98e2SPeter Wemm } 650c2aa98e2SPeter Wemm } 651c2aa98e2SPeter Wemm } 652c2aa98e2SPeter Wemm 653c2aa98e2SPeter Wemm if (lmtprcpts) { 654c2aa98e2SPeter Wemm /* Got a premature EOF -- toss message and exit */ 655c2aa98e2SPeter Wemm exit(EX_OK); 656c2aa98e2SPeter Wemm } 657c2aa98e2SPeter Wemm 658c2aa98e2SPeter Wemm /* If message not newline terminated, need an extra. */ 659c2aa98e2SPeter Wemm if (strchr(line, '\n') == NULL) 660c2aa98e2SPeter Wemm (void)putc('\n', fp); 661c2aa98e2SPeter Wemm 662c2aa98e2SPeter Wemm lmtpdot: 663c2aa98e2SPeter Wemm 664c2aa98e2SPeter Wemm /* Output a newline; note, empty messages are allowed. */ 665c2aa98e2SPeter Wemm (void)putc('\n', fp); 666c2aa98e2SPeter Wemm 667c2aa98e2SPeter Wemm if (fflush(fp) == EOF || ferror(fp)) { 668c2aa98e2SPeter Wemm if (lmtprcpts) { 669c2aa98e2SPeter Wemm while (lmtprcpts--) { 670c2aa98e2SPeter Wemm printf("451 4.3.0 temporary file write error\r\n"); 671c2aa98e2SPeter Wemm } 672c2aa98e2SPeter Wemm fclose(fp); 673c2aa98e2SPeter Wemm return -1; 674c2aa98e2SPeter Wemm } else { 675c2aa98e2SPeter Wemm e_to_sys(errno); 676c2aa98e2SPeter Wemm err("temporary file write error"); 677c2aa98e2SPeter Wemm } 678c2aa98e2SPeter Wemm } 679c2aa98e2SPeter Wemm return (fd); 680c2aa98e2SPeter Wemm } 681c2aa98e2SPeter Wemm 682c2aa98e2SPeter Wemm void 683d615a192SPeter Wemm deliver(fd, name, nobiff, nofsync) 684c2aa98e2SPeter Wemm int fd; 685c2aa98e2SPeter Wemm char *name; 686d615a192SPeter Wemm int nobiff, nofsync; 687c2aa98e2SPeter Wemm { 688c2aa98e2SPeter Wemm struct stat fsb, sb; 689c2aa98e2SPeter Wemm struct passwd *pw; 690c2aa98e2SPeter Wemm int mbfd, nr, nw, off; 691c2aa98e2SPeter Wemm char *p; 692c2aa98e2SPeter Wemm char biffmsg[100], buf[8*1024], path[MAXPATHLEN]; 693c2aa98e2SPeter Wemm off_t curoff; 694c2aa98e2SPeter Wemm extern char *quad_to_string(); 695c2aa98e2SPeter Wemm 696c2aa98e2SPeter Wemm /* 697c2aa98e2SPeter Wemm * Disallow delivery to unknown names -- special mailboxes can be 698c2aa98e2SPeter Wemm * handled in the sendmail aliases file. 699c2aa98e2SPeter Wemm */ 700c2aa98e2SPeter Wemm if ((pw = getpwnam(name)) == NULL) { 701c2aa98e2SPeter Wemm if (eval != EX_TEMPFAIL) 702c2aa98e2SPeter Wemm eval = EX_UNAVAILABLE; 703c2aa98e2SPeter Wemm if (lmtpmode) { 704c2aa98e2SPeter Wemm if (eval == EX_TEMPFAIL) { 705c2aa98e2SPeter Wemm printf("451 4.3.0 cannot lookup name: %s\r\n", name); 706c2aa98e2SPeter Wemm } else { 707c2aa98e2SPeter Wemm printf("550 5.1.1 unknown name: %s\r\n", name); 708c2aa98e2SPeter Wemm } 709c2aa98e2SPeter Wemm } 710c2aa98e2SPeter Wemm else { 711c2aa98e2SPeter Wemm warn("unknown name: %s", name); 712c2aa98e2SPeter Wemm } 713c2aa98e2SPeter Wemm return; 714c2aa98e2SPeter Wemm } 715c2aa98e2SPeter Wemm endpwent(); 716c2aa98e2SPeter Wemm 717c2aa98e2SPeter Wemm /* 718c2aa98e2SPeter Wemm * Keep name reasonably short to avoid buffer overruns. 719c2aa98e2SPeter Wemm * This isn't necessary on BSD because of the proper 720c2aa98e2SPeter Wemm * definition of snprintf(), but it can cause problems 721c2aa98e2SPeter Wemm * on other systems. 722c2aa98e2SPeter Wemm * Also, clear out any bogus characters. 723c2aa98e2SPeter Wemm */ 724c2aa98e2SPeter Wemm 725c2aa98e2SPeter Wemm if (strlen(name) > 40) 726c2aa98e2SPeter Wemm name[40] = '\0'; 727c2aa98e2SPeter Wemm for (p = name; *p != '\0'; p++) 728c2aa98e2SPeter Wemm { 729c2aa98e2SPeter Wemm if (!isascii(*p)) 730c2aa98e2SPeter Wemm *p &= 0x7f; 731c2aa98e2SPeter Wemm else if (!isprint(*p)) 732c2aa98e2SPeter Wemm *p = '.'; 733c2aa98e2SPeter Wemm } 734c2aa98e2SPeter Wemm 735c2aa98e2SPeter Wemm (void)snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name); 736c2aa98e2SPeter Wemm 737c2aa98e2SPeter Wemm /* 738c2aa98e2SPeter Wemm * If the mailbox is linked or a symlink, fail. There's an obvious 739c2aa98e2SPeter Wemm * race here, that the file was replaced with a symbolic link after 740c2aa98e2SPeter Wemm * the lstat returned, but before the open. We attempt to detect 741c2aa98e2SPeter Wemm * this by comparing the original stat information and information 742c2aa98e2SPeter Wemm * returned by an fstat of the file descriptor returned by the open. 743c2aa98e2SPeter Wemm * 744c2aa98e2SPeter Wemm * NB: this is a symptom of a larger problem, that the mail spooling 745c2aa98e2SPeter Wemm * directory is writeable by the wrong users. If that directory is 746c2aa98e2SPeter Wemm * writeable, system security is compromised for other reasons, and 747c2aa98e2SPeter Wemm * it cannot be fixed here. 748c2aa98e2SPeter Wemm * 749c2aa98e2SPeter Wemm * If we created the mailbox, set the owner/group. If that fails, 750c2aa98e2SPeter Wemm * just return. Another process may have already opened it, so we 751c2aa98e2SPeter Wemm * can't unlink it. Historically, binmail set the owner/group at 752c2aa98e2SPeter Wemm * each mail delivery. We no longer do this, assuming that if the 753c2aa98e2SPeter Wemm * ownership or permissions were changed there was a reason. 754c2aa98e2SPeter Wemm * 755c2aa98e2SPeter Wemm * XXX 756c2aa98e2SPeter Wemm * open(2) should support flock'ing the file. 757c2aa98e2SPeter Wemm */ 758c2aa98e2SPeter Wemm tryagain: 759c2aa98e2SPeter Wemm lockmbox(path); 760c2aa98e2SPeter Wemm if (lstat(path, &sb) < 0) { 761c2aa98e2SPeter Wemm mbfd = open(path, 762c2aa98e2SPeter Wemm O_APPEND|O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); 763c2aa98e2SPeter Wemm if (lstat(path, &sb) < 0) 764c2aa98e2SPeter Wemm { 765c2aa98e2SPeter Wemm eval = EX_CANTCREAT; 766c2aa98e2SPeter Wemm warn("%s: lstat: file changed after open", path); 767c2aa98e2SPeter Wemm goto err1; 768c2aa98e2SPeter Wemm } 769c2aa98e2SPeter Wemm else 770c2aa98e2SPeter Wemm sb.st_uid = pw->pw_uid; 771c2aa98e2SPeter Wemm if (mbfd == -1) { 772c2aa98e2SPeter Wemm if (errno == EEXIST) 773c2aa98e2SPeter Wemm goto tryagain; 774c2aa98e2SPeter Wemm } else if (fchown(mbfd, pw->pw_uid, pw->pw_gid)) { 775c2aa98e2SPeter Wemm mailerr("451 4.3.0", "chown %u.%u: %s", 776c2aa98e2SPeter Wemm pw->pw_uid, pw->pw_gid, name); 777c2aa98e2SPeter Wemm goto err1; 778c2aa98e2SPeter Wemm } 779c2aa98e2SPeter Wemm } else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) { 780c2aa98e2SPeter Wemm mailerr("550 5.2.0", "%s: irregular file", path); 781c2aa98e2SPeter Wemm goto err0; 782c2aa98e2SPeter Wemm } else if (sb.st_uid != pw->pw_uid) { 783c2aa98e2SPeter Wemm eval = EX_CANTCREAT; 784c2aa98e2SPeter Wemm mailerr("550 5.2.0", "%s: wrong ownership (%d)", 785c2aa98e2SPeter Wemm path, sb.st_uid); 786c2aa98e2SPeter Wemm goto err0; 787c2aa98e2SPeter Wemm } else { 788c2aa98e2SPeter Wemm mbfd = open(path, O_APPEND|O_WRONLY, 0); 789c2aa98e2SPeter Wemm } 790c2aa98e2SPeter Wemm 791c2aa98e2SPeter Wemm if (mbfd == -1) { 792c2aa98e2SPeter Wemm mailerr("450 4.2.0", "%s: %s", path, strerror(errno)); 793c2aa98e2SPeter Wemm goto err0; 794c2aa98e2SPeter Wemm } else if (fstat(mbfd, &fsb) < 0 || 795c2aa98e2SPeter Wemm fsb.st_nlink != 1 || 796c2aa98e2SPeter Wemm sb.st_nlink != 1 || 797c2aa98e2SPeter Wemm !S_ISREG(fsb.st_mode) || 798c2aa98e2SPeter Wemm sb.st_dev != fsb.st_dev || 799c2aa98e2SPeter Wemm sb.st_ino != fsb.st_ino || 800c2aa98e2SPeter Wemm #if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ 801c2aa98e2SPeter Wemm sb.st_gen != fsb.st_gen || 802c2aa98e2SPeter Wemm #endif 803c2aa98e2SPeter Wemm sb.st_uid != fsb.st_uid) { 804c2aa98e2SPeter Wemm eval = EX_TEMPFAIL; 805c2aa98e2SPeter Wemm warn("%s: fstat: file changed after open", path); 806c2aa98e2SPeter Wemm goto err1; 807c2aa98e2SPeter Wemm } 808c2aa98e2SPeter Wemm 809c2aa98e2SPeter Wemm /* Wait until we can get a lock on the file. */ 810c2aa98e2SPeter Wemm if (flock(mbfd, LOCK_EX)) { 811c2aa98e2SPeter Wemm mailerr("450 4.2.0", "%s: %s", path, strerror(errno)); 812c2aa98e2SPeter Wemm goto err1; 813c2aa98e2SPeter Wemm } 814c2aa98e2SPeter Wemm 815d615a192SPeter Wemm if (!nobiff) { 816c2aa98e2SPeter Wemm /* Get the starting offset of the new message for biff. */ 817c2aa98e2SPeter Wemm curoff = lseek(mbfd, (off_t)0, SEEK_END); 818c2aa98e2SPeter Wemm if (sizeof curoff > sizeof(long)) 819c2aa98e2SPeter Wemm (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n", 820c2aa98e2SPeter Wemm name, quad_to_string(curoff)); 821c2aa98e2SPeter Wemm else 822c2aa98e2SPeter Wemm (void)snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n", 823c2aa98e2SPeter Wemm name, curoff); 824d615a192SPeter Wemm } 825c2aa98e2SPeter Wemm 826c2aa98e2SPeter Wemm /* Copy the message into the file. */ 827c2aa98e2SPeter Wemm if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { 828c2aa98e2SPeter Wemm mailerr("450 4.2.0", "temporary file: %s", 829c2aa98e2SPeter Wemm strerror(errno)); 830c2aa98e2SPeter Wemm goto err1; 831c2aa98e2SPeter Wemm } 832c2aa98e2SPeter Wemm if (setreuid(0, pw->pw_uid) < 0) { 833c2aa98e2SPeter Wemm mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)", 834c2aa98e2SPeter Wemm pw->pw_uid, strerror(errno), getuid(), geteuid()); 835c2aa98e2SPeter Wemm goto err1; 836c2aa98e2SPeter Wemm } 837c2aa98e2SPeter Wemm #ifdef DEBUG 838c2aa98e2SPeter Wemm printf("new euid = %d\n", geteuid()); 839c2aa98e2SPeter Wemm #endif 840c2aa98e2SPeter Wemm while ((nr = read(fd, buf, sizeof(buf))) > 0) 841c2aa98e2SPeter Wemm for (off = 0; off < nr; off += nw) 842c2aa98e2SPeter Wemm if ((nw = write(mbfd, buf + off, nr - off)) < 0) { 843c2aa98e2SPeter Wemm mailerr("450 4.2.0", "%s: %s", 844c2aa98e2SPeter Wemm path, strerror(errno)); 845c2aa98e2SPeter Wemm goto err3; 846c2aa98e2SPeter Wemm } 847c2aa98e2SPeter Wemm if (nr < 0) { 848c2aa98e2SPeter Wemm mailerr("450 4.2.0", "temporary file: %s", 849c2aa98e2SPeter Wemm strerror(errno)); 850c2aa98e2SPeter Wemm goto err3; 851c2aa98e2SPeter Wemm } 852c2aa98e2SPeter Wemm 853c2aa98e2SPeter Wemm /* Flush to disk, don't wait for update. */ 854d615a192SPeter Wemm if (!nofsync && fsync(mbfd)) { 855c2aa98e2SPeter Wemm mailerr("450 4.2.0", "%s: %s", path, strerror(errno)); 856c2aa98e2SPeter Wemm err3: 857c2aa98e2SPeter Wemm if (setreuid(0, 0) < 0) { 858c2aa98e2SPeter Wemm e_to_sys(errno); 859c2aa98e2SPeter Wemm mailerr("450 4.2.0", "setreuid(0, 0): %s", 860c2aa98e2SPeter Wemm strerror(errno)); 861c2aa98e2SPeter Wemm } 862c2aa98e2SPeter Wemm #ifdef DEBUG 863c2aa98e2SPeter Wemm printf("reset euid = %d\n", geteuid()); 864c2aa98e2SPeter Wemm #endif 865c2aa98e2SPeter Wemm (void)ftruncate(mbfd, curoff); 866c2aa98e2SPeter Wemm err1: (void)close(mbfd); 867c2aa98e2SPeter Wemm err0: unlockmbox(); 868c2aa98e2SPeter Wemm return; 869c2aa98e2SPeter Wemm } 870c2aa98e2SPeter Wemm 871c2aa98e2SPeter Wemm /* Close and check -- NFS doesn't write until the close. */ 872c2aa98e2SPeter Wemm if (close(mbfd)) { 873c2aa98e2SPeter Wemm mailerr("450 4.2.0", "%s: %s", path, strerror(errno)); 874c2aa98e2SPeter Wemm truncate(path, curoff); 875d615a192SPeter Wemm } else if (!nobiff) 876c2aa98e2SPeter Wemm notifybiff(biffmsg); 877c2aa98e2SPeter Wemm 878c2aa98e2SPeter Wemm if (setreuid(0, 0) < 0) { 879c2aa98e2SPeter Wemm mailerr("450 4.2.0", "setreuid(0, 0): %s", 880c2aa98e2SPeter Wemm strerror(errno)); 881c2aa98e2SPeter Wemm goto err0; 882c2aa98e2SPeter Wemm } 883c2aa98e2SPeter Wemm #ifdef DEBUG 884c2aa98e2SPeter Wemm printf("reset euid = %d\n", geteuid()); 885c2aa98e2SPeter Wemm #endif 886c2aa98e2SPeter Wemm unlockmbox(); 887c2aa98e2SPeter Wemm if (lmtpmode) { 888c2aa98e2SPeter Wemm printf("250 2.1.5 %s OK\r\n", name); 889c2aa98e2SPeter Wemm } 890c2aa98e2SPeter Wemm } 891c2aa98e2SPeter Wemm 892c2aa98e2SPeter Wemm /* 893c2aa98e2SPeter Wemm * user.lock files are necessary for compatibility with other 894c2aa98e2SPeter Wemm * systems, e.g., when the mail spool file is NFS exported. 895c2aa98e2SPeter Wemm * Alas, mailbox locking is more than just a local matter. 896c2aa98e2SPeter Wemm * EPA 11/94. 897c2aa98e2SPeter Wemm */ 898c2aa98e2SPeter Wemm 899c2aa98e2SPeter Wemm char lockname[MAXPATHLEN]; 900c2aa98e2SPeter Wemm int locked = 0; 901c2aa98e2SPeter Wemm 902c2aa98e2SPeter Wemm void 903c2aa98e2SPeter Wemm lockmbox(path) 904c2aa98e2SPeter Wemm char *path; 905c2aa98e2SPeter Wemm { 906c2aa98e2SPeter Wemm int statfailed = 0; 907c2aa98e2SPeter Wemm 908c2aa98e2SPeter Wemm if (locked) 909c2aa98e2SPeter Wemm return; 910c2aa98e2SPeter Wemm if (strlen(path) + 6 > sizeof lockname) 911c2aa98e2SPeter Wemm return; 912c2aa98e2SPeter Wemm snprintf(lockname, sizeof lockname, "%s.lock", path); 913c2aa98e2SPeter Wemm for (;; sleep(5)) { 914c2aa98e2SPeter Wemm int fd; 915c2aa98e2SPeter Wemm struct stat st; 916c2aa98e2SPeter Wemm time_t now; 917c2aa98e2SPeter Wemm 918c2aa98e2SPeter Wemm fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0); 919c2aa98e2SPeter Wemm if (fd >= 0) { 920c2aa98e2SPeter Wemm /* defeat lock checking programs which test pid */ 921c2aa98e2SPeter Wemm write(fd, "0", 2); 922c2aa98e2SPeter Wemm locked = 1; 923c2aa98e2SPeter Wemm close(fd); 924c2aa98e2SPeter Wemm return; 925c2aa98e2SPeter Wemm } 926c2aa98e2SPeter Wemm if (stat(lockname, &st) < 0) { 927c2aa98e2SPeter Wemm if (statfailed++ > 5) 928c2aa98e2SPeter Wemm return; 929c2aa98e2SPeter Wemm continue; 930c2aa98e2SPeter Wemm } 931c2aa98e2SPeter Wemm statfailed = 0; 932c2aa98e2SPeter Wemm time(&now); 933c2aa98e2SPeter Wemm if (now < st.st_ctime + 300) 934c2aa98e2SPeter Wemm continue; 935c2aa98e2SPeter Wemm unlink(lockname); 936c2aa98e2SPeter Wemm } 937c2aa98e2SPeter Wemm } 938c2aa98e2SPeter Wemm 939c2aa98e2SPeter Wemm void 940c2aa98e2SPeter Wemm unlockmbox() 941c2aa98e2SPeter Wemm { 942c2aa98e2SPeter Wemm if (!locked) 943c2aa98e2SPeter Wemm return; 944c2aa98e2SPeter Wemm unlink(lockname); 945c2aa98e2SPeter Wemm locked = 0; 946c2aa98e2SPeter Wemm } 947c2aa98e2SPeter Wemm 948c2aa98e2SPeter Wemm void 949c2aa98e2SPeter Wemm notifybiff(msg) 950c2aa98e2SPeter Wemm char *msg; 951c2aa98e2SPeter Wemm { 952c2aa98e2SPeter Wemm static struct sockaddr_in addr; 953c2aa98e2SPeter Wemm static int f = -1; 954c2aa98e2SPeter Wemm struct hostent *hp; 955c2aa98e2SPeter Wemm struct servent *sp; 956c2aa98e2SPeter Wemm int len; 957c2aa98e2SPeter Wemm 958c2aa98e2SPeter Wemm if (addr.sin_family == 0) { 959c2aa98e2SPeter Wemm /* Be silent if biff service not available. */ 960c2aa98e2SPeter Wemm if ((sp = getservbyname("biff", "udp")) == NULL) 961c2aa98e2SPeter Wemm return; 962c2aa98e2SPeter Wemm if ((hp = gethostbyname("localhost")) == NULL) { 963c2aa98e2SPeter Wemm warn("localhost: %s", strerror(errno)); 964c2aa98e2SPeter Wemm return; 965c2aa98e2SPeter Wemm } 966c2aa98e2SPeter Wemm addr.sin_family = hp->h_addrtype; 967c2aa98e2SPeter Wemm memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); 968c2aa98e2SPeter Wemm addr.sin_port = sp->s_port; 969c2aa98e2SPeter Wemm } 970c2aa98e2SPeter Wemm if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 971c2aa98e2SPeter Wemm warn("socket: %s", strerror(errno)); 972c2aa98e2SPeter Wemm return; 973c2aa98e2SPeter Wemm } 974c2aa98e2SPeter Wemm len = strlen(msg) + 1; 975c2aa98e2SPeter Wemm if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr)) 976c2aa98e2SPeter Wemm != len) 977c2aa98e2SPeter Wemm warn("sendto biff: %s", strerror(errno)); 978c2aa98e2SPeter Wemm } 979c2aa98e2SPeter Wemm 980c2aa98e2SPeter Wemm void 981c2aa98e2SPeter Wemm usage() 982c2aa98e2SPeter Wemm { 983c2aa98e2SPeter Wemm eval = EX_USAGE; 984d615a192SPeter Wemm err("usage: mail.local [-b] [-l] [-f from] [-s] user ..."); 985c2aa98e2SPeter Wemm } 986c2aa98e2SPeter Wemm 987c2aa98e2SPeter Wemm void 988c2aa98e2SPeter Wemm #ifdef __STDC__ 989c2aa98e2SPeter Wemm mailerr(const char *hdr, const char *fmt, ...) 990c2aa98e2SPeter Wemm #else 991c2aa98e2SPeter Wemm mailerr(hdr, fmt, va_alist) 992c2aa98e2SPeter Wemm const char *hdr; 993c2aa98e2SPeter Wemm const char *fmt; 994c2aa98e2SPeter Wemm va_dcl 995c2aa98e2SPeter Wemm #endif 996c2aa98e2SPeter Wemm { 997c2aa98e2SPeter Wemm va_list ap; 998c2aa98e2SPeter Wemm 999c2aa98e2SPeter Wemm #ifdef __STDC__ 1000c2aa98e2SPeter Wemm va_start(ap, fmt); 1001c2aa98e2SPeter Wemm #else 1002c2aa98e2SPeter Wemm va_start(ap); 1003c2aa98e2SPeter Wemm #endif 1004c2aa98e2SPeter Wemm if (lmtpmode) 1005c2aa98e2SPeter Wemm { 1006c2aa98e2SPeter Wemm printf("%s ", hdr); 1007c2aa98e2SPeter Wemm vprintf(fmt, ap); 1008c2aa98e2SPeter Wemm printf("\r\n"); 1009c2aa98e2SPeter Wemm } 1010c2aa98e2SPeter Wemm else 1011c2aa98e2SPeter Wemm { 1012c2aa98e2SPeter Wemm e_to_sys(errno); 1013c2aa98e2SPeter Wemm vwarn(fmt, ap); 1014c2aa98e2SPeter Wemm } 1015c2aa98e2SPeter Wemm } 1016c2aa98e2SPeter Wemm 1017c2aa98e2SPeter Wemm #ifdef __STDC__ 1018c2aa98e2SPeter Wemm void 1019c2aa98e2SPeter Wemm err(const char *fmt, ...) 1020c2aa98e2SPeter Wemm #else 1021c2aa98e2SPeter Wemm void 1022c2aa98e2SPeter Wemm err(fmt, va_alist) 1023c2aa98e2SPeter Wemm const char *fmt; 1024c2aa98e2SPeter Wemm va_dcl 1025c2aa98e2SPeter Wemm #endif 1026c2aa98e2SPeter Wemm { 1027c2aa98e2SPeter Wemm va_list ap; 1028c2aa98e2SPeter Wemm 1029c2aa98e2SPeter Wemm #ifdef __STDC__ 1030c2aa98e2SPeter Wemm va_start(ap, fmt); 1031c2aa98e2SPeter Wemm #else 1032c2aa98e2SPeter Wemm va_start(ap); 1033c2aa98e2SPeter Wemm #endif 1034c2aa98e2SPeter Wemm vwarn(fmt, ap); 1035c2aa98e2SPeter Wemm va_end(ap); 1036c2aa98e2SPeter Wemm 1037c2aa98e2SPeter Wemm exit(eval); 1038c2aa98e2SPeter Wemm } 1039c2aa98e2SPeter Wemm 1040c2aa98e2SPeter Wemm void 1041c2aa98e2SPeter Wemm #ifdef __STDC__ 1042c2aa98e2SPeter Wemm warn(const char *fmt, ...) 1043c2aa98e2SPeter Wemm #else 1044c2aa98e2SPeter Wemm warn(fmt, va_alist) 1045c2aa98e2SPeter Wemm const char *fmt; 1046c2aa98e2SPeter Wemm va_dcl 1047c2aa98e2SPeter Wemm #endif 1048c2aa98e2SPeter Wemm { 1049c2aa98e2SPeter Wemm va_list ap; 1050c2aa98e2SPeter Wemm 1051c2aa98e2SPeter Wemm #ifdef __STDC__ 1052c2aa98e2SPeter Wemm va_start(ap, fmt); 1053c2aa98e2SPeter Wemm #else 1054c2aa98e2SPeter Wemm va_start(ap); 1055c2aa98e2SPeter Wemm #endif 1056c2aa98e2SPeter Wemm vwarn(fmt, ap); 1057c2aa98e2SPeter Wemm va_end(ap); 1058c2aa98e2SPeter Wemm } 1059c2aa98e2SPeter Wemm 1060c2aa98e2SPeter Wemm void 1061c2aa98e2SPeter Wemm vwarn(fmt, ap) 1062c2aa98e2SPeter Wemm const char *fmt; 1063c2aa98e2SPeter Wemm _BSD_VA_LIST_ ap; 1064c2aa98e2SPeter Wemm { 1065c2aa98e2SPeter Wemm /* 1066c2aa98e2SPeter Wemm * Log the message to stderr. 1067c2aa98e2SPeter Wemm * 1068c2aa98e2SPeter Wemm * Don't use LOG_PERROR as an openlog() flag to do this, 1069c2aa98e2SPeter Wemm * it's not portable enough. 1070c2aa98e2SPeter Wemm */ 1071c2aa98e2SPeter Wemm if (eval != EX_USAGE) 1072c2aa98e2SPeter Wemm (void)fprintf(stderr, "mail.local: "); 1073c2aa98e2SPeter Wemm (void)vfprintf(stderr, fmt, ap); 1074c2aa98e2SPeter Wemm (void)fprintf(stderr, "\n"); 1075c2aa98e2SPeter Wemm 1076c2aa98e2SPeter Wemm #if USE_VSYSLOG 1077c2aa98e2SPeter Wemm /* Log the message to syslog. */ 1078c2aa98e2SPeter Wemm vsyslog(LOG_ERR, fmt, ap); 1079c2aa98e2SPeter Wemm #else 1080c2aa98e2SPeter Wemm { 1081c2aa98e2SPeter Wemm char fmtbuf[10240]; 1082c2aa98e2SPeter Wemm 1083c2aa98e2SPeter Wemm (void) vsnprintf(fmtbuf, sizeof fmtbuf, fmt, ap); 1084c2aa98e2SPeter Wemm syslog(LOG_ERR, "%s", fmtbuf); 1085c2aa98e2SPeter Wemm } 1086c2aa98e2SPeter Wemm #endif 1087c2aa98e2SPeter Wemm } 1088c2aa98e2SPeter Wemm 1089c2aa98e2SPeter Wemm /* 1090c2aa98e2SPeter Wemm * e_to_sys -- 1091c2aa98e2SPeter Wemm * Guess which errno's are temporary. Gag me. 1092c2aa98e2SPeter Wemm */ 1093c2aa98e2SPeter Wemm void 1094c2aa98e2SPeter Wemm e_to_sys(num) 1095c2aa98e2SPeter Wemm int num; 1096c2aa98e2SPeter Wemm { 1097c2aa98e2SPeter Wemm /* Temporary failures override hard errors. */ 1098c2aa98e2SPeter Wemm if (eval == EX_TEMPFAIL) 1099c2aa98e2SPeter Wemm return; 1100c2aa98e2SPeter Wemm 1101c2aa98e2SPeter Wemm switch(num) { /* Hopefully temporary errors. */ 1102c2aa98e2SPeter Wemm #ifdef EAGAIN 1103c2aa98e2SPeter Wemm case EAGAIN: /* Resource temporarily unavailable */ 1104c2aa98e2SPeter Wemm #endif 1105c2aa98e2SPeter Wemm #ifdef EDQUOT 1106c2aa98e2SPeter Wemm case EDQUOT: /* Disc quota exceeded */ 1107c2aa98e2SPeter Wemm #endif 1108c2aa98e2SPeter Wemm #ifdef EBUSY 1109c2aa98e2SPeter Wemm case EBUSY: /* Device busy */ 1110c2aa98e2SPeter Wemm #endif 1111c2aa98e2SPeter Wemm #ifdef EPROCLIM 1112c2aa98e2SPeter Wemm case EPROCLIM: /* Too many processes */ 1113c2aa98e2SPeter Wemm #endif 1114c2aa98e2SPeter Wemm #ifdef EUSERS 1115c2aa98e2SPeter Wemm case EUSERS: /* Too many users */ 1116c2aa98e2SPeter Wemm #endif 1117c2aa98e2SPeter Wemm #ifdef ECONNABORTED 1118c2aa98e2SPeter Wemm case ECONNABORTED: /* Software caused connection abort */ 1119c2aa98e2SPeter Wemm #endif 1120c2aa98e2SPeter Wemm #ifdef ECONNREFUSED 1121c2aa98e2SPeter Wemm case ECONNREFUSED: /* Connection refused */ 1122c2aa98e2SPeter Wemm #endif 1123c2aa98e2SPeter Wemm #ifdef ECONNRESET 1124c2aa98e2SPeter Wemm case ECONNRESET: /* Connection reset by peer */ 1125c2aa98e2SPeter Wemm #endif 1126c2aa98e2SPeter Wemm #ifdef EDEADLK 1127c2aa98e2SPeter Wemm case EDEADLK: /* Resource deadlock avoided */ 1128c2aa98e2SPeter Wemm #endif 1129c2aa98e2SPeter Wemm #ifdef EFBIG 1130c2aa98e2SPeter Wemm case EFBIG: /* File too large */ 1131c2aa98e2SPeter Wemm #endif 1132c2aa98e2SPeter Wemm #ifdef EHOSTDOWN 1133c2aa98e2SPeter Wemm case EHOSTDOWN: /* Host is down */ 1134c2aa98e2SPeter Wemm #endif 1135c2aa98e2SPeter Wemm #ifdef EHOSTUNREACH 1136c2aa98e2SPeter Wemm case EHOSTUNREACH: /* No route to host */ 1137c2aa98e2SPeter Wemm #endif 1138c2aa98e2SPeter Wemm #ifdef EMFILE 1139c2aa98e2SPeter Wemm case EMFILE: /* Too many open files */ 1140c2aa98e2SPeter Wemm #endif 1141c2aa98e2SPeter Wemm #ifdef ENETDOWN 1142c2aa98e2SPeter Wemm case ENETDOWN: /* Network is down */ 1143c2aa98e2SPeter Wemm #endif 1144c2aa98e2SPeter Wemm #ifdef ENETRESET 1145c2aa98e2SPeter Wemm case ENETRESET: /* Network dropped connection on reset */ 1146c2aa98e2SPeter Wemm #endif 1147c2aa98e2SPeter Wemm #ifdef ENETUNREACH 1148c2aa98e2SPeter Wemm case ENETUNREACH: /* Network is unreachable */ 1149c2aa98e2SPeter Wemm #endif 1150c2aa98e2SPeter Wemm #ifdef ENFILE 1151c2aa98e2SPeter Wemm case ENFILE: /* Too many open files in system */ 1152c2aa98e2SPeter Wemm #endif 1153c2aa98e2SPeter Wemm #ifdef ENOBUFS 1154c2aa98e2SPeter Wemm case ENOBUFS: /* No buffer space available */ 1155c2aa98e2SPeter Wemm #endif 1156c2aa98e2SPeter Wemm #ifdef ENOMEM 1157c2aa98e2SPeter Wemm case ENOMEM: /* Cannot allocate memory */ 1158c2aa98e2SPeter Wemm #endif 1159c2aa98e2SPeter Wemm #ifdef ENOSPC 1160c2aa98e2SPeter Wemm case ENOSPC: /* No space left on device */ 1161c2aa98e2SPeter Wemm #endif 1162c2aa98e2SPeter Wemm #ifdef EROFS 1163c2aa98e2SPeter Wemm case EROFS: /* Read-only file system */ 1164c2aa98e2SPeter Wemm #endif 1165c2aa98e2SPeter Wemm #ifdef ESTALE 1166c2aa98e2SPeter Wemm case ESTALE: /* Stale NFS file handle */ 1167c2aa98e2SPeter Wemm #endif 1168c2aa98e2SPeter Wemm #ifdef ETIMEDOUT 1169c2aa98e2SPeter Wemm case ETIMEDOUT: /* Connection timed out */ 1170c2aa98e2SPeter Wemm #endif 1171c2aa98e2SPeter Wemm #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK 1172c2aa98e2SPeter Wemm case EWOULDBLOCK: /* Operation would block. */ 1173c2aa98e2SPeter Wemm #endif 1174c2aa98e2SPeter Wemm eval = EX_TEMPFAIL; 1175c2aa98e2SPeter Wemm break; 1176c2aa98e2SPeter Wemm default: 1177c2aa98e2SPeter Wemm eval = EX_UNAVAILABLE; 1178c2aa98e2SPeter Wemm break; 1179c2aa98e2SPeter Wemm } 1180c2aa98e2SPeter Wemm } 1181c2aa98e2SPeter Wemm 1182c2aa98e2SPeter Wemm #if !HASSTRERROR 1183c2aa98e2SPeter Wemm 1184c2aa98e2SPeter Wemm char * 1185c2aa98e2SPeter Wemm strerror(eno) 1186c2aa98e2SPeter Wemm int eno; 1187c2aa98e2SPeter Wemm { 1188c2aa98e2SPeter Wemm extern int sys_nerr; 1189c2aa98e2SPeter Wemm extern char *sys_errlist[]; 1190c2aa98e2SPeter Wemm static char ebuf[60]; 1191c2aa98e2SPeter Wemm 1192c2aa98e2SPeter Wemm if (eno >= 0 && eno < sys_nerr) 1193c2aa98e2SPeter Wemm return sys_errlist[eno]; 1194c2aa98e2SPeter Wemm (void) sprintf(ebuf, "Error %d", eno); 1195c2aa98e2SPeter Wemm return ebuf; 1196c2aa98e2SPeter Wemm } 1197c2aa98e2SPeter Wemm 1198c2aa98e2SPeter Wemm #endif /* !HASSTRERROR */ 1199c2aa98e2SPeter Wemm 1200c2aa98e2SPeter Wemm #if defined(ultrix) || defined(_CRAY) 1201c2aa98e2SPeter Wemm 1202c2aa98e2SPeter Wemm /* 1203c2aa98e2SPeter Wemm * Copyright (c) 1987, 1993 1204c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 1205c2aa98e2SPeter Wemm * 1206c2aa98e2SPeter Wemm * Redistribution and use in source and binary forms, with or without 1207c2aa98e2SPeter Wemm * modification, are permitted provided that the following conditions 1208c2aa98e2SPeter Wemm * are met: 1209c2aa98e2SPeter Wemm * 1. Redistributions of source code must retain the above copyright 1210c2aa98e2SPeter Wemm * notice, this list of conditions and the following disclaimer. 1211c2aa98e2SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 1212c2aa98e2SPeter Wemm * notice, this list of conditions and the following disclaimer in the 1213c2aa98e2SPeter Wemm * documentation and/or other materials provided with the distribution. 1214c2aa98e2SPeter Wemm * 3. All advertising materials mentioning features or use of this software 1215c2aa98e2SPeter Wemm * must display the following acknowledgement: 1216c2aa98e2SPeter Wemm * This product includes software developed by the University of 1217c2aa98e2SPeter Wemm * California, Berkeley and its contributors. 1218c2aa98e2SPeter Wemm * 4. Neither the name of the University nor the names of its contributors 1219c2aa98e2SPeter Wemm * may be used to endorse or promote products derived from this software 1220c2aa98e2SPeter Wemm * without specific prior written permission. 1221c2aa98e2SPeter Wemm * 1222c2aa98e2SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1223c2aa98e2SPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1224c2aa98e2SPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1225c2aa98e2SPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1226c2aa98e2SPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1227c2aa98e2SPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1228c2aa98e2SPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1229c2aa98e2SPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1230c2aa98e2SPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1231c2aa98e2SPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1232c2aa98e2SPeter Wemm * SUCH DAMAGE. 1233c2aa98e2SPeter Wemm */ 1234c2aa98e2SPeter Wemm 1235c2aa98e2SPeter Wemm #if defined(LIBC_SCCS) && !defined(lint) 1236c2aa98e2SPeter Wemm static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; 1237c2aa98e2SPeter Wemm #endif /* LIBC_SCCS and not lint */ 1238c2aa98e2SPeter Wemm 1239c2aa98e2SPeter Wemm #include <sys/types.h> 1240c2aa98e2SPeter Wemm #include <sys/stat.h> 1241c2aa98e2SPeter Wemm #include <fcntl.h> 1242c2aa98e2SPeter Wemm #include <errno.h> 1243c2aa98e2SPeter Wemm #include <stdio.h> 1244c2aa98e2SPeter Wemm #include <ctype.h> 1245c2aa98e2SPeter Wemm 1246c2aa98e2SPeter Wemm static int _gettemp(); 1247c2aa98e2SPeter Wemm 1248c2aa98e2SPeter Wemm mkstemp(path) 1249c2aa98e2SPeter Wemm char *path; 1250c2aa98e2SPeter Wemm { 1251c2aa98e2SPeter Wemm int fd; 1252c2aa98e2SPeter Wemm 1253c2aa98e2SPeter Wemm return (_gettemp(path, &fd) ? fd : -1); 1254c2aa98e2SPeter Wemm } 1255c2aa98e2SPeter Wemm 1256c2aa98e2SPeter Wemm /* 1257c2aa98e2SPeter Wemm char * 1258c2aa98e2SPeter Wemm mktemp(path) 1259c2aa98e2SPeter Wemm char *path; 1260c2aa98e2SPeter Wemm { 1261c2aa98e2SPeter Wemm return(_gettemp(path, (int *)NULL) ? path : (char *)NULL); 1262c2aa98e2SPeter Wemm } 1263c2aa98e2SPeter Wemm */ 1264c2aa98e2SPeter Wemm 1265c2aa98e2SPeter Wemm static 1266c2aa98e2SPeter Wemm _gettemp(path, doopen) 1267c2aa98e2SPeter Wemm char *path; 1268c2aa98e2SPeter Wemm register int *doopen; 1269c2aa98e2SPeter Wemm { 1270c2aa98e2SPeter Wemm extern int errno; 1271c2aa98e2SPeter Wemm register char *start, *trv; 1272c2aa98e2SPeter Wemm struct stat sbuf; 1273c2aa98e2SPeter Wemm u_int pid; 1274c2aa98e2SPeter Wemm 1275c2aa98e2SPeter Wemm pid = getpid(); 1276c2aa98e2SPeter Wemm for (trv = path; *trv; ++trv); /* extra X's get set to 0's */ 1277c2aa98e2SPeter Wemm while (*--trv == 'X') { 1278c2aa98e2SPeter Wemm *trv = (pid % 10) + '0'; 1279c2aa98e2SPeter Wemm pid /= 10; 1280c2aa98e2SPeter Wemm } 1281c2aa98e2SPeter Wemm 1282c2aa98e2SPeter Wemm /* 1283c2aa98e2SPeter Wemm * check the target directory; if you have six X's and it 1284c2aa98e2SPeter Wemm * doesn't exist this runs for a *very* long time. 1285c2aa98e2SPeter Wemm */ 1286c2aa98e2SPeter Wemm for (start = trv + 1;; --trv) { 1287c2aa98e2SPeter Wemm if (trv <= path) 1288c2aa98e2SPeter Wemm break; 1289c2aa98e2SPeter Wemm if (*trv == '/') { 1290c2aa98e2SPeter Wemm *trv = '\0'; 1291c2aa98e2SPeter Wemm if (stat(path, &sbuf) < 0) 1292c2aa98e2SPeter Wemm return(0); 1293c2aa98e2SPeter Wemm if (!S_ISDIR(sbuf.st_mode)) { 1294c2aa98e2SPeter Wemm errno = ENOTDIR; 1295c2aa98e2SPeter Wemm return(0); 1296c2aa98e2SPeter Wemm } 1297c2aa98e2SPeter Wemm *trv = '/'; 1298c2aa98e2SPeter Wemm break; 1299c2aa98e2SPeter Wemm } 1300c2aa98e2SPeter Wemm } 1301c2aa98e2SPeter Wemm 1302c2aa98e2SPeter Wemm for (;;) { 1303c2aa98e2SPeter Wemm if (doopen) { 1304c2aa98e2SPeter Wemm if ((*doopen = 1305c2aa98e2SPeter Wemm open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) 1306c2aa98e2SPeter Wemm return(1); 1307c2aa98e2SPeter Wemm if (errno != EEXIST) 1308c2aa98e2SPeter Wemm return(0); 1309c2aa98e2SPeter Wemm } 1310c2aa98e2SPeter Wemm else if (stat(path, &sbuf) < 0) 1311c2aa98e2SPeter Wemm return(errno == ENOENT ? 1 : 0); 1312c2aa98e2SPeter Wemm 1313c2aa98e2SPeter Wemm /* tricky little algorithm for backward compatibility */ 1314c2aa98e2SPeter Wemm for (trv = start;;) { 1315c2aa98e2SPeter Wemm if (!*trv) 1316c2aa98e2SPeter Wemm return(0); 1317c2aa98e2SPeter Wemm if (*trv == 'z') 1318c2aa98e2SPeter Wemm *trv++ = 'a'; 1319c2aa98e2SPeter Wemm else { 1320c2aa98e2SPeter Wemm if (isascii(*trv) && isdigit(*trv)) 1321c2aa98e2SPeter Wemm *trv = 'a'; 1322c2aa98e2SPeter Wemm else 1323c2aa98e2SPeter Wemm ++*trv; 1324c2aa98e2SPeter Wemm break; 1325c2aa98e2SPeter Wemm } 1326c2aa98e2SPeter Wemm } 1327c2aa98e2SPeter Wemm } 1328c2aa98e2SPeter Wemm /*NOTREACHED*/ 1329c2aa98e2SPeter Wemm } 1330c2aa98e2SPeter Wemm 1331c2aa98e2SPeter Wemm #endif /* ultrix */ 1332