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