mail.local.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:35k
源码类别:

Email客户端

开发平台:

Unix_Linux

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