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