1 /* 2 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 #ifndef lint 14 static char copyright[] = 15 "@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ 16 All rights reserved.\n\ 17 Copyright (c) 1990, 1993, 1994\n\ 18 The Regents of the University of California. All rights reserved.\n"; 19 #endif /* ! lint */ 20 21 #ifndef lint 22 static char id[] = "@(#)$Id: mail.local.c,v 8.143.4.37 2000/09/22 00:49:10 doug Exp $"; 23 #endif /* ! lint */ 24 25 /* $FreeBSD$ */ 26 27 /* 28 ** This is not intended to work on System V derived systems 29 ** such as Solaris or HP-UX, since they use a totally different 30 ** approach to mailboxes (essentially, they have a setgid program 31 ** rather than setuid, and they rely on the ability to "give away" 32 ** files to do their work). IT IS NOT A BUG that this doesn't 33 ** work on such architectures. 34 */ 35 36 37 /* additional mode for open() */ 38 # define EXTRA_MODE 0 39 40 # include <sys/types.h> 41 # include <sys/param.h> 42 # include <sys/stat.h> 43 # include <sys/socket.h> 44 # include <sys/file.h> 45 46 # include <netinet/in.h> 47 # include <arpa/nameser.h> 48 49 # include <fcntl.h> 50 # include <netdb.h> 51 # include <pwd.h> 52 # include <stdio.h> 53 # include <stdlib.h> 54 # include <string.h> 55 # include <syslog.h> 56 # include <time.h> 57 # include <unistd.h> 58 # ifdef EX_OK 59 # undef EX_OK /* unistd.h may have another use for this */ 60 # endif /* EX_OK */ 61 # include <sysexits.h> 62 # include <ctype.h> 63 64 # ifndef __P 65 # include "sendmail/cdefs.h" 66 # endif /* ! __P */ 67 # include "sendmail/useful.h" 68 69 extern size_t strlcpy __P((char *, const char *, size_t)); 70 extern size_t strlcat __P((char *, const char *, size_t)); 71 72 # if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) 73 # ifndef HASSTRERROR 74 # define HASSTRERROR 1 75 # endif /* ! HASSTRERROR */ 76 # endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ 77 78 # include "sendmail/errstring.h" 79 80 # ifndef LOCKTO_RM 81 # define LOCKTO_RM 300 /* timeout for stale lockfile removal */ 82 # endif /* ! LOCKTO_RM */ 83 # ifndef LOCKTO_GLOB 84 # define LOCKTO_GLOB 400 /* global timeout for lockfile creation */ 85 # endif /* ! LOCKTO_GLOB */ 86 87 # ifdef __STDC__ 88 # include <stdarg.h> 89 # define REALLOC(ptr, size) realloc(ptr, size) 90 # else /* __STDC__ */ 91 # include <varargs.h> 92 /* define a realloc() which works for NULL pointers */ 93 # define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size)) 94 # endif /* __STDC__ */ 95 96 # if (defined(sun) && defined(__svr4__)) || defined(__SVR4) 97 # define USE_LOCKF 1 98 # define USE_SETEUID 1 99 # define _PATH_MAILDIR "/var/mail" 100 # endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */ 101 102 # ifdef NCR_MP_RAS3 103 # define USE_LOCKF 1 104 # define HASSNPRINTF 1 105 # define _PATH_MAILDIR "/var/mail" 106 # endif /* NCR_MP_RAS3 */ 107 108 # if defined(_AIX) 109 # define USE_LOCKF 1 110 # define USE_SETEUID 1 111 # define USE_VSYSLOG 0 112 # endif /* defined(_AIX) */ 113 114 # if defined(__hpux) 115 # define USE_LOCKF 1 116 # define USE_SETRESUID 1 117 # define USE_VSYSLOG 0 118 # endif /* defined(__hpux) */ 119 120 # ifdef DGUX 121 # define HASSNPRINTF 1 122 # define USE_LOCKF 1 123 # define USE_VSYSLOG 0 124 # endif /* DGUX */ 125 126 # if defined(_CRAY) 127 # if !defined(MAXPATHLEN) 128 # define MAXPATHLEN PATHSIZE 129 # endif /* !defined(MAXPATHLEN) */ 130 # define USE_VSYSLOG 0 131 # define _PATH_MAILDIR "/usr/spool/mail" 132 # endif /* defined(_CRAY) */ 133 134 # if defined(ultrix) 135 # define USE_VSYSLOG 0 136 # endif /* defined(ultrix) */ 137 138 # if defined(__osf__) 139 # define USE_VSYSLOG 0 140 # endif /* defined(__osf__) */ 141 142 # if defined(NeXT) && !defined(__APPLE__) 143 # include <libc.h> 144 # define _PATH_MAILDIR "/usr/spool/mail" 145 # define S_IRUSR S_IREAD 146 # define S_IWUSR S_IWRITE 147 # endif /* defined(NeXT) && !defined(__APPLE__) */ 148 149 # if defined(IRIX64) || defined(IRIX5) || defined(IRIX6) 150 # include <paths.h> 151 # endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ 152 153 /* 154 * If you don't have flock, you could try using lockf instead. 155 */ 156 157 # ifdef USE_LOCKF 158 # define flock(a, b) lockf(a, b, 0) 159 # ifdef LOCK_EX 160 # undef LOCK_EX 161 # endif /* LOCK_EX */ 162 # define LOCK_EX F_LOCK 163 # endif /* USE_LOCKF */ 164 165 # ifndef USE_VSYSLOG 166 # define USE_VSYSLOG 1 167 # endif /* ! USE_VSYSLOG */ 168 169 # ifndef LOCK_EX 170 # include <sys/file.h> 171 # endif /* ! LOCK_EX */ 172 173 # if defined(BSD4_4) || defined(__GLIBC__) 174 # include <paths.h> 175 # define _PATH_LOCTMP "/var/tmp/local.XXXXXX" 176 # endif /* defined(BSD4_4) || defined(__GLIBC__) */ 177 178 # ifdef BSD4_4 179 # define HAS_ST_GEN 1 180 # else /* BSD4_4 */ 181 # ifndef _BSD_VA_LIST_ 182 # define _BSD_VA_LIST_ va_list 183 # endif /* ! _BSD_VA_LIST_ */ 184 # endif /* BSD4_4 */ 185 186 # if defined(BSD4_4) || defined(linux) 187 # define HASSNPRINTF 1 188 # else /* defined(BSD4_4) || defined(linux) */ 189 # ifndef ultrix 190 extern FILE *fdopen __P((int, const char *)); 191 # endif /* ! ultrix */ 192 # endif /* defined(BSD4_4) || defined(linux) */ 193 194 # if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) 195 # define CONTENTLENGTH 1 /* Needs the Content-Length header */ 196 # endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */ 197 198 # if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) 199 # define HASSNPRINTF 1 /* has snprintf starting in 2.6 */ 200 # endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */ 201 202 # ifdef HPUX11 203 # define HASSNPRINTF 1 /* has snprintf starting in 11.X */ 204 # endif /* HPUX11 */ 205 206 # if _AIX4 >= 40300 207 # define HASSNPRINTF 1 /* has snprintf starting in 4.3 */ 208 # endif /* _AIX4 >= 40300 */ 209 210 # if !HASSNPRINTF 211 extern int snprintf __P((char *, size_t, const char *, ...)); 212 # ifndef _CRAY 213 extern int vsnprintf __P((char *, size_t, const char *, ...)); 214 # endif /* ! _CRAY */ 215 # endif /* !HASSNPRINTF */ 216 217 /* 218 ** If you don't have setreuid, and you have saved uids, and you have 219 ** a seteuid() call that doesn't try to emulate using setuid(), then 220 ** you can try defining USE_SETEUID. 221 */ 222 # ifdef USE_SETEUID 223 # define setreuid(r, e) seteuid(e) 224 # endif /* USE_SETEUID */ 225 226 /* 227 ** And of course on hpux you have setresuid() 228 */ 229 # ifdef USE_SETRESUID 230 # define setreuid(r, e) setresuid(-1, e, -1) 231 # endif /* USE_SETRESUID */ 232 233 # ifndef _PATH_LOCTMP 234 # define _PATH_LOCTMP "/var/tmp/local.XXXXXX" 235 # endif /* ! _PATH_LOCTMP */ 236 # ifndef _PATH_MAILDIR 237 # define _PATH_MAILDIR "/var/spool/mail" 238 # endif /* ! _PATH_MAILDIR */ 239 240 # ifndef S_ISREG 241 # define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG) 242 # endif /* ! S_ISREG */ 243 244 # ifdef MAILLOCK 245 # include <maillock.h> 246 # endif /* MAILLOCK */ 247 248 # define U_UID pw->pw_uid 249 # define U_GID pw->pw_gid 250 251 #ifndef INADDRSZ 252 # define INADDRSZ 4 /* size of an IPv4 address in bytes */ 253 #endif /* ! INADDRSZ */ 254 255 #ifndef MAILER_DAEMON 256 # define MAILER_DAEMON "MAILER-DAEMON" 257 #endif /* ! MAILER_DAEMON */ 258 259 #ifdef CONTENTLENGTH 260 char ContentHdr[40] = "Content-Length: "; 261 off_t HeaderLength; 262 off_t BodyLength; 263 #endif /* CONTENTLENGTH */ 264 265 bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */ 266 int ExitVal = EX_OK; /* sysexits.h error value. */ 267 bool LMTPMode = FALSE; 268 bool bouncequota = FALSE; /* permanent error when over quota */ 269 bool nobiff = FALSE; 270 bool nofsync = FALSE; 271 272 void deliver __P((int, char *, bool)); 273 int e_to_sys __P((int)); 274 void notifybiff __P((char *)); 275 int store __P((char *, int)); 276 void usage __P((void)); 277 void vwarn __P((const char *, _BSD_VA_LIST_)); 278 int lockmbox __P((char *)); 279 void unlockmbox __P((void)); 280 void mailerr __P((const char *, const char *, ...)); 281 282 283 int 284 main(argc, argv) 285 int argc; 286 char *argv[]; 287 { 288 struct passwd *pw; 289 int ch, fd; 290 uid_t uid; 291 char *from; 292 extern char *optarg; 293 extern int optind; 294 extern void dolmtp __P((bool)); 295 296 297 /* make sure we have some open file descriptors */ 298 for (fd = 10; fd < 30; fd++) 299 (void) close(fd); 300 301 /* use a reasonable umask */ 302 (void) umask(0077); 303 304 # ifdef LOG_MAIL 305 openlog("mail.local", 0, LOG_MAIL); 306 # else /* LOG_MAIL */ 307 openlog("mail.local", 0); 308 # endif /* LOG_MAIL */ 309 310 from = NULL; 311 while ((ch = getopt(argc, argv, "7Bbdf:r:ls")) != -1) 312 { 313 switch(ch) 314 { 315 case '7': /* Do not advertise 8BITMIME */ 316 EightBitMime = FALSE; 317 break; 318 319 case 'B': 320 nobiff = TRUE; 321 break; 322 323 case 'b': /* bounce mail when over quota. */ 324 bouncequota = TRUE; 325 break; 326 327 case 'd': /* Backward compatible. */ 328 break; 329 330 case 'f': 331 case 'r': /* Backward compatible. */ 332 if (from != NULL) 333 { 334 mailerr(NULL, "multiple -f options"); 335 usage(); 336 } 337 from = optarg; 338 break; 339 340 case 'l': 341 LMTPMode = TRUE; 342 break; 343 344 case 's': 345 nofsync++; 346 break; 347 348 case '?': 349 default: 350 usage(); 351 } 352 } 353 argc -= optind; 354 argv += optind; 355 356 /* initialize biff structures */ 357 if (!nobiff) 358 notifybiff(NULL); 359 360 if (LMTPMode) 361 dolmtp(bouncequota); 362 363 if (*argv == '\0') 364 usage(); 365 366 /* 367 ** If from not specified, use the name from getlogin() if the 368 ** uid matches, otherwise, use the name from the password file 369 ** corresponding to the uid. 370 */ 371 uid = getuid(); 372 373 if (from == NULL && ((from = getlogin()) == NULL || 374 (pw = getpwnam(from)) == NULL || 375 pw->pw_uid != uid)) 376 from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???"; 377 378 /* 379 ** There is no way to distinguish the error status of one delivery 380 ** from the rest of the deliveries. So, if we failed hard on one 381 ** or more deliveries, but had no failures on any of the others, we 382 ** return a hard failure. If we failed temporarily on one or more 383 ** deliveries, we return a temporary failure regardless of the other 384 ** failures. This results in the delivery being reattempted later 385 ** at the expense of repeated failures and multiple deliveries. 386 */ 387 for (fd = store(from, 0); *argv; ++argv) 388 deliver(fd, *argv, bouncequota); 389 exit(ExitVal); 390 /* NOTREACHED */ 391 return ExitVal; 392 } 393 394 char * 395 parseaddr(s, rcpt) 396 char *s; 397 bool rcpt; 398 { 399 char *p; 400 int l; 401 402 if (*s++ != '<') 403 return NULL; 404 405 p = s; 406 407 /* at-domain-list */ 408 while (*p == '@') 409 { 410 p++; 411 while (*p != ',' && *p != ':' && *p != '\0') 412 p++; 413 if (*p == '\0') 414 return NULL; 415 416 /* Skip over , or : */ 417 p++; 418 } 419 420 s = p; 421 422 /* local-part */ 423 while (*p != '\0' && *p != '@' && *p != '>') 424 { 425 if (*p == '\\') 426 { 427 if (*++p == '\0') 428 return NULL; 429 } 430 else if (*p == '\"') 431 { 432 p++; 433 while (*p != '\0' && *p != '\"') 434 { 435 if (*p == '\\') 436 { 437 if (*++p == '\0') 438 return NULL; 439 } 440 p++; 441 } 442 if (*p == '\0' || *(p + 1) == '\0') 443 return NULL; 444 } 445 /* +detail ? */ 446 if (*p == '+' && rcpt) 447 *p = '\0'; 448 p++; 449 } 450 451 /* @domain */ 452 if (*p == '@') 453 { 454 if (rcpt) 455 *p++ = '\0'; 456 while (*p != '\0' && *p != '>') 457 p++; 458 } 459 460 if (*p != '>') 461 return NULL; 462 else 463 *p = '\0'; 464 p++; 465 466 if (*p != '\0' && *p != ' ') 467 return NULL; 468 469 if (*s == '\0') 470 s = MAILER_DAEMON; 471 472 l = strlen(s) + 1; 473 p = malloc(l); 474 if (p == NULL) 475 { 476 printf("421 4.3.0 memory exhausted\r\n"); 477 exit(EX_TEMPFAIL); 478 } 479 480 (void) strlcpy(p, s, l); 481 return p; 482 } 483 484 char * 485 process_recipient(addr) 486 char *addr; 487 { 488 if (getpwnam(addr) == NULL) 489 return "550 5.1.1 user unknown"; 490 return NULL; 491 } 492 493 #define RCPT_GROW 30 494 495 void 496 dolmtp(bouncequota) 497 bool bouncequota; 498 { 499 char *return_path = NULL; 500 char **rcpt_addr = NULL; 501 int rcpt_num = 0; 502 int rcpt_alloc = 0; 503 bool gotlhlo = FALSE; 504 char *err; 505 int msgfd; 506 char *p; 507 int i; 508 char myhostname[1024]; 509 char buf[4096]; 510 511 (void) gethostname(myhostname, sizeof myhostname - 1); 512 513 printf("220 %s LMTP ready\r\n", myhostname); 514 for (;;) 515 { 516 (void) fflush(stdout); 517 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) 518 exit(EX_OK); 519 p = buf + strlen(buf) - 1; 520 if (p >= buf && *p == '\n') 521 *p-- = '\0'; 522 if (p >= buf && *p == '\r') 523 *p-- = '\0'; 524 525 switch (buf[0]) 526 { 527 case 'd': 528 case 'D': 529 if (strcasecmp(buf, "data") == 0) 530 { 531 if (rcpt_num == 0) 532 { 533 printf("503 5.5.1 No recipients\r\n"); 534 continue; 535 } 536 msgfd = store(return_path, rcpt_num); 537 if (msgfd == -1) 538 continue; 539 540 for (i = 0; i < rcpt_num; i++) 541 { 542 p = strchr(rcpt_addr[i], '+'); 543 if (p != NULL) 544 *p++ = '\0'; 545 deliver(msgfd, rcpt_addr[i], 546 bouncequota); 547 } 548 (void) close(msgfd); 549 goto rset; 550 } 551 goto syntaxerr; 552 /* NOTREACHED */ 553 break; 554 555 case 'l': 556 case 'L': 557 if (strncasecmp(buf, "lhlo ", 5) == 0) 558 { 559 /* check for duplicate per RFC 1651 4.2 */ 560 if (gotlhlo) 561 { 562 printf("503 %s Duplicate LHLO\r\n", 563 myhostname); 564 continue; 565 } 566 gotlhlo = TRUE; 567 printf("250-%s\r\n", myhostname); 568 if (EightBitMime) 569 printf("250-8BITMIME\r\n"); 570 printf("250-ENHANCEDSTATUSCODES\r\n"); 571 printf("250 PIPELINING\r\n"); 572 continue; 573 } 574 goto syntaxerr; 575 /* NOTREACHED */ 576 break; 577 578 case 'm': 579 case 'M': 580 if (strncasecmp(buf, "mail ", 5) == 0) 581 { 582 if (return_path != NULL) 583 { 584 printf("503 5.5.1 Nested MAIL command\r\n"); 585 continue; 586 } 587 if (strncasecmp(buf+5, "from:", 5) != 0 || 588 ((return_path = parseaddr(buf + 10, 589 FALSE)) == NULL)) 590 { 591 printf("501 5.5.4 Syntax error in parameters\r\n"); 592 continue; 593 } 594 printf("250 2.5.0 ok\r\n"); 595 continue; 596 } 597 goto syntaxerr; 598 /* NOTREACHED */ 599 break; 600 601 case 'n': 602 case 'N': 603 if (strcasecmp(buf, "noop") == 0) 604 { 605 printf("250 2.0.0 ok\r\n"); 606 continue; 607 } 608 goto syntaxerr; 609 /* NOTREACHED */ 610 break; 611 612 case 'q': 613 case 'Q': 614 if (strcasecmp(buf, "quit") == 0) 615 { 616 printf("221 2.0.0 bye\r\n"); 617 exit(EX_OK); 618 } 619 goto syntaxerr; 620 /* NOTREACHED */ 621 break; 622 623 case 'r': 624 case 'R': 625 if (strncasecmp(buf, "rcpt ", 5) == 0) 626 { 627 if (return_path == NULL) 628 { 629 printf("503 5.5.1 Need MAIL command\r\n"); 630 continue; 631 } 632 if (rcpt_num >= rcpt_alloc) 633 { 634 rcpt_alloc += RCPT_GROW; 635 rcpt_addr = (char **) 636 REALLOC((char *) rcpt_addr, 637 rcpt_alloc * 638 sizeof(char **)); 639 if (rcpt_addr == NULL) 640 { 641 printf("421 4.3.0 memory exhausted\r\n"); 642 exit(EX_TEMPFAIL); 643 } 644 } 645 if (strncasecmp(buf + 5, "to:", 3) != 0 || 646 ((rcpt_addr[rcpt_num] = parseaddr(buf + 8, 647 TRUE)) == NULL)) 648 { 649 printf("501 5.5.4 Syntax error in parameters\r\n"); 650 continue; 651 } 652 if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) 653 { 654 printf("%s\r\n", err); 655 continue; 656 } 657 rcpt_num++; 658 printf("250 2.1.5 ok\r\n"); 659 continue; 660 } 661 else if (strcasecmp(buf, "rset") == 0) 662 { 663 printf("250 2.0.0 ok\r\n"); 664 665 rset: 666 while (rcpt_num) 667 free(rcpt_addr[--rcpt_num]); 668 if (return_path != NULL) 669 free(return_path); 670 return_path = NULL; 671 continue; 672 } 673 goto syntaxerr; 674 /* NOTREACHED */ 675 break; 676 677 case 'v': 678 case 'V': 679 if (strncasecmp(buf, "vrfy ", 5) == 0) 680 { 681 printf("252 2.3.3 try RCPT to attempt delivery\r\n"); 682 continue; 683 } 684 goto syntaxerr; 685 /* NOTREACHED */ 686 break; 687 688 default: 689 syntaxerr: 690 printf("500 5.5.2 Syntax error\r\n"); 691 continue; 692 /* NOTREACHED */ 693 break; 694 } 695 } 696 } 697 698 int 699 store(from, lmtprcpts) 700 char *from; 701 int lmtprcpts; 702 { 703 FILE *fp = NULL; 704 time_t tval; 705 bool eline; 706 bool fullline = TRUE; /* current line is terminated */ 707 bool prevfl; /* previous line was terminated */ 708 char line[2048]; 709 int fd; 710 char tmpbuf[sizeof _PATH_LOCTMP + 1]; 711 712 (void) umask(0077); 713 (void) strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf); 714 if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL) 715 { 716 if (lmtprcpts) 717 { 718 printf("451 4.3.0 unable to open temporary file\r\n"); 719 return -1; 720 } 721 else 722 { 723 mailerr("451 4.3.0", "unable to open temporary file"); 724 exit(ExitVal); 725 } 726 } 727 (void) unlink(tmpbuf); 728 729 if (LMTPMode) 730 { 731 printf("354 go ahead\r\n"); 732 (void) fflush(stdout); 733 } 734 735 (void) time(&tval); 736 (void) fprintf(fp, "From %s %s", from, ctime(&tval)); 737 738 #ifdef CONTENTLENGTH 739 HeaderLength = 0; 740 BodyLength = -1; 741 #endif /* CONTENTLENGTH */ 742 743 line[0] = '\0'; 744 eline = TRUE; 745 while (fgets(line, sizeof(line), stdin) != (char *)NULL) 746 { 747 size_t line_len = 0; 748 int peek; 749 750 prevfl = fullline; /* preserve state of previous line */ 751 while (line[line_len] != '\n' && line_len < sizeof(line) - 2) 752 line_len++; 753 line_len++; 754 755 /* Check for dot-stuffing */ 756 if (prevfl && lmtprcpts && line[0] == '.') 757 { 758 if (line[1] == '\n' || 759 (line[1] == '\r' && line[2] == '\n')) 760 goto lmtpdot; 761 memcpy(line, line + 1, line_len); 762 line_len--; 763 } 764 765 /* Check to see if we have the full line from fgets() */ 766 fullline = FALSE; 767 if (line_len > 0) 768 { 769 if (line[line_len - 1] == '\n') 770 { 771 if (line_len >= 2 && 772 line[line_len - 2] == '\r') 773 { 774 line[line_len - 2] = '\n'; 775 line[line_len - 1] = '\0'; 776 line_len--; 777 } 778 fullline = TRUE; 779 } 780 else if (line[line_len - 1] == '\r') 781 { 782 /* Did we just miss the CRLF? */ 783 peek = fgetc(stdin); 784 if (peek == '\n') 785 { 786 line[line_len - 1] = '\n'; 787 fullline = TRUE; 788 } 789 else 790 (void) ungetc(peek, stdin); 791 } 792 } 793 else 794 fullline = TRUE; 795 796 #ifdef CONTENTLENGTH 797 if (prevfl && line[0] == '\n' && HeaderLength == 0) 798 { 799 eline = FALSE; 800 HeaderLength = ftell(fp); 801 if (HeaderLength <= 0) 802 { 803 /* 804 ** shouldn't happen, unless ftell() is 805 ** badly broken 806 */ 807 808 HeaderLength = -1; 809 } 810 } 811 #else /* CONTENTLENGTH */ 812 if (prevfl && line[0] == '\n') 813 eline = TRUE; 814 #endif /* CONTENTLENGTH */ 815 else 816 { 817 if (eline && line[0] == 'F' && 818 !memcmp(line, "From ", 5)) 819 (void) putc('>', fp); 820 eline = FALSE; 821 #ifdef CONTENTLENGTH 822 /* discard existing "Content-Length:" headers */ 823 if (prevfl && HeaderLength == 0 && 824 (line[0] == 'C' || line[0] == 'c') && 825 strncasecmp(line, ContentHdr, 15) == 0) 826 { 827 /* 828 ** be paranoid: clear the line 829 ** so no "wrong matches" may occur later 830 */ 831 line[0] = '\0'; 832 continue; 833 } 834 #endif /* CONTENTLENGTH */ 835 836 } 837 (void) fwrite(line, sizeof(char), line_len, fp); 838 if (ferror(fp)) 839 { 840 if (lmtprcpts) 841 { 842 while (lmtprcpts--) 843 printf("451 4.3.0 temporary file write error\r\n"); 844 (void) fclose(fp); 845 return -1; 846 } 847 else 848 { 849 mailerr("451 4.3.0", 850 "temporary file write error"); 851 (void) fclose(fp); 852 exit(ExitVal); 853 } 854 } 855 } 856 857 if (lmtprcpts) 858 { 859 /* Got a premature EOF -- toss message and exit */ 860 exit(EX_OK); 861 } 862 863 /* If message not newline terminated, need an extra. */ 864 if (strchr(line, '\n') == NULL) 865 (void) putc('\n', fp); 866 867 lmtpdot: 868 869 #ifdef CONTENTLENGTH 870 BodyLength = ftell(fp); 871 if (HeaderLength == 0 && BodyLength > 0) /* empty body */ 872 { 873 HeaderLength = BodyLength; 874 BodyLength = 0; 875 } 876 else 877 BodyLength = BodyLength - HeaderLength - 1 ; 878 879 if (HeaderLength > 0 && BodyLength >= 0) 880 { 881 extern char *quad_to_string(); 882 883 if (sizeof BodyLength > sizeof(long)) 884 snprintf(line, sizeof line, "%s\n", 885 quad_to_string(BodyLength)); 886 else 887 snprintf(line, sizeof line, "%ld\n", 888 (long) BodyLength); 889 strlcpy(&ContentHdr[16], line, sizeof(ContentHdr) - 16); 890 } 891 else 892 BodyLength = -1; /* Something is wrong here */ 893 #endif /* CONTENTLENGTH */ 894 895 /* Output a newline; note, empty messages are allowed. */ 896 (void) putc('\n', fp); 897 898 if (fflush(fp) == EOF || ferror(fp) != 0) 899 { 900 if (lmtprcpts) 901 { 902 while (lmtprcpts--) 903 printf("451 4.3.0 temporary file write error\r\n"); 904 (void) fclose(fp); 905 return -1; 906 } 907 else 908 { 909 mailerr("451 4.3.0", "temporary file write error"); 910 (void) fclose(fp); 911 exit(ExitVal); 912 } 913 } 914 return fd; 915 } 916 917 void 918 deliver(fd, name, bouncequota) 919 int fd; 920 char *name; 921 bool bouncequota; 922 { 923 struct stat fsb; 924 struct stat sb; 925 struct passwd *pw; 926 char path[MAXPATHLEN]; 927 int mbfd, nr = 0, nw, off; 928 char *p; 929 off_t curoff; 930 #ifdef CONTENTLENGTH 931 off_t headerbytes; 932 int readamount; 933 #endif /* CONTENTLENGTH */ 934 char biffmsg[100], buf[8*1024]; 935 extern char *quad_to_string(); 936 937 938 /* 939 ** Disallow delivery to unknown names -- special mailboxes can be 940 ** handled in the sendmail aliases file. 941 */ 942 if ((pw = getpwnam(name)) == NULL) 943 { 944 if (ExitVal != EX_TEMPFAIL) 945 ExitVal = EX_UNAVAILABLE; 946 if (LMTPMode) 947 { 948 if (ExitVal == EX_TEMPFAIL) 949 printf("451 4.3.0 cannot lookup name: %s\r\n", 950 name); 951 else 952 printf("550 5.1.1 unknown name: %s\r\n", name); 953 } 954 else 955 { 956 char *errcode = NULL; 957 958 if (ExitVal == EX_TEMPFAIL) 959 errcode = "451 4.3.0"; 960 else 961 errcode = "550 5.1.1"; 962 mailerr(errcode, "unknown name: %s", name); 963 } 964 return; 965 } 966 endpwent(); 967 968 /* 969 ** Keep name reasonably short to avoid buffer overruns. 970 ** This isn't necessary on BSD because of the proper 971 ** definition of snprintf(), but it can cause problems 972 ** on other systems. 973 ** Also, clear out any bogus characters. 974 */ 975 976 if (strlen(name) > 40) 977 name[40] = '\0'; 978 for (p = name; *p != '\0'; p++) 979 { 980 if (!isascii(*p)) 981 *p &= 0x7f; 982 else if (!isprint(*p)) 983 *p = '.'; 984 } 985 986 987 (void) snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name); 988 989 990 /* 991 ** If the mailbox is linked or a symlink, fail. There's an obvious 992 ** race here, that the file was replaced with a symbolic link after 993 ** the lstat returned, but before the open. We attempt to detect 994 ** this by comparing the original stat information and information 995 ** returned by an fstat of the file descriptor returned by the open. 996 ** 997 ** NB: this is a symptom of a larger problem, that the mail spooling 998 ** directory is writeable by the wrong users. If that directory is 999 ** writeable, system security is compromised for other reasons, and 1000 ** it cannot be fixed here. 1001 ** 1002 ** If we created the mailbox, set the owner/group. If that fails, 1003 ** just return. Another process may have already opened it, so we 1004 ** can't unlink it. Historically, binmail set the owner/group at 1005 ** each mail delivery. We no longer do this, assuming that if the 1006 ** ownership or permissions were changed there was a reason. 1007 ** 1008 ** XXX 1009 ** open(2) should support flock'ing the file. 1010 */ 1011 1012 tryagain: 1013 #ifdef MAILLOCK 1014 p = name; 1015 #else /* MAILLOCK */ 1016 p = path; 1017 #endif /* MAILLOCK */ 1018 if ((off = lockmbox(p)) != 0) 1019 { 1020 if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL) 1021 { 1022 ExitVal = EX_TEMPFAIL; 1023 mailerr("451 4.3.0", 1024 "lockmailbox %s failed; error code %d %s", 1025 p, off, errno > 0 ? errstring(errno) : ""); 1026 } 1027 else 1028 { 1029 mailerr("551 5.3.0", 1030 "lockmailbox %s failed; error code %d %s", 1031 p, off, errno > 0 ? errstring(errno) : ""); 1032 } 1033 return; 1034 } 1035 1036 if (lstat(path, &sb) < 0) 1037 { 1038 int save_errno; 1039 int mode = S_IRUSR|S_IWUSR; 1040 gid_t gid = U_GID; 1041 1042 #ifdef MAILGID 1043 (void) umask(0007); 1044 gid = MAILGID; 1045 mode |= S_IRGRP|S_IWGRP; 1046 #endif /* MAILGID */ 1047 1048 mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|EXTRA_MODE, 1049 mode); 1050 save_errno = errno; 1051 1052 if (lstat(path, &sb) < 0) 1053 { 1054 ExitVal = EX_CANTCREAT; 1055 mailerr("550 5.2.0", 1056 "%s: lstat: file changed after open", path); 1057 goto err1; 1058 } 1059 if (mbfd == -1) 1060 { 1061 if (save_errno == EEXIST) 1062 goto tryagain; 1063 1064 /* open failed, don't try again */ 1065 mailerr("450 4.2.0", "%s: %s", path, 1066 errstring(save_errno)); 1067 goto err0; 1068 } 1069 else if (fchown(mbfd, U_UID, gid) < 0) 1070 { 1071 mailerr("451 4.3.0", "chown %u.%u: %s", 1072 U_UID, gid, name); 1073 goto err1; 1074 } 1075 else 1076 { 1077 /* 1078 ** open() was successful, now close it so can 1079 ** be opened as the right owner again. 1080 ** Paranoia: reset mbdf since the file descriptor 1081 ** is no longer valid; better safe than sorry. 1082 */ 1083 1084 sb.st_uid = U_UID; 1085 (void) close(mbfd); 1086 mbfd = -1; 1087 } 1088 } 1089 else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode)) 1090 { 1091 mailerr("550 5.2.0", "%s: irregular file", path); 1092 goto err0; 1093 } 1094 else if (sb.st_uid != U_UID) 1095 { 1096 ExitVal = EX_CANTCREAT; 1097 mailerr("550 5.2.0", "%s: wrong ownership (%d)", 1098 path, sb.st_uid); 1099 goto err0; 1100 } 1101 1102 /* change UID for quota checks */ 1103 if (setreuid(0, U_UID) < 0) 1104 { 1105 mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)", 1106 U_UID, errstring(errno), getuid(), geteuid()); 1107 goto err1; 1108 } 1109 #ifdef DEBUG 1110 fprintf(stderr, "new euid = %d\n", geteuid()); 1111 #endif /* DEBUG */ 1112 mbfd = open(path, O_APPEND|O_WRONLY|EXTRA_MODE, 0); 1113 if (mbfd < 0) 1114 { 1115 mailerr("450 4.2.0", "%s: %s", path, errstring(errno)); 1116 goto err0; 1117 } 1118 else if (fstat(mbfd, &fsb) < 0 || 1119 fsb.st_nlink != 1 || 1120 sb.st_nlink != 1 || 1121 !S_ISREG(fsb.st_mode) || 1122 sb.st_dev != fsb.st_dev || 1123 sb.st_ino != fsb.st_ino || 1124 # if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ 1125 sb.st_gen != fsb.st_gen || 1126 # endif /* HAS_ST_GEN && 0 */ 1127 sb.st_uid != fsb.st_uid) 1128 { 1129 ExitVal = EX_TEMPFAIL; 1130 mailerr("550 5.2.0", "%s: fstat: file changed after open", 1131 path); 1132 goto err1; 1133 } 1134 1135 1136 /* Wait until we can get a lock on the file. */ 1137 if (flock(mbfd, LOCK_EX) < 0) 1138 { 1139 mailerr("450 4.2.0", "%s: %s", path, errstring(errno)); 1140 goto err1; 1141 } 1142 1143 if (!nobiff) 1144 { 1145 /* Get the starting offset of the new message for biff. */ 1146 curoff = lseek(mbfd, (off_t)0, SEEK_END); 1147 if (sizeof curoff > sizeof(long)) 1148 (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n", 1149 name, quad_to_string(curoff)); 1150 else 1151 (void) snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n", 1152 name, (long) curoff); 1153 } 1154 1155 /* Copy the message into the file. */ 1156 if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) 1157 { 1158 mailerr("450 4.2.0", "temporary file: %s", 1159 errstring(errno)); 1160 goto err1; 1161 } 1162 #ifdef DEBUG 1163 fprintf(stderr, "before writing: euid = %d\n", geteuid()); 1164 #endif /* DEBUG */ 1165 #ifdef CONTENTLENGTH 1166 headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ; 1167 for (;;) 1168 { 1169 if (headerbytes == 0) 1170 { 1171 snprintf(buf, sizeof buf, "%s", ContentHdr); 1172 nr = strlen(buf); 1173 headerbytes = -1; 1174 readamount = 0; 1175 } 1176 else if (headerbytes > sizeof(buf) || headerbytes < 0) 1177 readamount = sizeof(buf); 1178 else 1179 readamount = headerbytes; 1180 if (readamount != 0) 1181 nr = read(fd, buf, readamount); 1182 if (nr <= 0) 1183 break; 1184 if (headerbytes > 0) 1185 headerbytes -= nr ; 1186 1187 #else /* CONTENTLENGTH */ 1188 while ((nr = read(fd, buf, sizeof(buf))) > 0) 1189 { 1190 #endif /* CONTENTLENGTH */ 1191 for (off = 0; off < nr; off += nw) 1192 { 1193 if ((nw = write(mbfd, buf + off, nr - off)) < 0) 1194 { 1195 #ifdef EDQUOT 1196 if (errno == EDQUOT && bouncequota) 1197 mailerr("552 5.2.2", "%s: %s", 1198 path, errstring(errno)); 1199 else 1200 #endif /* EDQUOT */ 1201 mailerr("450 4.2.0", "%s: %s", 1202 path, errstring(errno)); 1203 goto err3; 1204 } 1205 } 1206 } 1207 if (nr < 0) 1208 { 1209 mailerr("450 4.2.0", "temporary file: %s", 1210 errstring(errno)); 1211 goto err3; 1212 } 1213 1214 /* Flush to disk, don't wait for update. */ 1215 if (!nofsync && fsync(mbfd) < 0) 1216 { 1217 mailerr("450 4.2.0", "%s: %s", path, errstring(errno)); 1218 err3: 1219 if (setreuid(0, 0) < 0) 1220 { 1221 #if 0 1222 /* already printed an error above for this recipient */ 1223 (void) e_to_sys(errno); 1224 mailerr("450 4.2.0", "setreuid(0, 0): %s", 1225 errstring(errno)); 1226 #endif /* 0 */ 1227 } 1228 #ifdef DEBUG 1229 fprintf(stderr, "reset euid = %d\n", geteuid()); 1230 #endif /* DEBUG */ 1231 (void) ftruncate(mbfd, curoff); 1232 err1: if (mbfd >= 0) 1233 (void) close(mbfd); 1234 err0: unlockmbox(); 1235 return; 1236 } 1237 1238 /* Close and check -- NFS doesn't write until the close. */ 1239 if (close(mbfd)) 1240 { 1241 #ifdef EDQUOT 1242 if (errno == EDQUOT && bouncequota) 1243 mailerr("552 5.2.2", "%s: %s", path, errstring(errno)); 1244 else 1245 #endif /* EDQUOT */ 1246 mailerr("450 4.2.0", "%s: %s", path, errstring(errno)); 1247 (void) truncate(path, curoff); 1248 } 1249 else if (!nobiff) 1250 notifybiff(biffmsg); 1251 1252 if (setreuid(0, 0) < 0) 1253 { 1254 mailerr("450 4.2.0", "setreuid(0, 0): %s", 1255 errstring(errno)); 1256 goto err0; 1257 } 1258 #ifdef DEBUG 1259 fprintf(stderr, "reset euid = %d\n", geteuid()); 1260 #endif /* DEBUG */ 1261 unlockmbox(); 1262 if (LMTPMode) 1263 printf("250 2.1.5 %s OK\r\n", name); 1264 } 1265 1266 /* 1267 ** user.lock files are necessary for compatibility with other 1268 ** systems, e.g., when the mail spool file is NFS exported. 1269 ** Alas, mailbox locking is more than just a local matter. 1270 ** EPA 11/94. 1271 */ 1272 1273 bool Locked = FALSE; 1274 1275 #ifdef MAILLOCK 1276 int 1277 lockmbox(name) 1278 char *name; 1279 { 1280 int r = 0; 1281 1282 if (Locked) 1283 return 0; 1284 if ((r = maillock(name, 15)) == L_SUCCESS) 1285 { 1286 Locked = TRUE; 1287 return 0; 1288 } 1289 switch (r) 1290 { 1291 case L_TMPLOCK: /* Can't create tmp file */ 1292 case L_TMPWRITE: /* Can't write pid into lockfile */ 1293 case L_MAXTRYS: /* Failed after retrycnt attempts */ 1294 errno = 0; 1295 r = EX_TEMPFAIL; 1296 break; 1297 case L_ERROR: /* Check errno for reason */ 1298 r = errno; 1299 break; 1300 default: /* other permanent errors */ 1301 errno = 0; 1302 r = EX_UNAVAILABLE; 1303 break; 1304 } 1305 return r; 1306 } 1307 1308 void 1309 unlockmbox() 1310 { 1311 if (Locked) 1312 mailunlock(); 1313 Locked = FALSE; 1314 } 1315 #else /* MAILLOCK */ 1316 1317 char LockName[MAXPATHLEN]; 1318 1319 int 1320 lockmbox(path) 1321 char *path; 1322 { 1323 int statfailed = 0; 1324 time_t start; 1325 1326 if (Locked) 1327 return 0; 1328 if (strlen(path) + 6 > sizeof LockName) 1329 return EX_SOFTWARE; 1330 (void) snprintf(LockName, sizeof LockName, "%s.lock", path); 1331 (void) time(&start); 1332 for (; ; sleep(5)) 1333 { 1334 int fd; 1335 struct stat st; 1336 time_t now; 1337 1338 /* global timeout */ 1339 (void) time(&now); 1340 if (now > start + LOCKTO_GLOB) 1341 { 1342 errno = 0; 1343 return EX_TEMPFAIL; 1344 } 1345 fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, 0); 1346 if (fd >= 0) 1347 { 1348 /* defeat lock checking programs which test pid */ 1349 (void) write(fd, "0", 2); 1350 Locked = TRUE; 1351 (void) close(fd); 1352 return 0; 1353 } 1354 if (stat(LockName, &st) < 0) 1355 { 1356 if (statfailed++ > 5) 1357 { 1358 errno = 0; 1359 return EX_TEMPFAIL; 1360 } 1361 continue; 1362 } 1363 statfailed = 0; 1364 (void) time(&now); 1365 if (now < st.st_ctime + LOCKTO_RM) 1366 continue; 1367 1368 /* try to remove stale lockfile */ 1369 if (unlink(LockName) < 0) 1370 return errno; 1371 } 1372 } 1373 1374 void 1375 unlockmbox() 1376 { 1377 if (!Locked) 1378 return; 1379 (void) unlink(LockName); 1380 Locked = FALSE; 1381 } 1382 #endif /* MAILLOCK */ 1383 1384 void 1385 notifybiff(msg) 1386 char *msg; 1387 { 1388 static bool initialized = FALSE; 1389 static int f = -1; 1390 struct hostent *hp; 1391 struct servent *sp; 1392 int len; 1393 static struct sockaddr_in addr; 1394 1395 if (!initialized) 1396 { 1397 initialized = TRUE; 1398 1399 /* Be silent if biff service not available. */ 1400 if ((sp = getservbyname("biff", "udp")) == NULL || 1401 (hp = gethostbyname("localhost")) == NULL || 1402 hp->h_length != INADDRSZ) 1403 return; 1404 1405 addr.sin_family = hp->h_addrtype; 1406 memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ); 1407 addr.sin_port = sp->s_port; 1408 } 1409 1410 /* No message, just return */ 1411 if (msg == NULL) 1412 return; 1413 1414 /* Couldn't initialize addr struct */ 1415 if (addr.sin_family == AF_UNSPEC) 1416 return; 1417 1418 if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 1419 return; 1420 len = strlen(msg) + 1; 1421 (void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr)); 1422 } 1423 1424 void 1425 usage() 1426 { 1427 ExitVal = EX_USAGE; 1428 mailerr(NULL, "usage: mail.local [-7] [-B] [-b] [-l] [-f from] [-s] user ..."); 1429 exit(ExitVal); 1430 } 1431 1432 void 1433 #ifdef __STDC__ 1434 mailerr(const char *hdr, const char *fmt, ...) 1435 #else /* __STDC__ */ 1436 mailerr(hdr, fmt, va_alist) 1437 const char *hdr; 1438 const char *fmt; 1439 va_dcl 1440 #endif /* __STDC__ */ 1441 { 1442 va_list ap; 1443 1444 #ifdef __STDC__ 1445 va_start(ap, fmt); 1446 #else /* __STDC__ */ 1447 va_start(ap); 1448 #endif /* __STDC__ */ 1449 if (LMTPMode) 1450 { 1451 if (hdr != NULL) 1452 printf("%s ", hdr); 1453 (void) vprintf(fmt, ap); 1454 (void) printf("\r\n"); 1455 } 1456 else 1457 { 1458 (void) e_to_sys(errno); 1459 vwarn(fmt, ap); 1460 } 1461 } 1462 1463 void 1464 vwarn(fmt, ap) 1465 const char *fmt; 1466 _BSD_VA_LIST_ ap; 1467 { 1468 /* 1469 ** Log the message to stderr. 1470 ** 1471 ** Don't use LOG_PERROR as an openlog() flag to do this, 1472 ** it's not portable enough. 1473 */ 1474 1475 if (ExitVal != EX_USAGE) 1476 (void) fprintf(stderr, "mail.local: "); 1477 (void) vfprintf(stderr, fmt, ap); 1478 (void) fprintf(stderr, "\n"); 1479 1480 #if USE_VSYSLOG 1481 /* Log the message to syslog. */ 1482 vsyslog(LOG_ERR, fmt, ap); 1483 #else /* USE_VSYSLOG */ 1484 { 1485 char fmtbuf[10240]; 1486 1487 (void) vsnprintf(fmtbuf, sizeof fmtbuf, fmt, ap); 1488 syslog(LOG_ERR, "%s", fmtbuf); 1489 } 1490 #endif /* USE_VSYSLOG */ 1491 } 1492 1493 /* 1494 * e_to_sys -- 1495 * Guess which errno's are temporary. Gag me. 1496 */ 1497 int 1498 e_to_sys(num) 1499 int num; 1500 { 1501 /* Temporary failures override hard errors. */ 1502 if (ExitVal == EX_TEMPFAIL) 1503 return ExitVal; 1504 1505 switch (num) /* Hopefully temporary errors. */ 1506 { 1507 #ifdef EDQUOT 1508 case EDQUOT: /* Disc quota exceeded */ 1509 if (bouncequota) 1510 { 1511 ExitVal = EX_UNAVAILABLE; 1512 break; 1513 } 1514 /* FALLTHROUGH */ 1515 #endif /* EDQUOT */ 1516 #ifdef EAGAIN 1517 case EAGAIN: /* Resource temporarily unavailable */ 1518 #endif /* EAGAIN */ 1519 #ifdef EBUSY 1520 case EBUSY: /* Device busy */ 1521 #endif /* EBUSY */ 1522 #ifdef EPROCLIM 1523 case EPROCLIM: /* Too many processes */ 1524 #endif /* EPROCLIM */ 1525 #ifdef EUSERS 1526 case EUSERS: /* Too many users */ 1527 #endif /* EUSERS */ 1528 #ifdef ECONNABORTED 1529 case ECONNABORTED: /* Software caused connection abort */ 1530 #endif /* ECONNABORTED */ 1531 #ifdef ECONNREFUSED 1532 case ECONNREFUSED: /* Connection refused */ 1533 #endif /* ECONNREFUSED */ 1534 #ifdef ECONNRESET 1535 case ECONNRESET: /* Connection reset by peer */ 1536 #endif /* ECONNRESET */ 1537 #ifdef EDEADLK 1538 case EDEADLK: /* Resource deadlock avoided */ 1539 #endif /* EDEADLK */ 1540 #ifdef EFBIG 1541 case EFBIG: /* File too large */ 1542 #endif /* EFBIG */ 1543 #ifdef EHOSTDOWN 1544 case EHOSTDOWN: /* Host is down */ 1545 #endif /* EHOSTDOWN */ 1546 #ifdef EHOSTUNREACH 1547 case EHOSTUNREACH: /* No route to host */ 1548 #endif /* EHOSTUNREACH */ 1549 #ifdef EMFILE 1550 case EMFILE: /* Too many open files */ 1551 #endif /* EMFILE */ 1552 #ifdef ENETDOWN 1553 case ENETDOWN: /* Network is down */ 1554 #endif /* ENETDOWN */ 1555 #ifdef ENETRESET 1556 case ENETRESET: /* Network dropped connection on reset */ 1557 #endif /* ENETRESET */ 1558 #ifdef ENETUNREACH 1559 case ENETUNREACH: /* Network is unreachable */ 1560 #endif /* ENETUNREACH */ 1561 #ifdef ENFILE 1562 case ENFILE: /* Too many open files in system */ 1563 #endif /* ENFILE */ 1564 #ifdef ENOBUFS 1565 case ENOBUFS: /* No buffer space available */ 1566 #endif /* ENOBUFS */ 1567 #ifdef ENOMEM 1568 case ENOMEM: /* Cannot allocate memory */ 1569 #endif /* ENOMEM */ 1570 #ifdef ENOSPC 1571 case ENOSPC: /* No space left on device */ 1572 #endif /* ENOSPC */ 1573 #ifdef EROFS 1574 case EROFS: /* Read-only file system */ 1575 #endif /* EROFS */ 1576 #ifdef ESTALE 1577 case ESTALE: /* Stale NFS file handle */ 1578 #endif /* ESTALE */ 1579 #ifdef ETIMEDOUT 1580 case ETIMEDOUT: /* Connection timed out */ 1581 #endif /* ETIMEDOUT */ 1582 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK 1583 case EWOULDBLOCK: /* Operation would block. */ 1584 #endif /* defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK */ 1585 ExitVal = EX_TEMPFAIL; 1586 break; 1587 1588 default: 1589 ExitVal = EX_UNAVAILABLE; 1590 break; 1591 } 1592 return ExitVal; 1593 } 1594 1595 #if defined(ultrix) || defined(_CRAY) 1596 /* 1597 * Copyright (c) 1987, 1993 1598 * The Regents of the University of California. All rights reserved. 1599 * 1600 * Redistribution and use in source and binary forms, with or without 1601 * modification, are permitted provided that the following conditions 1602 * are met: 1603 * 1. Redistributions of source code must retain the above copyright 1604 * notice, this list of conditions and the following disclaimer. 1605 * 2. Redistributions in binary form must reproduce the above copyright 1606 * notice, this list of conditions and the following disclaimer in the 1607 * documentation and/or other materials provided with the distribution. 1608 * 3. All advertising materials mentioning features or use of this software 1609 * must display the following acknowledgement: 1610 * This product includes software developed by the University of 1611 * California, Berkeley and its contributors. 1612 * 4. Neither the name of the University nor the names of its contributors 1613 * may be used to endorse or promote products derived from this software 1614 * without specific prior written permission. 1615 * 1616 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1617 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1618 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1619 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1620 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1621 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1622 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1623 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1624 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1625 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1626 * SUCH DAMAGE. 1627 */ 1628 1629 # if defined(LIBC_SCCS) && !defined(lint) 1630 static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; 1631 # endif /* defined(LIBC_SCCS) && !defined(lint) */ 1632 1633 # include <sys/types.h> 1634 # include <sys/stat.h> 1635 # include <fcntl.h> 1636 # include <errno.h> 1637 # include <stdio.h> 1638 # include <ctype.h> 1639 1640 static int _gettemp(); 1641 1642 mkstemp(path) 1643 char *path; 1644 { 1645 int fd; 1646 1647 return (_gettemp(path, &fd) ? fd : -1); 1648 } 1649 1650 # if 0 1651 char * 1652 mktemp(path) 1653 char *path; 1654 { 1655 return(_gettemp(path, (int *)NULL) ? path : (char *)NULL); 1656 } 1657 # endif /* 0 */ 1658 1659 static 1660 _gettemp(path, doopen) 1661 char *path; 1662 register int *doopen; 1663 { 1664 extern int errno; 1665 register char *start, *trv; 1666 struct stat sbuf; 1667 u_int pid; 1668 1669 pid = getpid(); 1670 for (trv = path; *trv; ++trv); /* extra X's get set to 0's */ 1671 while (*--trv == 'X') 1672 { 1673 *trv = (pid % 10) + '0'; 1674 pid /= 10; 1675 } 1676 1677 /* 1678 * check the target directory; if you have six X's and it 1679 * doesn't exist this runs for a *very* long time. 1680 */ 1681 for (start = trv + 1;; --trv) 1682 { 1683 if (trv <= path) 1684 break; 1685 if (*trv == '/') 1686 { 1687 *trv = '\0'; 1688 if (stat(path, &sbuf) < 0) 1689 return(0); 1690 if (!S_ISDIR(sbuf.st_mode)) 1691 { 1692 errno = ENOTDIR; 1693 return(0); 1694 } 1695 *trv = '/'; 1696 break; 1697 } 1698 } 1699 1700 for (;;) 1701 { 1702 if (doopen) 1703 { 1704 if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR, 1705 0600)) >= 0) 1706 return(1); 1707 if (errno != EEXIST) 1708 return(0); 1709 } 1710 else if (stat(path, &sbuf) < 0) 1711 return(errno == ENOENT ? 1 : 0); 1712 1713 /* tricky little algorithm for backward compatibility */ 1714 for (trv = start;;) 1715 { 1716 if (!*trv) 1717 return(0); 1718 if (*trv == 'z') 1719 *trv++ = 'a'; 1720 else 1721 { 1722 if (isascii(*trv) && isdigit(*trv)) 1723 *trv = 'a'; 1724 else 1725 ++*trv; 1726 break; 1727 } 1728 } 1729 } 1730 /* NOTREACHED */ 1731 } 1732 #endif /* defined(ultrix) || defined(_CRAY) */ 1733