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