diff options
author | peter <peter@FreeBSD.org> | 1996-10-24 05:07:25 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1996-10-24 05:07:25 +0000 |
commit | c927066f5476bdb43c28f0e4b780360fcd08fed3 (patch) | |
tree | 1a2566bdc48c089b7507030635d9b632523b720f /usr.sbin/sendmail/src | |
parent | 117b06cef4a1d5adbcfb7492dbc5f4a29db0a6a7 (diff) | |
download | FreeBSD-src-c927066f5476bdb43c28f0e4b780360fcd08fed3.zip FreeBSD-src-c927066f5476bdb43c28f0e4b780360fcd08fed3.tar.gz |
Fold sendmail-8.8.2 changes into files that have been touched.
(^!&@$#&^! delete !!@^@^ trailing !@^&#$!& whitespace!!!)
Diffstat (limited to 'usr.sbin/sendmail/src')
-rw-r--r-- | usr.sbin/sendmail/src/collect.c | 34 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/conf.c | 865 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/conf.h | 397 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/daemon.c | 153 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/deliver.c | 523 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/domain.c | 43 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/headers.c | 177 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/main.c | 458 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/parseaddr.c | 526 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/readcf.c | 392 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/recipient.c | 40 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/savemail.c | 164 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/sendmail.8 | 197 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/sendmail.h | 268 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/srvrsmtp.c | 196 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/udb.c | 116 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/usersmtp.c | 47 | ||||
-rw-r--r-- | usr.sbin/sendmail/src/util.c | 337 |
18 files changed, 3711 insertions, 1222 deletions
diff --git a/usr.sbin/sendmail/src/collect.c b/usr.sbin/sendmail/src/collect.c index 7e43c5f..233c247 100644 --- a/usr.sbin/sendmail/src/collect.c +++ b/usr.sbin/sendmail/src/collect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)collect.c 8.49 (Berkeley) 10/29/95"; +static char sccsid[] = "@(#)collect.c 8.58 (Berkeley) 9/18/96"; #endif /* not lint */ # include <errno.h> @@ -101,8 +101,8 @@ collect(fp, smtpmode, requeueflag, hdrp, e) int buflen; int istate; int mstate; - char *pbp; - char peekbuf[8]; + u_char *pbp; + u_char peekbuf[8]; char dfname[20]; char bufbuf[MAXLINE]; extern bool isheader(); @@ -170,9 +170,10 @@ collect(fp, smtpmode, requeueflag, hdrp, e) if (setjmp(CtxCollectTimeout) != 0) { #ifdef LOG - syslog(LOG_NOTICE, - "timeout waiting for input from %s during message collect", - CurHostName ? CurHostName : "<local machine>"); + if (LogLevel > 2) + syslog(LOG_NOTICE, + "timeout waiting for input from %s during message collect", + CurHostName ? CurHostName : "<local machine>"); #endif errno = 0; usrerr("451 timeout waiting for input during message collect"); @@ -216,8 +217,6 @@ collect(fp, smtpmode, requeueflag, hdrp, e) c &= 0x7f; else HasEightBits |= bitset(0x80, c); - if (!headeronly) - e->e_msgsize++; } if (tTd(30, 94)) printf("istate=%d, c=%c (0x%x)\n", @@ -253,7 +252,7 @@ collect(fp, smtpmode, requeueflag, hdrp, e) break; case IS_DOTCR: - if (c == '\n') + if (c == '\n' && !ignrdot) goto readerr; else { @@ -287,6 +286,8 @@ collect(fp, smtpmode, requeueflag, hdrp, e) istate = IS_NORM; bufferchar: + if (!headeronly) + e->e_msgsize++; if (mstate == MS_BODY) { /* just put the character out */ @@ -316,7 +317,13 @@ bufferchar: if (obuf != bufbuf) free(obuf); } - if (c != '\0') + if (c >= 0200 && c <= 0237) + { +#if 0 /* causes complaints -- figure out something for 8.9 */ + usrerr("Illegal character 0x%x in header", c); +#endif + } + else if (c != '\0') *bp++ = c; if (istate == IS_BOL) break; @@ -564,7 +571,8 @@ readerr: if (HasEightBits) { e->e_flags |= EF_HAS8BIT; - if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode)) + if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) && + !bitset(EF_IS_MIME, e->e_flags)) { e->e_status = "5.6.1"; usrerr("554 Eight bit data not allowed"); @@ -625,6 +633,7 @@ tferror(tf, e) struct stat st; long avail; long bsize; + extern long freediskspace __P((char *, long *)); e->e_flags |= EF_NO_BODY_RETN; if (fstat(fileno(tf), &st) < 0) @@ -729,7 +738,6 @@ eatfrom(fm, e) if (*p != '\0') { char *q; - extern char *arpadate(); /* we have found a date */ q = xalloc(25); diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c index 0dc18df..3a40c98 100644 --- a/usr.sbin/sendmail/src/conf.c +++ b/usr.sbin/sendmail/src/conf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)conf.c 8.243.1.9 (Berkeley) 9/17/96"; +static char sccsid[] = "@(#)conf.c 8.312 (Berkeley) 10/17/96"; #endif /* not lint */ # include "sendmail.h" @@ -78,49 +78,50 @@ static char sccsid[] = "@(#)conf.c 8.243.1.9 (Berkeley) 9/17/96"; struct hdrinfo HdrInfo[] = { /* originator fields, most to least significant */ - "resent-sender", H_FROM|H_RESENT, - "resent-from", H_FROM|H_RESENT, - "resent-reply-to", H_FROM|H_RESENT, - "sender", H_FROM, - "from", H_FROM, - "reply-to", H_FROM, - "full-name", H_ACHECK, - "return-receipt-to", H_FROM|H_RECEIPTTO, - "errors-to", H_FROM|H_ERRORSTO, + { "resent-sender", H_FROM|H_RESENT }, + { "resent-from", H_FROM|H_RESENT }, + { "resent-reply-to", H_FROM|H_RESENT }, + { "sender", H_FROM }, + { "from", H_FROM }, + { "reply-to", H_FROM }, + { "errors-to", H_FROM|H_ERRORSTO }, + { "full-name", H_ACHECK }, + { "return-receipt-to", H_RECEIPTTO }, /* destination fields */ - "to", H_RCPT, - "resent-to", H_RCPT|H_RESENT, - "cc", H_RCPT, - "resent-cc", H_RCPT|H_RESENT, - "bcc", H_RCPT|H_BCC, - "resent-bcc", H_RCPT|H_BCC|H_RESENT, - "apparently-to", H_RCPT, + { "to", H_RCPT }, + { "resent-to", H_RCPT|H_RESENT }, + { "cc", H_RCPT }, + { "resent-cc", H_RCPT|H_RESENT }, + { "bcc", H_RCPT|H_BCC }, + { "resent-bcc", H_RCPT|H_BCC|H_RESENT }, + { "apparently-to", H_RCPT }, /* message identification and control */ - "message-id", 0, - "resent-message-id", H_RESENT, - "message", H_EOH, - "text", H_EOH, + { "message-id", 0 }, + { "resent-message-id", H_RESENT }, + { "message", H_EOH }, + { "text", H_EOH }, /* date fields */ - "date", 0, - "resent-date", H_RESENT, + { "date", 0 }, + { "resent-date", H_RESENT }, /* trace fields */ - "received", H_TRACE|H_FORCE, - "x400-received", H_TRACE|H_FORCE, - "via", H_TRACE|H_FORCE, - "mail-from", H_TRACE|H_FORCE, + { "received", H_TRACE|H_FORCE }, + { "x400-received", H_TRACE|H_FORCE }, + { "via", H_TRACE|H_FORCE }, + { "mail-from", H_TRACE|H_FORCE }, /* miscellaneous fields */ - "comments", H_FORCE, - "return-path", H_FORCE|H_ACHECK, - "content-transfer-encoding", H_CTE, - "content-type", H_CTYPE, - "content-length", H_ACHECK, - - NULL, 0, + { "comments", H_FORCE|H_ENCODABLE }, + { "return-path", H_FORCE|H_ACHECK }, + { "content-transfer-encoding", H_CTE }, + { "content-type", H_CTYPE }, + { "content-length", H_ACHECK }, + { "subject", H_ENCODABLE }, + + { NULL, 0 } }; @@ -139,18 +140,18 @@ char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ struct prival PrivacyValues[] = { - "public", PRIV_PUBLIC, - "needmailhelo", PRIV_NEEDMAILHELO, - "needexpnhelo", PRIV_NEEDEXPNHELO, - "needvrfyhelo", PRIV_NEEDVRFYHELO, - "noexpn", PRIV_NOEXPN, - "novrfy", PRIV_NOVRFY, - "restrictmailq", PRIV_RESTRICTMAILQ, - "restrictqrun", PRIV_RESTRICTQRUN, - "authwarnings", PRIV_AUTHWARNINGS, - "noreceipts", PRIV_NORECEIPTS, - "goaway", PRIV_GOAWAY, - NULL, 0, + { "public", PRIV_PUBLIC }, + { "needmailhelo", PRIV_NEEDMAILHELO }, + { "needexpnhelo", PRIV_NEEDEXPNHELO }, + { "needvrfyhelo", PRIV_NEEDVRFYHELO }, + { "noexpn", PRIV_NOEXPN }, + { "novrfy", PRIV_NOVRFY }, + { "restrictmailq", PRIV_RESTRICTMAILQ }, + { "restrictqrun", PRIV_RESTRICTQRUN }, + { "authwarnings", PRIV_AUTHWARNINGS }, + { "noreceipts", PRIV_NORECEIPTS }, + { "goaway", PRIV_GOAWAY }, + { NULL, 0 } }; @@ -227,12 +228,15 @@ setdefaults(e) TimeOuts.to_q_warning[i] = 0; /* option T */ } ServiceSwitchFile = "/etc/service.switch"; + ServiceCacheMaxAge = (time_t) 10; HostsFile = _PATH_HOSTS; MustQuoteChars = "@,;:\\()[].'"; MciInfoTimeout = 30 MINUTES; MaxRuleRecursion = MAXRULERECURSION; MaxAliasRecursion = 10; + MaxMacroRecursion = 10; ColonOkInAddr = TRUE; + DoubleBounceAddr = "postmaster"; setdefuser(); setupmaps(); setupmailers(); @@ -276,6 +280,14 @@ host_map_init(MAP *map, char *args) case 'a': map->map_app = ++p; break; + + case 'm': + map->map_mflags |= MF_MATCHONLY; + break; + + case 't': + map->map_mflags |= MF_NODEFER; + break; } while (*p != '\0' && !(isascii(*p) && isspace(*p))) p++; @@ -296,13 +308,13 @@ setupmailers() char buf[100]; extern void makemailer(); - strcpy(buf, "prog, P=/bin/sh, F=lsoD, T=DNS/RFC822/X-Unix, A=sh -c \201u"); + strcpy(buf, "prog, P=/bin/sh, F=lsoDq9, T=DNS/RFC822/X-Unix, A=sh -c \201u"); makemailer(buf); - strcpy(buf, "*file*, P=[FILE], F=lsDFMPEou, T=DNS/RFC822/X-Unix, A=FILE"); + strcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=DNS/RFC822/X-Unix, A=FILE \201u"); makemailer(buf); - strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); + strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u"); makemailer(buf); } /* @@ -359,6 +371,11 @@ setupmaps() map_parseargs, nisplus_map_open, null_map_close, nisplus_map_lookup, null_map_store); #endif +#ifdef LDAPMAP + MAPDEF("ldapx", NULL, 0, + ldap_map_parseargs, ldap_map_open, ldap_map_close, + ldap_map_lookup, null_map_store); +#endif #ifdef HESIOD MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY, @@ -566,7 +583,7 @@ inithostmaps() else if (strcmp(maptype[i], "netinfo") == 0 && stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL) { - strcpy(buf, "aliases.netinfo netinfo /aliases"); + strcpy(buf, "aliases.netinfo netinfo -z, /aliases"); (void) makemapentry(buf); } #endif @@ -670,15 +687,12 @@ switch_map_find(service, maptype, mapreturn) char *maptype[MAXMAPSTACK]; short mapreturn[MAXMAPACTIONS]; { - register FILE *fp; int svcno; - static char buf[MAXLINE]; #ifdef _USE_SUN_NSSWITCH_ struct __nsw_switchconfig *nsw_conf; enum __nsw_parse_err pserr; struct __nsw_lookup *lk; - int nsw_rc; static struct __nsw_lookup lkp0 = { "files", {1, 0, 0, 0}, NULL, NULL }; static struct __nsw_switchconfig lkp_default = @@ -759,44 +773,85 @@ switch_map_find(service, maptype, mapreturn) ** Fall-back mechanism. */ + STAB *st; + time_t now = curtime(); + for (svcno = 0; svcno < MAXMAPACTIONS; svcno++) mapreturn[svcno] = 0; - svcno = 0; - fp = fopen(ServiceSwitchFile, "r"); - if (fp != NULL) + if ((now - ServiceCacheTime) > (time_t) ServiceCacheMaxAge) { - while (fgets(buf, sizeof buf, fp) != NULL) + /* (re)read service switch */ + register FILE *fp; + + if (ConfigFileRead) + ServiceCacheTime = now; + fp = fopen(ServiceSwitchFile, "r"); + if (fp != NULL) { - register char *p; - - p = strpbrk(buf, "#\n"); - if (p != NULL) - *p = '\0'; - p = strpbrk(buf, " \t"); - if (p != NULL) - *p++ = '\0'; - if (strcmp(buf, service) != 0) - continue; - - /* got the right service -- extract data */ - do + char buf[MAXLINE]; + + while (fgets(buf, sizeof buf, fp) != NULL) { + register char *p; + + p = strpbrk(buf, "#\n"); + if (p != NULL) + *p = '\0'; + p = strpbrk(buf, " \t"); + if (p != NULL) + *p++ = '\0'; + if (buf[0] == '\0') + continue; while (isspace(*p)) p++; if (*p == '\0') - break; - maptype[svcno++] = p; - p = strpbrk(p, " \t"); - if (p != NULL) + continue; + + /* + ** Find/allocate space for this service entry. + ** Space for all of the service strings + ** are allocated at once. This means + ** that we only have to free the first + ** one to free all of them. + */ + + st = stab(buf, ST_SERVICE, ST_ENTER); + if (st->s_service[0] != NULL) + free((void *) st->s_service[0]); + p = newstr(p); + for (svcno = 0; svcno < MAXMAPSTACK; ) + { + if (*p == '\0') + break; + st->s_service[svcno++] = p; + p = strpbrk(p, " \t"); + if (p == NULL) + break; *p++ = '\0'; - } while (p != NULL); + while (isspace(*p)) + p++; + } + if (svcno < MAXMAPSTACK) + st->s_service[svcno] = NULL; + } fclose(fp); - return svcno; } + } - /* service was not found -- use compiled in default */ - fclose(fp); + /* look up entry in cache */ + st = stab(service, ST_SERVICE, ST_FIND); + if (st != NULL && st->s_service[0] != NULL) + { + /* extract data */ + svcno = 0; + while (svcno < MAXMAPSTACK) + { + maptype[svcno] = st->s_service[svcno]; + if (maptype[svcno++] == NULL) + break; + } + return --svcno; } #endif @@ -1017,9 +1072,14 @@ setsignal(sig, handler) struct sigaction n, o; bzero(&n, sizeof n); +# if USE_SA_SIGACTION + n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler; + n.sa_flags = SA_RESTART|SA_SIGINFO; +# else n.sa_handler = handler; -# ifdef SA_RESTART +# ifdef SA_RESTART n.sa_flags = SA_RESTART; +# endif # endif if (sigaction(sig, &n, &o) < 0) return SIG_ERR; @@ -1042,13 +1102,20 @@ releasesignal(sig) int sig; { #ifdef BSD4_3 - return sigsetmask(sigblock(0) & ~(1 << sig)); +# ifndef sigmask +# define sigmask(s) (1 << ((s) - 1)) +# endif + return sigsetmask(sigblock(0) & ~sigmask(sig)); #else +# ifdef ALTOS_SYSTEM_V + sigrelse(sig) ; +# else sigset_t sset; sigemptyset(&sset); sigaddset(&sset, sig); return sigprocmask(SIG_UNBLOCK, &sset, NULL); +# endif #endif } /* @@ -1095,7 +1162,11 @@ rlsesigs() */ #ifdef _AUX_SOURCE -# include <compat.h> +# include <compat.h> +#endif + +#if SHARE_V1 +# include <shares.h> #endif void @@ -1107,6 +1178,18 @@ init_md(argc, argv) setcompat(getcompat() | COMPAT_BSDPROT); #endif +#ifdef SUN_EXTENSIONS + init_md_sun(); +#endif + +#if _CONVEX_SOURCE + /* keep gethostby*() from stripping the local domain name */ + set_domain_trim_off(); +#endif +#if SECUREWARE + set_auth_parameters(argc, argv); +#endif + #ifdef VENDOR_DEFAULT VendorCode = VENDOR_DEFAULT; #else @@ -1159,6 +1242,7 @@ init_vendor_macros(e) #define LA_READKSYM 8 /* SVR4: use MIOC_READKSYM ioctl call */ #define LA_DGUX 9 /* special DGUX implementation */ #define LA_HPUX 10 /* special HPUX implementation */ +#define LA_IRIX6 11 /* special IRIX 6.2 implementation */ /* do guesses based on general OS type */ #ifndef LA_TYPE @@ -1174,9 +1258,6 @@ init_vendor_macros(e) # define FSHIFT 10 # endif -# if defined(_AIX3) -# define FSHIFT 16 -# endif #endif #ifndef FSHIFT @@ -1228,6 +1309,7 @@ struct nlist Nl[] = #endif #define X_AVENRUN 0 +int getla() { static int kmem = -1; @@ -1245,22 +1327,12 @@ getla() if (kmem < 0) { - kmem = open(_PATH_KMEM, 0, 0); - if (kmem < 0) - { - if (tTd(3, 1)) - printf("getla: open(/dev/kmem): %s\n", - errstring(errno)); - return (-1); - } - (void) fcntl(kmem, F_SETFD, 1); - #ifdef _AUX_SOURCE strcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN); Nl[1].n_name[0] = '\0'; #endif -#ifdef _AIX3 +#if defined(_AIX3) || defined(_AIX4) if (knlist(Nl, 1, sizeof Nl[0]) < 0) #else if (nlist(_PATH_UNIX, Nl) < 0) @@ -1281,6 +1353,16 @@ getla() #ifdef NAMELISTMASK Nl[X_AVENRUN].n_value &= NAMELISTMASK; #endif + + kmem = open(_PATH_KMEM, 0, 0); + if (kmem < 0) + { + if (tTd(3, 1)) + printf("getla: open(/dev/kmem): %s\n", + errstring(errno)); + return (-1); + } + (void) fcntl(kmem, F_SETFD, 1); } if (tTd(3, 20)) printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); @@ -1295,9 +1377,15 @@ getla() # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) if (tTd(3, 5)) { +# if LA_TYPE == LA_SHORT printf("getla: avenrun = %d", avenrun[0]); if (tTd(3, 15)) printf(", %d, %d", avenrun[1], avenrun[2]); +# else + printf("getla: avenrun = %ld", avenrun[0]); + if (tTd(3, 15)) + printf(", %ld, %ld", avenrun[1], avenrun[2]); +# endif printf("\n"); } if (tTd(3, 1)) @@ -1450,6 +1538,7 @@ getla() # include <mach.h> #endif +int getla() { processor_set_t default_set; @@ -1460,14 +1549,22 @@ getla() error = processor_set_default(host_self(), &default_set); if (error != KERN_SUCCESS) + { + if (tTd(3, 1)) + perror("getla: processor_set_default failed:"); return -1; + } info_count = PROCESSOR_SET_BASIC_INFO_COUNT; if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host, (processor_set_info_t)&info, &info_count) != KERN_SUCCESS) { + if (tTd(3, 1)) + perror("getla: processor_set_info failed:"); return -1; } + if (tTd(3, 1)) + printf("getla: %d\n", (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE); return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; } @@ -1520,6 +1617,167 @@ getla() #endif /* LA_TYPE == LA_PROCSTR */ +#if LA_TYPE == LA_IRIX6 + +#include <nlist.h> +#include <sys/types.h> +#include <unistd.h> + +#define X_AVENRUN 0 +struct nlist Nl32[] = +{ + { LA_AVENRUN }, + { 0 }, +}; +struct nlist64 Nl64[] = +{ + { LA_AVENRUN }, + { 0 }, +}; + +int getla(void) +{ + static int kmem = -1; + static enum { getla_none, getla_32, getla_64 } kernel_type = + getla_none; + uint32_t avenrun32[3]; + uint64_t avenrun64[3]; + + if (kernel_type == getla_none) + { + /* Try 32 bit kernel ... */ + errno = 0; + if (nlist(_PATH_UNIX, Nl32) == 0) + { + if (tTd(3, 20)) + printf("getla: Kernel is 32bit\n"); + + if (Nl32[X_AVENRUN].n_value == 0) + { + if (tTd(3, 1)) + printf("getla: nlist(%s, %s) ==> 0\n", + _PATH_UNIX, LA_AVENRUN); + } + else + kernel_type = getla_32; + } + else if (errno != 0) + { + if (tTd(3, 1)) + printf("getla: nlist(%s): %s\n", + _PATH_UNIX, errstring(errno)); + } + else + { + if (tTd(3, 20)) + printf("getla: Kernel is not 32bit\n"); + } + + /* Try 64 bit kernel ... */ + errno = 0; + if (nlist64(_PATH_UNIX, Nl64) == 0) + { + if (tTd(3, 20)) + printf("getla: Kernel is 64bit\n"); + + if (Nl64[X_AVENRUN].n_value == 0) + { + if (tTd(3, 1)) + printf("getla: nlist(%s, %s) ==> 0\n", + _PATH_UNIX, LA_AVENRUN); + } + else + kernel_type = getla_64; + } + else if (errno != 0) + { + if (tTd(3, 1)) + printf("getla: nlist64(%s): %s\n", + _PATH_UNIX, errstring(errno)); + } + else + { + if (tTd(3, 20)) + printf("getla: Kernel is not 64bit\n"); + } + } + + if (kernel_type == getla_none) + { + if (tTd(3, 1)) + printf("getla: Failed to determine kernel type\n"); + return -1; + } + + if (kmem < 0) + { + kmem = open(_PATH_KMEM, 0, 0); + if (kmem < 0) + { + if (tTd(3, 1)) + printf("getla: open(/dev/kmem): %s\n", + errstring(errno)); + return -1; + } + (void) fcntl(kmem, F_SETFD, 1); + } + + switch (kernel_type) + { + case getla_32: + if (lseek(kmem, (off_t) Nl32[X_AVENRUN].n_value, SEEK_SET) == -1 || + read(kmem, (char *) avenrun32, sizeof(avenrun32)) < sizeof(avenrun32)) + { + if (tTd(3, 1)) + printf("getla: lseek or read: %s\n", + errstring(errno)); + return -1; + } + if (tTd(3, 5)) + { + printf("getla: avenrun{32} = %ld", + (long int) avenrun32[0]); + if (tTd(3, 15)) + printf(", %ld, %ld", + (long int)avenrun32[1], + (long int)avenrun32[2]); + printf("\n"); + } + if (tTd(3, 1)) + printf("getla: %d\n", + (int) (avenrun32[0] + FSCALE/2) >> FSHIFT); + return ((int) (avenrun32[0] + FSCALE/2) >> FSHIFT); + + case getla_64: + /* Using of lseek64 is perhaps overkill ... */ + if (lseek64(kmem, (off64_t) Nl64[X_AVENRUN].n_value, SEEK_SET) == -1 || + read(kmem, (char *) avenrun64, sizeof(avenrun64)) < + sizeof(avenrun64)) + { + if (tTd(3, 1)) + printf("getla: lseek64 or read: %s\n", + errstring(errno)); + return -1; + } + if (tTd(3, 5)) + { + printf("getla: avenrun{64} = %lld", + (long long int) avenrun64[0]); + if (tTd(3, 15)) + printf(", %lld, %lld", + (long long int) avenrun64[1], + (long long int) avenrun64[2]); + printf("\n"); + } + if (tTd(3, 1)) + printf("getla: %d\n", + (int) (avenrun64[0] + FSCALE/2) >> FSHIFT); + return ((int) (avenrun64[0] + FSCALE/2) >> FSHIFT); + } + return -1; +} +#endif + #if LA_TYPE == LA_ZERO getla() @@ -1531,7 +1789,6 @@ getla() #endif /* LA_TYPE == LA_ZERO */ - /* * Copyright 1989 Massachusetts Institute of Technology * @@ -1600,7 +1857,7 @@ shouldqueue(pri, ctime) bool rval; if (tTd(3, 30)) - printf("shouldqueue: CurrentLA=%d, pri=%d: ", CurrentLA, pri); + printf("shouldqueue: CurrentLA=%d, pri=%ld: ", CurrentLA, pri); if (CurrentLA < QueueLA) { if (tTd(3, 30)) @@ -1624,7 +1881,7 @@ shouldqueue(pri, ctime) ** REFUSECONNECTIONS -- decide if connections should be refused ** ** Parameters: -** none. +** port -- port number (for error messages only) ** ** Returns: ** TRUE if incoming SMTP connections should be refused @@ -1636,8 +1893,12 @@ shouldqueue(pri, ctime) */ bool -refuseconnections() +refuseconnections(port) + int port; { + time_t now; + static time_t lastconn = (time_t) 0; + static int conncnt = 0; extern bool enoughdiskspace(); extern void setproctitle __P((const char *, ...)); @@ -1646,20 +1907,55 @@ refuseconnections() return TRUE; #endif + now = curtime(); + if (now != lastconn) + { + lastconn = now; + conncnt = 0; + } + else if (conncnt++ > ConnRateThrottle && ConnRateThrottle > 0) + { + /* sleep to flatten out connection load */ + setproctitle("deferring connections on port %d: %d per second", + port, ConnRateThrottle); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "deferring connections on port %d: %d per second", + port, ConnRateThrottle); +#endif + sleep(1); + } + + CurrentLA = getla(); if (CurrentLA >= RefuseLA) { - setproctitle("rejecting connections: load average: %d", - CurrentLA); + setproctitle("rejecting connections on port %d: load average: %d", + port, CurrentLA); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "rejecting connections on port %d: load average: %d", + port, CurrentLA); +#endif } else if (!enoughdiskspace(MinBlocksFree + 1)) { - setproctitle("rejecting connections: min free: %d", - MinBlocksFree); + setproctitle("rejecting connections on port %d: min free: %d", + port, MinBlocksFree); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "rejecting connections on port %d: min free: %d", + port, MinBlocksFree); +#endif } else if (MaxChildren > 0 && CurChildren >= MaxChildren) { - setproctitle("rejecting connections: maximum children: %d", - CurChildren); + setproctitle("rejecting connections on port %d: %d children, max %d", + port, CurChildren, MaxChildren); +#ifdef LOG + if (LogLevel >= 14) + syslog(LOG_INFO, "rejecting connections on port %d: %d children, max %d", + port, CurChildren, MaxChildren); +#endif } else return FALSE; @@ -1818,7 +2114,7 @@ setproctitle(fmt, va_alist) /* print the argument string */ VA_START(fmt); - (void) vsnprintf(p, sizeof buf - (p - buf), fmt, ap); + (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap); VA_END; i = strlen(buf); @@ -1847,7 +2143,7 @@ setproctitle(fmt, va_alist) } buf[PSARGSZ - 1] = '\0'; seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u; - if (lseek(kmem, (char *) seek_off, SEEK_SET) == seek_off) + if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off) (void) write(kmem, buf, PSARGSZ); # endif # if SPT_TYPE == SPT_REUSEARGV @@ -1884,10 +2180,10 @@ reapchild(sig) int sig; { int olderrno = errno; + pid_t pid; # ifdef HASWAITPID auto int status; int count; - int pid; count = 0; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) @@ -1895,24 +2191,26 @@ reapchild(sig) if (count++ > 1000) { #ifdef LOG - syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", - pid, status); + if (LogLevel > 0) + syslog(LOG_ALERT, + "reapchild: waitpid loop: pid=%d, status=%x", + pid, status); #endif break; } - CurChildren--; + proc_list_drop(pid); } # else # ifdef WNOHANG union wait status; - while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) - CurChildren--; + while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0) + proc_list_drop(pid); # else /* WNOHANG */ auto int status; - while (wait(&status) > 0) - CurChildren--; + while ((pid = wait(&status)) > 0) + proc_list_drop(pid); # endif /* WNOHANG */ # endif # ifdef SYS5SIGNALS @@ -1953,7 +2251,7 @@ putenv(str) * find out how much of str to match when searching * for a string to replace. */ - if ((tmp = index(str, '=')) == NULL || tmp == str) + if ((tmp = strchr(str, '=')) == NULL || tmp == str) matchlen = strlen(str); else matchlen = (int) (tmp - str); @@ -2317,7 +2615,7 @@ getopt(nargc,nargv,ostr) if (!*place) ++optind; tell(": illegal option -- "); } - if (*++oli != ':') { /* don't need argument */ + if (oli && *++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } @@ -2400,9 +2698,9 @@ vsprintf(s, fmt, ap) * causing nast effects. **************************************************************/ -/*static char _id[] = "$Id: conf.c,v 1.1.1.5 1996/09/19 02:59:42 peter Exp $";*/ static void dopr(); static char *end; +static int SnprfOverflow; /* VARARGS3 */ int @@ -2416,30 +2714,34 @@ snprintf(str, count, fmt, va_alist) va_dcl #endif { - VA_LOCAL_DECL + int len; + VA_LOCAL_DECL - VA_START (fmt); - (void) vsnprintf ( str, count, fmt, ap); - VA_END; - return( strlen( str ) ); + VA_START(fmt); + len = vsnprintf(str, count, fmt, ap); + VA_END; + return len; } # ifndef luna2 int vsnprintf(str, count, fmt, args) - char *str; - size_t count; - const char *fmt; - va_list args; + char *str; + size_t count; + const char *fmt; + va_list args; { - str[0] = 0; - end = str+count-1; - dopr( str, fmt, args ); - if( count>0 ){ - end[0] = 0; - } - return(strlen(str)); + str[0] = 0; + end = str + count - 1; + SnprfOverflow = 0; + dopr( str, fmt, args ); + if (count > 0) + end[0] = 0; + if (SnprfOverflow && tTd(57, 2)) + printf("\nvsnprintf overflow, len = %d, str = %s", + count, shortenstring(str, 203)); + return strlen(str); } /* @@ -2538,8 +2840,11 @@ dopr( buffer, format, args ) fmtnum( value,-16,0, ljust, len, zpad ); break; case 's': strvalue = va_arg( args, char *); - if (maxwidth > 0 || !pointflag) + if (maxwidth > 0 || !pointflag) { + if (pointflag && len > maxwidth) + len = maxwidth; /* Adjust padding */ fmtstr( strvalue,ljust,len,zpad, maxwidth); + } break; case 'c': ch = va_arg( args, int ); @@ -2663,14 +2968,14 @@ dopr_outch( c ) #if 0 if( iscntrl(c) && c != '\n' && c != '\t' ){ c = '@' + (c & 0x1F); - if( end == 0 || output < end ){ + if( end == 0 || output < end ) *output++ = '^'; - } } #endif - if( end == 0 || output < end ){ + if( end == 0 || output < end ) *output++ = c; - } + else + SnprfOverflow++; } # endif /* !luna2 */ @@ -2694,7 +2999,7 @@ dopr_outch( c ) # define _PATH_SHELLS "/etc/shells" # endif -# ifdef _AIX3 +# if defined(_AIX3) || defined(_AIX4) # include <userconf.h> # include <usersec.h> # endif @@ -2722,7 +3027,7 @@ char *DefaultUserShells[] = "/bin/posix/sh", # endif #endif -#ifdef _AIX3 +#if defined(_AIX3) || defined(_AIX4) "/bin/ksh", /* Korn shell */ "/usr/bin/ksh", "/bin/tsh", /* trusted shell */ @@ -3254,9 +3559,9 @@ chownsafe(fd) tfd = open(s, O_RDONLY|O_CREAT, 0600); rval = fchown(tfd, DefUid, DefGid) != 0; close(tfd); - unlink(s); setresuid(o_uid, o_euid, -1); setresgid(o_gid, o_egid, -1); + unlink(s); return rval; #else # ifdef _POSIX_CHOWN_RESTRICTED @@ -3301,7 +3606,7 @@ chownsafe(fd) */ #if HASSETRLIMIT -# ifdef apollo +# ifdef RLIMIT_NEEDS_SYS_TIME_H # include <sys/time.h> # endif # include <sys/resource.h> @@ -3409,10 +3714,21 @@ setvendor(vendor) ** none. */ +#if SHARE_V1 +int DefShareUid; /* default share uid to run as -- unused??? */ +#endif + void vendor_pre_defaults(e) ENVELOPE *e; { +#if SHARE_V1 + /* OTHERUID is defined in shares.h, do not be alarmed */ + DefShareUid = OTHERUID; +#endif +#ifdef SUN_EXTENSIONS + sun_pre_defaults(e); +#endif } @@ -3420,6 +3736,91 @@ void vendor_post_defaults(e) ENVELOPE *e; { +#ifdef SUN_EXTENSIONS + sun_post_defaults(e); +#endif +} +/* +** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode +*/ + +void +vendor_daemon_setup(e) + ENVELOPE *e; +{ +#if SECUREWARE + if (getluid() != -1) + { + usrerr("Daemon cannot have LUID"); + exit(EX_USAGE); + } +#endif /* SECUREWARE */ +} +/* +** VENDOR_SET_UID -- do setup for setting a user id +** +** This is called when we are still root. +** +** Parameters: +** uid -- the uid we are about to become. +** +** Returns: +** none. +*/ + +void +vendor_set_uid(uid) + UID_T uid; +{ + /* + ** We need to setup the share groups (lnodes) + ** and and auditing inforation (luid's) + ** before we loose our ``root''ness. + */ +#if SHARE_V1 + if (setupshares(uid, syserr) != 0) + syserr("Unable to set up shares"); +#endif +#if SECUREWARE + (void) setup_secure(uid); +#endif +} +/* +** VALIDATE_CONNECTION -- check connection for rationality +** +** If the connection is rejected, this routine should log an +** appropriate message -- but should never issue any SMTP protocol. +** +** Parameters: +** sap -- a pointer to a SOCKADDR naming the peer. +** hostname -- the name corresponding to sap. +** e -- the current envelope. +** +** Returns: +** TRUE -- if the connection should be accepted. +** FALSE -- if it should be rejected. +*/ + +#if TCPWRAPPERS +# include <tcpd.h> +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif + +bool +validate_connection(sap, hostname, e) + SOCKADDR *sap; + char *hostname; + ENVELOPE *e; +{ + if (rscheck("check_relay", hostname, anynet_ntoa(sap), e) != EX_OK) + return FALSE; + +#if TCPWRAPPERS + if (!hosts_ctl("sendmail", hostname, anynet_ntoa(sap), STRING_UNKNOWN)) + return FALSE; +#endif + return TRUE; } /* ** STRTOL -- convert string to long integer @@ -3577,8 +3978,8 @@ sm_gethostbyname(name) char *name; { struct hostent *h; -#if defined(SOLARIS) && SOLARIS < 204 || defined(sony_news) && defined(__svr4) -# if SOLARIS == 203 +#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) +# if SOLARIS == 20300 || SOLARIS == 203 static struct hostent hp; static char buf[1000]; extern struct hostent *_switch_gethostbyname_r(); @@ -3615,7 +4016,7 @@ sm_gethostbyname(name) if (nmaps >= 0) { /* try short name */ - if (strlen(name) > sizeof hbuf - 1) + if (strlen(name) > (SIZE_T) sizeof hbuf - 1) return NULL; strcpy(hbuf, name); shorten_hostname(hbuf); @@ -3646,8 +4047,8 @@ sm_gethostbyaddr(addr, len, type) int len; int type; { -#if defined(SOLARIS) && SOLARIS < 204 -# if SOLARIS == 203 +#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) +# if SOLARIS == 20300 || SOLARIS == 203 static struct hostent hp; static char buf[1000]; extern struct hostent *_switch_gethostbyaddr_r(); @@ -3680,6 +4081,68 @@ sm_getpwuid(uid) return getpwuid(uid); } /* +** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup +** +** Set up the trusted computing environment for C2 level security +** under SecureWare. +** +** Parameters: +** uid -- uid of the user to initialize in the TCB +** +** Returns: +** none +** +** Side Effects: +** Initialized the user in the trusted computing base +*/ + +#if SECUREWARE + +# include <sys/security.h> +# include <prot.h> + +void +secureware_setup_secure(uid) + UID_T uid; +{ + int rc; + + if (getluid() != -1) + return; + + if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN) + { + switch (rc) + { + case SSI_NO_PRPW_ENTRY: + syserr("No protected passwd entry, uid = %d", uid); + break; + + case SSI_LOCKED: + syserr("Account has been disabled, uid = %d", uid); + break; + + case SSI_RETIRED: + syserr("Account has been retired, uid = %d", uid); + break; + + case SSI_BAD_SET_LUID: + syserr("Could not set LUID, uid = %d", uid); + break; + + case SSI_BAD_SET_PRIVS: + syserr("Could not set kernel privs, uid = %d", uid); + + default: + syserr("Unknown return code (%d) from set_secure_info(%d)", + rc, uid); + break; + } + exit(EX_NOPERM); + } +} +#endif /* SECUREWARE */ +/* ** LOAD_IF_NAMES -- load interface-specific names into $=w ** ** Parameters: @@ -3725,7 +4188,6 @@ load_if_names() close(s); return; } - close(s); /* scan the list of IP address */ if (tTd(0, 40)) @@ -3738,6 +4200,9 @@ load_if_names() struct sockaddr *sa = &ifr->ifr_addr; struct in_addr ia; struct hostent *hp; +#ifdef SIOCGIFFLAGS + struct ifreq ifrf; +#endif char ip_addr[256]; extern char *inet_ntoa(); extern struct hostent *gethostbyaddr(); @@ -3752,19 +4217,35 @@ load_if_names() if (tTd(0, 20)) printf("%s\n", anynet_ntoa((SOCKADDR *) sa)); - /* for some reason gcc 2.3 pukes on || here */ - if (!bitset(IFF_UP, ifr->ifr_flags)) - continue; if (ifr->ifr_addr.sa_family != AF_INET) continue; +#ifdef SIOCGIFFLAGS + bzero(&ifrf, sizeof(struct ifreq)); + strncpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name)); + ioctl(s, SIOCGIFFLAGS, (char *) &ifrf); + if (tTd(0, 41)) + printf("\tflags: %x\n", ifrf.ifr_flags); + if (!bitset(IFF_UP, ifrf.ifr_flags)) + continue; +#else + if (!bitset(IFF_UP, ifr->ifr_flags)) + continue; +#endif + /* extract IP address from the list*/ ia = (((struct sockaddr_in *) sa)->sin_addr); + if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE) + { + message("WARNING: interface %s is UP with %s address", + ifr->ifr_name, inet_ntoa(ia)); + continue; + } /* save IP address in text from */ (void) snprintf(ip_addr, sizeof ip_addr, "[%.*s]", sizeof ip_addr - 3, - inet_ntoa(((struct sockaddr_in *) sa)->sin_addr)); + inet_ntoa(ia)); if (!wordinclass(ip_addr, 'w')) { setclass('w', ip_addr); @@ -3780,8 +4261,12 @@ load_if_names() hp = sm_gethostbyaddr((char *) &ia, sizeof(ia), AF_INET); if (hp == NULL) { - syslog(LOG_CRIT, "gethostbyaddr() failed for %.100s\n", - inet_ntoa(ia)); +#ifdef LOG + if (LogLevel > 3) + syslog(LOG_WARNING, + "gethostbyaddr() failed for %.100s\n", + inet_ntoa(ia)); +#endif continue; } @@ -3805,6 +4290,7 @@ load_if_names() hp->h_aliases++; } } + close(s); #endif } /* @@ -3818,14 +4304,21 @@ load_if_names() # define MAXSYSLOGTRIES 100 # undef syslog +# ifdef V4FS +# define XCNST const +# define CAST (const char *) +# else +# define XCNST +# define CAST +# endif -# ifdef __STDC__ void -hard_syslog(int pri, char *msg, ...) +# ifdef __STDC__ +hard_syslog(int pri, XCNST char *msg, ...) # else hard_syslog(pri, msg, va_alist) int pri; - char *msg; + XCNST char *msg; va_dcl # endif { @@ -3837,10 +4330,11 @@ hard_syslog(pri, msg, va_alist) vsnprintf(buf, sizeof buf, msg, ap); VA_END; - for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; ) + for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; ) continue; } +# undef CAST #endif /* ** LOCAL_HOSTNAME_LENGTH @@ -3886,12 +4380,18 @@ char *CompileOptions[] = #if HES_GETMAILHOST "HES_GETMAILHOST", #endif +#if LDAPMAP + "LDAPMAP", +#endif #ifdef LOG "LOG", #endif #if MATCHGECOS "MATCHGECOS", #endif +#if MIME7TO8 + "MIME7TO8", +#endif #if MIME8TO7 "MIME8TO7", #endif @@ -3928,12 +4428,24 @@ char *CompileOptions[] = #if NISPLUS "NISPLUS", #endif +#if QUEUE + "QUEUE", +#endif #if SCANF "SCANF", #endif +#if SMTP + "SMTP", +#endif +#if SMTPDEBUG + "SMTPDEBUG", +#endif #if SUID_ROOT_FILES_OK "SUID_ROOT_FILES_OK", #endif +#if TCPWRAPPERS + "TCPWRAPPERS", +#endif #if USERDB "USERDB", #endif @@ -3959,6 +4471,9 @@ char *OsCompileOptions[] = #if HASFLOCK "HASFLOCK", #endif +#if HASGETDTABLESIZE + "HASGETDTABLESIZE", +#endif #if HASGETUSERSHELL "HASGETUSERSHELL", #endif @@ -3971,18 +4486,36 @@ char *OsCompileOptions[] = #if HASSETREUID "HASSETREUID", #endif +#if HASSETRLIMIT + "HASSETRLIMIT", +#endif #if HASSETSID "HASSETSID", #endif +#if HASSETUSERCONTEXT + "HASSETUSERCONTEXT", +#endif #if HASSETVBUF "HASSETVBUF", #endif +#if HASSIGSETMASK + "HASSIGSETMASK", +#endif #if HASSNPRINTF "HASSNPRINTF", #endif +#if HASULIMIT + "HASULIMIT", +#endif #if HASUNAME "HASUNAME", #endif +#if HASUNSETENV + "HASUNSETENV", +#endif +#if HASWAITPID + "HASWAITPID", +#endif #if IDENTPROTO "IDENTPROTO", #endif @@ -3995,12 +4528,24 @@ char *OsCompileOptions[] = #if NOFTRUNCATE "NOFTRUNCATE", #endif +#if RLIMIT_NEEDS_SYS_TIME_H + "RLIMIT_NEEDS_SYS_TIME_H", +#endif +#if SECUREWARE + "SECUREWARE", +#endif +#if SHARE_V1 + "SHARE_V1", +#endif #if SYS5SETPGRP "SYS5SETPGRP", #endif #if SYSTEM5 "SYSTEM5", #endif +#if USE_SA_SIGACTION + "USE_SA_SIGACTION", +#endif #if USESETEUID "USESETEUID", #endif diff --git a/usr.sbin/sendmail/src/conf.h b/usr.sbin/sendmail/src/conf.h index ca6cae3..66ddf12 100644 --- a/usr.sbin/sendmail/src/conf.h +++ b/usr.sbin/sendmail/src/conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)conf.h 8.220 (Berkeley) 11/29/95 + * @(#)conf.h 8.267 (Berkeley) 10/17/96 */ /* @@ -66,7 +66,7 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define MAXMAILERS 25 /* maximum mailers known to system */ # define MAXRWSETS 200 /* max # of sets of rewriting rules */ # define MAXPRIORITIES 25 /* max values for Precedence: field */ -# define MAXMXHOSTS 20 /* max # of MX records */ +# define MAXMXHOSTS 100 /* max # of MX records for one host */ # define SMTPLINELIM 990 /* maximum SMTP line length */ # define MAXKEY 128 /* maximum size of a database key */ # define MEMCHUNKSIZE 1024 /* chunk size for memory allocation */ @@ -183,9 +183,6 @@ struct rusage; /* forward declaration to get gcc to shut up in wait.h */ # define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */ # endif # define syslog hard_syslog -# ifdef __STDC__ -extern void hard_syslog(int, char *, ...); -# endif # ifdef V4FS /* HP-UX 10.x */ @@ -205,12 +202,25 @@ extern void hard_syslog(int, char *, ...); # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif +# ifdef __STDC__ +extern void hard_syslog(int, char *, ...); +# endif # endif #endif /* +** IBM AIX 4.x +*/ + +#ifdef _AIX4 +# define _AIX3 1 /* pull in AIX3 stuff */ +# define HASSETREUID 1 /* setreuid(2) works */ +#endif + + +/* ** IBM AIX 3.x -- actually tested for 3.2.3 */ @@ -222,29 +232,89 @@ extern void hard_syslog(int, char *, ...); # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ -# define FORK fork /* no vfork primitive available */ # define GIDSET_T gid_t # define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ # define SPT_PADCHAR '\0' /* pad process title with nulls */ # define LA_TYPE LA_INT +# define FSHIFT 16 # define LA_AVENRUN "avenrun" #endif /* +** IBM AIX 2.2.1 -- actually tested for osupdate level 2706+1773 +** +** From Mark Whetzel <markw@wg.waii.com>. +*/ + +#ifdef AIX /* AIX/RT compiler pre-defines this */ +# include <paths.h> +# include <sys/time.h> /* AIX/RT resource.h does NOT include this */ +# define HASINITGROUPS 1 /* has initgroups(3) call */ +# define HASUNAME 1 /* use System V uname(2) system call */ +# define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ +# define HASFCHMOD 0 /* does not have fchmod(2) syscall */ +# define HASSETREUID 1 /* use setreuid(2) -lbsd system call */ +# define HASSETVBUF 1 /* use setvbuf(2) system call */ +# define HASSETRLIMIT 0 /* does not have setrlimit call */ +# define HASFLOCK 0 /* does not have flock call - use fcntl */ +# define HASULIMIT 1 /* use ulimit instead of setrlimit call */ +# define NEEDGETOPT 1 /* Do we need theirs or ours */ +# define SYS5SETPGRP 1 /* don't have setpgid on AIX/RT */ +# define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ +# define BSD4_3 1 /* NOT bsd 4.4 or posix signals */ +# define GIDSET_T int +# define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ +# define SPT_PADCHAR '\0' /* pad process title with nulls */ +# define LA_TYPE LA_SUBR /* use our ported loadavgd daemon */ +# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ +# define ARBPTR_T int * +# define void int +typedef int pid_t; +/* RTisms for BSD compatibility, specified in the Makefile + define BSD 1 + define BSD_INCLUDES 1 + define BSD_REMAP_SIGNAL_TO_SIGVEC + RTisms needed above */ +/* make this sendmail in a completely different place */ +# define _PATH_VENDORCF "/usr/local/newmail/sendmail.cf" +# ifndef _PATH_SENDMAILPID +# define _PATH_SENDMAILPID "/usr/local/newmail/sendmail.pid" +# endif +#endif + + +/* ** Silicon Graphics IRIX ** ** Compiles on 4.0.1. ** ** Use IRIX64 instead of IRIX for 64-bit IRIX (6.0). ** Use IRIX5 instead of IRIX for IRIX 5.x. +** +** This version tries to be adaptive using _MIPS_SIM: +** _MIPS_SIM == _ABIO32 (= 1) Abi: -32 on IRIX 6.2 +** _MIPS_SIM == _ABIN32 (= 2) Abi: -n32 on IRIX 6.2 +** _MIPS_SIM == _ABI64 (= 3) Abi: -64 on IRIX 6.2 +** +** _MIPS_SIM is 1 also on IRIX 5.3 ** ** IRIX64 changes from Mark R. Levinson <ml@cvdev.rochester.edu>. ** IRIX5 changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>. +** Adaptive changes from Kari E. Hurtta <Kari.Hurtta@fmi.fi>. */ -#if defined(IRIX64) || defined(IRIX5) -# define IRIX +#if defined(__sgi) +# ifndef IRIX +# define IRIX +# endif +# if _MIPS_SIM > 0 && !defined(IRIX5) +# define IRIX5 /* IRIX5 or IRIX6 */ +# endif +# if _MIPS_SIM > 1 && !defined(IRIX6) && !defined(IRIX64) +# define IRIX6 /* IRIX6 */ +# endif + #endif #ifdef IRIX @@ -254,18 +324,24 @@ extern void hard_syslog(int, char *, ...); # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define IP_SRCROUTE 1 /* can check IP source routing */ -# define FORK fork /* no vfork primitive available */ # define setpgid BSDsetpgrp # define GIDSET_T gid_t # define SFS_TYPE SFS_4ARGS /* four argument statfs() call */ # define SFS_BAVAIL f_bfree /* alternate field name */ -# define LA_TYPE LA_INT -# ifdef IRIX64 -# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */ +# ifdef IRIX6 +# define LA_TYPE LA_IRIX6 /* figure out at run time */ # else -# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */ +# define LA_TYPE LA_INT + +# ifdef IRIX64 +# define NAMELISTMASK 0x7fffffffffffffff /* mask for nlist() values */ +# else +# define NAMELISTMASK 0x7fffffff /* mask for nlist() values */ +# endif # endif -# if defined(IRIX64) || defined(IRIX5) +# if defined(IRIX64) || defined(IRIX5) +# include <sys/cdefs.h> +# include <paths.h> # define ARGV_T char *const * # define HASSETRLIMIT 1 /* has setrlimit(2) syscall */ # define HASGETDTABLESIZE 1 /* has getdtablesize(2) syscall */ @@ -290,10 +366,16 @@ extern void hard_syslog(int, char *, ...); # define HASGETUSERSHELL 1 /* DOES have getusershell(3) call in libc */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ # define IP_SRCROUTE 1 /* can check IP source routing */ -# define LA_TYPE LA_INT +# ifndef LA_TYPE +# define LA_TYPE LA_INT +# endif # ifdef SOLARIS_2_3 -# define SOLARIS 203 /* for back compat only -- use -DSOLARIS=203 */ +# define SOLARIS 20300 /* for back compat only -- use -DSOLARIS=20300 */ +# endif + +# if defined(NOT_SENDMAIL) && !defined(SOLARIS) && defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# define SOLARIS 1 /* unknown Solaris version */ # endif # ifdef SOLARIS @@ -303,6 +385,7 @@ extern void hard_syslog(int, char *, ...); # endif # include <sys/time.h> # define GIDSET_T gid_t +# define USE_SA_SIGACTION 1 /* use sa_sigaction field */ # ifndef _PATH_UNIX # define _PATH_UNIX "/dev/ksyms" # endif @@ -316,6 +399,20 @@ extern void hard_syslog(int, char *, ...); # ifndef SYSLOG_BUFSIZE # define SYSLOG_BUFSIZE 1024 /* allow full size syslog buffer */ # endif +# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) +# define USESETEUID 1 /* seteuid works as of 2.3 */ +# endif +# if SOLARIS >= 20500 || (SOLARIS < 10000 && SOLARIS >= 205) +# define HASSNPRINTF 1 /* has snprintf starting in 2.5 */ +# define HASSETREUID 1 /* setreuid works as of 2.5 */ +# if SOLARIS == 20500 || SOLARIS == 205 +# define snprintf __snprintf /* but names it oddly in 2.5 */ +# define vsnprintf __vsnprintf +# endif +# endif +# ifndef HASGETUSERSHELL +# define HASGETUSERSHELL 0 /* getusershell(3) causes core dumps */ +# endif # else /* SunOS 4.0.3 or 4.1.x */ @@ -432,8 +529,6 @@ extern long dgux_inet_addr(); #ifdef __ksr__ # define __osf__ 1 /* get OSF/1 defines below */ -# define FORK fork /* no vfork primitive available */ -# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf" # ifndef TZ_TYPE # define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ # endif @@ -449,12 +544,16 @@ extern long dgux_inet_addr(); #ifdef __PARAGON__ # define __osf__ 1 /* get OSF/1 defines below */ -# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf" +# ifndef TZ_TYPE +# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ +# endif #endif /* -** OSF/1 (tested on Alpha) +** OSF/1 (tested on Alpha) -- now known as Digital UNIX. +** +** Tested for 3.2 and 4.0. */ #ifdef __osf__ @@ -468,6 +567,7 @@ extern long dgux_inet_addr(); # endif # define LA_TYPE LA_INT # define SFS_TYPE SFS_MOUNT /* use <sys/mount.h> statfs() impl */ +# define _PATH_VENDOR_CF "/var/adm/sendmail/sendmail.cf" # ifndef _PATH_SENDMAILPID # define _PATH_SENDMAILPID "/var/run/sendmail.pid" # endif @@ -487,6 +587,7 @@ extern long dgux_inet_addr(); # define NEEDGETOPT 1 /* need a replacement for getopt(3) */ # define WAITUNION 1 /* use "union wait" as wait argument type */ # define UID_T int /* compiler gripes on uid_t */ +# define GID_T int /* ditto for gid_t */ # define sleep sleepX # define setpgid setpgrp # ifndef LA_TYPE @@ -512,6 +613,7 @@ typedef int pid_t; */ #if defined(BSD4_4) && !defined(__bsdi__) +# include <paths.h> # define HASUNSETENV 1 /* has unsetenv(3) call */ # define USESETEUID 1 /* has useable seteuid(2) call */ # define HASFCHMOD 1 /* has fchmod(2) syscall */ @@ -529,11 +631,12 @@ typedef int pid_t; /* -** BSD/386 (all versions) +** BSD/OS (was BSD/386) (all versions) ** From Tony Sanders, BSDI */ #ifdef __bsdi__ +# include <paths.h> # define HASUNSETENV 1 /* has the unsetenv(3) call */ # define HASSETSID 1 /* has the setsid(2) POSIX syscall */ # define USESETEUID 1 /* has useable seteuid(2) call */ @@ -592,25 +695,25 @@ typedef int pid_t; # if defined(__NetBSD__) && (NetBSD > 199307 || NetBSD0_9 > 1) # undef SPT_TYPE # define SPT_TYPE SPT_BUILTIN /* setproctitle is in libc */ -# define setreuid __setreuid # endif # if defined(__FreeBSD__) # undef SPT_TYPE # if __FreeBSD__ == 2 # include <osreldate.h> /* and this works */ # if __FreeBSD_version >= 199512 /* 2.2-current right now */ -# define SPT_TYPE SPT_BUILTIN # include <libutil.h> +# define SPT_TYPE SPT_BUILTIN # endif # endif # ifndef SPT_TYPE # define SPT_TYPE SPT_REUSEARGV -# define SPT_PADCHAR '\0' /* pad process title with nulls */ +# define SPT_PADCHAR '\0' /* pad process title with nulls */ # endif # endif #endif + /* ** Mach386 ** @@ -672,36 +775,63 @@ extern int errno; /* ** SCO Unix ** -** This includes two parts -- the first is for SCO Open Server 3.2v4 -** (contributed by Philippe Brand <phb@colombo.telesys-innov.fr>). -** The second is, I believe, for an older version. +** This includes three parts: +** +** The first is for SCO OpenServer 5. +** (Contributed by Keith Reynolds <keithr@sco.COM>). +** +** SCO OpenServer 5 has a compiler version number macro, +** which we can use to figure out what version we're on. +** This may have to change in future releases. +** +** The second is for SCO UNIX 3.2v4.2/Open Desktop 3.0. +** (Contributed by Philippe Brand <phb@colombo.telesys-innov.fr>). +** +** The third is for SCO UNIX 3.2v4.0/Open Desktop 2.0 and earlier. */ +#if _SCO_DS >= 1 +# include <paths.h> +# define _SCO_unix_4_2 +# define HASSNPRINTF 1 /* has snprintf() call */ +# define HASFCHMOD 1 /* has fchmod() call */ +# define HASSETRLIMIT 1 /* has setrlimit() call */ +# define RLIMIT_NEEDS_SYS_TIME_H 1 +#endif + + #ifdef _SCO_unix_4_2 # define _SCO_unix_ # define HASSETREUID 1 /* has setreuid(2) call */ -# define _PATH_UNIX "/unix" -# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf" -# ifndef _PATH_SENDMAILPID -# define _PATH_SENDMAILPID "/etc/sendmail.pid" -# endif #endif #ifdef _SCO_unix_ # include <sys/stream.h> /* needed for IP_SRCROUTE */ # define SYSTEM5 1 /* include all the System V defines */ -# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ -# define NOFTRUNCATE 0 /* does not have ftruncate(3) call */ -# define NEEDFSYNC 1 /* needs the fsync(2) call stub */ -# define FORK fork # define MAXPATHLEN PATHSIZE # define LA_TYPE LA_SHORT # define SFS_TYPE SFS_4ARGS /* use <sys/statfs.h> 4-arg impl */ # define SFS_BAVAIL f_bfree /* alternate field name */ # define SPT_TYPE SPT_SCO /* write kernel u. area */ # define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */ -# define NETUNIX 0 /* no unix domain socket support */ +# define _PATH_UNIX "/unix" +# define _PATH_VENDOR_CF "/usr/lib/sendmail.cf" +# ifndef _PATH_SENDMAILPID +# define _PATH_SENDMAILPID "/etc/sendmail.pid" +# endif + +/* stuff fixed in later releases */ +# ifndef _SCO_unix_4_2 +# define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ +# endif + +# ifndef _SCO_DS +# define NOFTRUNCATE 0 /* does not have ftruncate(3) call */ +# define NEEDFSYNC 1 /* needs the fsync(2) call stub */ +# define NETUNIX 0 /* no unix domain socket support */ +# endif + #endif @@ -721,7 +851,6 @@ extern int errno; # define HASSETREUID 1 /* has setreuid(2) call */ # define NEEDFSYNC 1 /* needs the fsync(2) call stub */ # define NETUNIX 0 /* no unix domain socket support */ -# define FORK fork # define MAXPATHLEN 1024 # define LA_TYPE LA_SHORT # define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ @@ -736,22 +865,24 @@ extern int errno; /* -** Altos System V. -** Contributed by Tim Rice <timr@crl.com>. +** Altos System V (5.3.1) +** Contributed by Tim Rice <tim@trr.metro.net>. */ -#ifdef ALTOS_SYS_V +#ifdef ALTOS_SYSTEM_V +# include <sys/stream.h> +# include <limits.h> # define SYSTEM5 1 /* include all the System V defines */ # define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define WAITUNION 1 /* use "union wait" as wait argument type */ # define NEEDFSYNC 1 /* no fsync(2) in system library */ -# define FORK fork -# define MAXPATHLEN PATHSIZE +# define NEEDSTRSTR 1 /* need emulation of the strstr(3) call */ +# define MAXPATHLEN PATH_MAX # define LA_TYPE LA_SHORT # define SFS_TYPE SFS_STATFS /* use <sys/statfs.h> statfs() impl */ # define SFS_BAVAIL f_bfree /* alternate field name */ -# define TZ_TYPE TZ_TM_NAME /* use tm->tm_name */ +# define TZ_TYPE TZ_TZNAME /* use tzname[] vector */ # define NETUNIX 0 /* no unix domain socket support */ # undef WIFEXITED # undef WEXITSTATUS @@ -760,6 +891,17 @@ extern int errno; typedef unsigned short uid_t; typedef unsigned short gid_t; typedef short pid_t; + +/* some stuff that should have been in the include files */ +# include <grp.h> +extern char *malloc(); +extern struct passwd *getpwent(); +extern struct passwd *getpwnam(); +extern struct passwd *getpwuid(); +extern char *getenv(); +extern struct group *getgrgid(); +extern struct group *getgrnam(); + #endif @@ -768,13 +910,26 @@ typedef short pid_t; ** ** "Todd C. Miller" <millert@mroe.cs.colorado.edu> claims this ** works on 9.1 as well. +** +** ConvexOS 11.5 and later, should work on 11.0 as defined. +** For pre-ConvexOOS 11.0, define NEEDGETOPT, undef IDENTPROTO +** +** Eric Schnoebelen (eric@cirr.com) For CONVEX Computer Corp. +** (now the CONVEX Technologies Center of Hewlett Packard) */ #ifdef _CONVEX_SOURCE -# define BSD 1 /* include all the BSD defines */ +# define HASGETDTABLESIZE 1 /* has getdtablesize(2) */ +# define HASINITGROUPS 1 /* has initgroups(3) */ # define HASUNAME 1 /* use System V uname(2) system call */ # define HASSETSID 1 /* has POSIX setsid(2) call */ -# define NEEDGETOPT 1 /* need replacement for getopt(3) */ +# define HASUNSETENV 1 /* has unsetenv(3) */ +# define HASFLOCK 1 /* has flock(2) */ +# define HASSETRLIMIT 1 /* has setrlimit(2) */ +# define HASSETREUID 1 /* has setreuid(2) */ +# define BROKEN_RES_SEARCH 1 /* res_search(unknown) returns h_error=0 */ +# define NEEDPUTENV 1 /* needs putenv (written in terms of setenv) */ +# define NEEDGETOPT 0 /* need replacement for getopt(3) */ # define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ # define LA_TYPE LA_FLOAT # define SFS_TYPE SFS_VFS /* use <sys/vfs.h> statfs() implementation */ @@ -787,8 +942,23 @@ typedef short pid_t; # define S_IFCHR _S_IFCHR # define S_IFBLK _S_IFBLK # endif +# ifndef TZ_TYPE +# define TZ_TYPE TZ_TIMEZONE +# endif # ifndef IDENTPROTO -# define IDENTPROTO 0 /* TCP/IP implementation is broken */ +# define IDENTPROTO 1 +# endif +# ifndef SHARE_V1 +# define SHARE_V1 1 /* version 1 of the fair share scheduler */ +# endif +# if !defined(__GNUC__ ) +# define UID_T int /* GNUC gets it right, ConvexC botches */ +# define GID_T int /* GNUC gets it right, ConvexC botches */ +# endif +# if SECUREWARE +# define FORK fork /* SecureWare wants the real fork! */ +# else +# define FORK vfork /* the rest of the OS versions don't care */ # endif #endif @@ -839,9 +1009,14 @@ extern void *malloc(); ** Florian La Roche <rzsfl@rz.uni-sb.de> ** Karl London <karl@borg.demon.co.uk> ** -** Last compiled against: [09/06/95 @ 10:20:58 AM (Wednesday)] -** sendmail 8.7-b14 named 4.9.3-beta17 db-1.85 -** gcc 2.7.0 libc-5.2.7 linux 1.2.13 +** Last compiled against: [06/10/96 @ 09:21:40 PM (Monday)] +** sendmail 8.8-a4 named bind-4.9.4-T4B db-1.85 +** gcc 2.7.2 libc-5.3.12 linux 2.0.0 +** +** NOTE: Override HASFLOCK as you will but, as of 1.99.6, mixed-style +** file locking is no longer allowed. In particular, make sure +** your DBM library and sendmail are both using either flock(2) +** *or* fcntl(2) file locking, but not both. */ #ifdef __linux__ @@ -857,7 +1032,12 @@ extern void *malloc(); # define HASGETUSERSHELL 0 /* getusershell(3) broken in Slackware 2.0 */ # define IP_SRCROUTE 0 /* linux <= 1.2.8 doesn't support IP_OPTIONS */ # ifndef HASFLOCK -# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */ +# include <linux/version.h> +# if LINUX_VERSION_CODE < 66399 +# define HASFLOCK 0 /* flock(2) is broken after 0.99.13 */ +# else +# define HASFLOCK 1 /* flock(2) fixed after 1.3.95 */ +# endif # endif # ifndef LA_TYPE # define LA_TYPE LA_PROCSTR @@ -907,7 +1087,6 @@ extern void *malloc(); # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif -# define FORK fork # ifndef LA_TYPE # define LA_TYPE LA_INT # define FSHIFT 16 @@ -937,7 +1116,6 @@ extern void *malloc(); # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # define SYS5SIGNALS 1 /* SysV signal semantics -- reset on each sig */ # define SYS5SETPGRP 1 /* use System V setpgrp(2) syscall */ -# define FORK fork /* no vfork(2) primitive available */ # define SFS_TYPE SFS_4ARGS /* four argument statfs() call */ # define MAXPATHLEN PATH_MAX extern struct passwd *getpwent(), *getpwnam(), *getpwuid(); @@ -1010,9 +1188,12 @@ typedef int pid_t; ** For DYNIX/ptx v1.x, undefine HASSETREUID. ** ** From Tim Wright <timw@sequent.com>. +** Update from Jack Woolley <jwoolley@sctcorp.com>, 26 Dec 1995, +** for DYNIX/ptx 4.0.2. */ #ifdef _SEQUENT_ +# include <sys/stream.h> # define SYSTEM5 1 /* include all the System V defines */ # define HASSETSID 1 /* has POSIX setsid(2) call */ # define HASINITGROUPS 1 /* has initgroups(3) call */ @@ -1076,6 +1257,7 @@ typedef int pid_t; # ifndef IDENTPROTO # define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif +# define RLIMIT_NEEDS_SYS_TIME_H 1 #endif @@ -1138,18 +1320,30 @@ typedef int pid_t; /* -** NCR 3000 Series (SysVr4) +** NCR MP-RAS 2.x (SysVr4) with Wollongong TCP/IP ** ** From Kevin Darcy <kevin@tech.mis.cfc.com>. */ -#ifdef NCR3000 +#ifdef NCR_MP_RAS2 # include <sys/sockio.h> # define __svr4__ # define IP_SRCROUTE 0 /* Something is broken with getsockopt() */ -# undef BSD -# define LA_AVENRUN "avenrun" # define SYSLOG_BUFSIZE 1024 +# define SPT_TYPE SPT_NONE +#endif + + +/* +** NCR MP-RAS 3.x (SysVr4) with STREAMware TCP/IP +** +** From Tom Moore <Tom.Moore@DaytonOH.NCR.COM> +*/ + +#ifdef NCR_MP_RAS3 +# define __svr4__ +# define SYSLOG_BUFSIZE 1024 +# define SPT_TYPE SPT_NONE #endif @@ -1372,20 +1566,75 @@ extern int errno; ** Fujitsu/ICL UXP/DS (For the DS/90 Series) ** ** From Diego R. Lopez <drlopez@cica.es>. +** Additional changes from Fumio Moriya and Toshiaki Nomura of the +** Fujitsu Fresoftware gruop <dsfrsoft@oai6.yk.fujitsu.co.jp>. */ -#ifdef UXPDS +#ifdef __uxp__ +# include <arpa/nameser.h> +# include <sys/sysmacros.h> +# include <sys/mkdev.h> # define __svr4__ -# define HASGETUSERSHELL 1 +# define HASGETUSERSHELL 0 # define HASFLOCK 0 +# if UXPDS == 10 +# define HASSNPRINTF 0 /* no snprintf(3) or vsnprintf(3) */ +# else +# define HASSNPRINTF 1 /* has snprintf(3) and vsnprintf(3) */ +# endif # define _PATH_UNIX "/stand/unix" -# define _PATH_VENDOR_CF "/etc/mail/sendmail.cf" +# define _PATH_VENDOR_CF "/usr/ucblib/sendmail.cf" # ifndef _PATH_SENDMAILPID -# define _PATH_SENDMAILPID "/etc/mail/sendmail.pid" +# define _PATH_SENDMAILPID "/usr/ucblib/sendmail.pid" +# endif +#endif + +/* +** Pyramid DC/OSx +** +** From Earle Ake <akee@wpdis01.wpafb.af.mil>. +*/ + +#ifdef DCOSx +# define GIDSET_T gid_t +# ifndef IDENTPROTO +# define IDENTPROTO 0 /* TCP/IP implementation is broken */ # endif #endif +/* +** Concurrent Computer Corporation Maxion +** +** From Donald R. Laster Jr. <laster@access.digex.net>. +*/ + +#ifdef __MAXION__ + +# include <sys/stream.h> +# define __svr4__ 1 /* SVR4.2MP */ +# define HASSETREUID 1 /* have setreuid(2) */ +# define HASLSTAT 1 /* have lstat(2) */ +# define HASSETRLIMIT 1 /* have setrlimit(2) */ +# define HASGETDTABLESIZE 1 /* have getdtablesize(2) */ +# define HASSNPRINTF 1 /* have snprintf(3) */ +# define HASGETUSERSHELL 1 /* have getusershell(3) */ +# define NOFTRUNCATE 1 /* do not have ftruncate(2) */ +# define SLEEP_T unsigned +# define SFS_TYPE SFS_STATVFS +# define SFS_BAVAIL f_bavail +# ifndef SYSLOG_BUFSIZE +# define SYSLOG_BUFSIZE 256 /* Use 256 bytes */ +# endif +# undef WUNTRACED +# undef WIFEXITED +# undef WIFSIGNALED +# undef WIFSTOPPED +# undef WEXITSTATUS +# undef WTERMSIG +# undef WSTOPSIG + +#endif /********************************************************************** ** End of Per-Operating System defines @@ -1418,13 +1667,16 @@ extern int errno; # define SYSTEM5 1 # define USESETEUID 1 /* has useable seteuid(2) call */ # define HASINITGROUPS 1 /* has initgroups(3) call */ -# define BSD_COMP 1 /* get BSD ioctl calls */ +# define BSD_COMP 1 /* get BSD ioctl calls */ # ifndef HASSETRLIMIT # define HASSETRLIMIT 1 /* has setrlimit(2) call */ # endif # ifndef HASGETUSERSHELL # define HASGETUSERSHELL 0 /* does not have getusershell(3) call */ # endif +# ifndef HASFCHMOD +# define HASFCHMOD 1 /* most (all?) SVr4s seem to have fchmod(2) */ +# endif # ifndef _PATH_UNIX # define _PATH_UNIX "/unix" @@ -1442,6 +1694,7 @@ extern int errno; # define SFS_TYPE SFS_STATVFS # endif +/* SVr4 uses different routines for setjmp/longjmp with signal support */ # define jmp_buf sigjmp_buf # define setjmp(env) sigsetjmp(env, 1) # define longjmp(env, val) siglongjmp(env, val) @@ -1499,7 +1752,7 @@ extern int errno; # undef bcopy /* despite SystemV claim, uses BSD bcopy */ #endif -#ifdef ALTOS_SYS_V +#ifdef ALTOS_SYSTEM_V # undef bcopy /* despite SystemV claim, uses BSD bcopy */ # undef bzero /* despite SystemV claim, uses BSD bzero */ # undef bcmp /* despite SystemV claim, uses BSD bcmp */ @@ -1561,6 +1814,10 @@ extern int errno; # define OLD_NEWDB 0 /* assume newer version of newdb */ #endif +#ifndef SECUREWARE +# define SECUREWARE 0 /* assume no SecureWare C2 auditing hooks */ +#endif + /* heuristic setting of HASSETSIGMASK; can override above */ #ifndef HASSIGSETMASK # ifdef SIGVTALRM @@ -1584,6 +1841,10 @@ extern int errno; # define UID_T uid_t #endif +#ifndef GID_T +# define GID_T gid_t +#endif + #ifndef SIZE_T # define SIZE_T size_t #endif @@ -1601,6 +1862,9 @@ extern int errno; #ifndef S_ISREG # define S_ISREG(foo) ((foo & S_IFMT) == S_IFREG) #endif +#ifndef S_ISDIR +# define S_ISDIR(foo) ((foo & S_IFMT) == S_IFDIR) +#endif #if !defined(S_ISLNK) && defined(S_IFLNK) # define S_ISLNK(foo) ((foo & S_IFMT) == S_IFLNK) #endif @@ -1729,7 +1993,7 @@ struct utsname }; #endif /* HASUNAME */ -#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYS_V) +#if !defined(MAXHOSTNAMELEN) && !defined(_SCO_unix_) && !defined(NonStop_UX_BXX) && !defined(ALTOS_SYSTEM_V) # define MAXHOSTNAMELEN 256 #endif @@ -1809,9 +2073,10 @@ typedef void (*sigfunc_t) __P((int)); */ # define PSBUFSIZE (MAXNAME + MAXATOM) /* size of prescan buffer */ + /* fork routine -- set above using #ifdef _osname_ or in Makefile */ # ifndef FORK -# define FORK vfork /* function to call to fork mailer */ +# define FORK fork /* function to call to fork mailer */ # endif /* diff --git a/usr.sbin/sendmail/src/daemon.c b/usr.sbin/sendmail/src/daemon.c index 9a11969..aead4ff 100644 --- a/usr.sbin/sendmail/src/daemon.c +++ b/usr.sbin/sendmail/src/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -37,9 +37,9 @@ #ifndef lint #ifdef DAEMON -static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (with daemon mode)"; +static char sccsid[] = "@(#)daemon.c 8.145 (Berkeley) 10/12/96 (with daemon mode)"; #else -static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemon mode)"; +static char sccsid[] = "@(#)daemon.c 8.145 (Berkeley) 10/12/96 (without daemon mode)"; #endif #endif /* not lint */ @@ -70,7 +70,7 @@ static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemo ** thing yourself, I recommend chucking the entire file ** and starting from scratch. Basic semantics are: ** -** getrequests() +** getrequests(e) ** Opens a port and initiates a connection. ** Returns in a child. Must set InChannel and ** OutChannel appropriately. @@ -80,7 +80,7 @@ static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemo ** etc., to avoid having extra file descriptors during ** the queue run and to avoid confusing the network ** code (if it cares). -** makeconnection(host, port, outfile, infile, usesecureport) +** makeconnection(host, port, outfile, infile, e) ** Make a connection to the named host on the given ** port. Set *outfile and *infile to the files ** appropriate for communication. Returns zero on @@ -93,10 +93,12 @@ static char sccsid[] = "@(#)daemon.c 8.119.1.2 (Berkeley) 9/16/96 (without daemo ** GETREQUESTS -- open mail IPC port and get requests. ** ** Parameters: -** none. +** e -- the current envelope. ** ** Returns: -** none. +** TRUE -- if a "null server" should be used -- that is, one +** that rejects all commands. +** FALSE -- to use a normal server. ** ** Side Effects: ** Waits until some interesting activity occurs. When @@ -113,8 +115,9 @@ int ListenQueueSize = 10; /* size of listen queue */ int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ int TcpSndBufferSize = 0; /* size of TCP send buffer */ -void -getrequests() +bool +getrequests(e) + ENVELOPE *e; { int t; bool refusingconnections = TRUE; @@ -124,6 +127,7 @@ getrequests() bool j_has_dot; #endif extern void reapchild(); + extern int opendaemonsocket __P((bool)); /* ** Set up the address for the mailer. @@ -166,7 +170,7 @@ getrequests() extern char *CommandLineArgs; /* write the process id on line 1 */ - fprintf(pidf, "%d\n", getpid()); + fprintf(pidf, "%ld\n", (long) getpid()); /* line 2 contains all command line flags */ fprintf(pidf, "%s\n", CommandLineArgs); @@ -179,7 +183,7 @@ getrequests() { char jbuf[MAXHOSTNAMELEN]; - expand("\201j", jbuf, sizeof jbuf, CurEnv); + expand("\201j", jbuf, sizeof jbuf, e); j_has_dot = strchr(jbuf, '.') != NULL; } #endif @@ -195,8 +199,7 @@ getrequests() extern int getla(); /* see if we are rejecting connections */ - CurrentLA = getla(); - if (refuseconnections()) + if (refuseconnections(ntohs(DaemonAddr.sin.sin_port))) { if (DaemonSocket >= 0) { @@ -220,8 +223,9 @@ getrequests() /* check for disaster */ { char jbuf[MAXHOSTNAMELEN]; + extern void dumpstate __P((char *)); - expand("\201j", jbuf, sizeof jbuf, CurEnv); + expand("\201j", jbuf, sizeof jbuf, e); if (!wordinclass(jbuf, 'w')) { dumpstate("daemon lost $j"); @@ -238,7 +242,8 @@ getrequests() #endif /* wait for a connection */ - setproctitle("accepting connections"); + setproctitle("accepting connections on port %d", + ntohs(DaemonAddr.sin.sin_port)); do { errno = 0; @@ -277,9 +282,9 @@ getrequests() if (pid == 0) { char *p; - extern char *hostnamebyanyaddr(); extern void intsig(); FILE *inchannel, *outchannel; + bool nullconn; /* ** CHILD -- return to caller. @@ -296,7 +301,7 @@ getrequests() /* determine host name */ p = hostnamebyanyaddr(&RealHostAddr); - if (strlen(p) > MAXNAME) + if (strlen(p) > (SIZE_T) MAXNAME) p[MAXNAME] = '\0'; RealHostName = newstr(p); setproctitle("startup with %s", p); @@ -313,7 +318,13 @@ getrequests() OutChannel = outchannel; DisConnected = FALSE; - /* should we check for illegal connection here? XXX */ + /* validate the connection */ + HoldErrs = TRUE; + nullconn = !validate_connection(&RealHostAddr, RealHostName, e); + HoldErrs = FALSE; + if (nullconn) + break; + #ifdef XLA if (!xla_host_ok(RealHostName)) { @@ -323,16 +334,19 @@ getrequests() #endif if (tTd(15, 2)) - printf("getreq: returning\n"); - return; + printf("getreq: returning (normal server)\n"); + return FALSE; } - CurChildren++; + /* parent -- keep track of children */ + proc_list_add(pid); /* close the port so that others will hang (for a while) */ (void) close(t); } - /*NOTREACHED*/ + if (tTd(15, 2)) + printf("getreq: returning (null server)\n"); + return TRUE; } /* ** OPENDAEMONSOCKET -- open the SMTP socket @@ -446,6 +460,7 @@ opendaemonsocket(firsttime) } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); finis(); + return -1; /* avoid compiler warning on IRIX */ } /* ** CLRDAEMON -- reset the daemon connection @@ -536,16 +551,16 @@ setdaemonoptions(p) #if NETINET case AF_INET: if (isascii(*v) && isdigit(*v)) - DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); + DaemonAddr.sin.sin_addr.s_addr = inet_addr(v); else { - register struct netent *np; + register struct hostent *hp; - np = getnetbyname(v); - if (np == NULL) - syserr("554 network \"%s\" unknown", v); + hp = sm_gethostbyname(v); + if (hp == NULL) + syserr("554 host \"%s\" unknown", v); else - DaemonAddr.sin.sin_addr.s_addr = np->n_net; + bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ); } break; #endif @@ -630,8 +645,7 @@ setdaemonoptions(p) ** port -- the port number to connect to. ** mci -- a pointer to the mail connection information ** structure to be filled in. -** usesecureport -- if set, use a low numbered (reserved) -** port to provide some rudimentary authentication. +** e -- the current envelope. ** ** Returns: ** An exit code telling whether the connection could be @@ -653,11 +667,11 @@ connecttimeout() SOCKADDR CurHostAddr; /* address of current host */ int -makeconnection(host, port, mci, usesecureport) +makeconnection(host, port, mci, e) char *host; u_short port; register MCI *mci; - bool usesecureport; + ENVELOPE *e; { register int i = 0; register int s; @@ -691,7 +705,7 @@ makeconnection(host, port, mci, usesecureport) *p = '\0'; #if NETINET hid = inet_addr(&host[1]); - if (hid == -1) + if (hid == INADDR_NONE) #endif { /* try it as a host name (avoid MX lookup) */ @@ -717,8 +731,11 @@ makeconnection(host, port, mci, usesecureport) } if (p == NULL) { + extern char MsgBuf[]; + usrerr("553 Invalid numeric domain spec \"%s\"", host); mci->mci_status = "5.1.2"; + mci->mci_rstatus = newstr(MsgBuf); return (EX_NOHOST); } #if NETINET @@ -728,22 +745,25 @@ makeconnection(host, port, mci, usesecureport) } else { - register char *p = &host[strlen(host) - 1]; - - hp = sm_gethostbyname(host); - if (hp == NULL && *p == '.') + /* contortion to get around SGI cc complaints */ { + register char *p = &host[strlen(host) - 1]; + + hp = sm_gethostbyname(host); + if (hp == NULL && *p == '.') + { #if NAMED_BIND - int oldopts = _res.options; + int oldopts = _res.options; - _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); + _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); #endif - *p = '\0'; - hp = sm_gethostbyname(host); - *p = '.'; + *p = '\0'; + hp = sm_gethostbyname(host); + *p = '.'; #if NAMED_BIND - _res.options = oldopts; + _res.options = oldopts; #endif + } } gothostent: if (hp == NULL) @@ -754,6 +774,7 @@ gothostent: (errno == ECONNREFUSED && UseNameServer)) { mci->mci_status = "4.4.3"; + mci->mci_rstatus = NULL; return (EX_TEMPFAIL); } #endif @@ -841,7 +862,7 @@ gothostent: /* save for logging */ CurHostAddr = addr; - if (usesecureport) + if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags)) { int rport = IPPORT_RESERVED - 1; @@ -878,8 +899,8 @@ gothostent: (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); } - if (CurEnv->e_xfp != NULL) - (void) fflush(CurEnv->e_xfp); /* for debugging */ + if (e->e_xfp != NULL) + (void) fflush(e->e_xfp); /* for debugging */ errno = 0; /* for debugging */ /* @@ -889,10 +910,12 @@ gothostent: if (setjmp(CtxConnectTimeout) == 0) { - if (TimeOuts.to_connect == 0) - ev = NULL; - else + if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0) + ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0); + else if (TimeOuts.to_connect != 0) ev = setevent(TimeOuts.to_connect, connecttimeout, 0); + else + ev = NULL; if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) { if (ev != NULL) @@ -986,7 +1009,6 @@ myhostname(hostbuf, size) int size; { register struct hostent *hp; - extern bool getcanonname(); if (gethostname(hostbuf, size) < 0) { @@ -1087,7 +1109,6 @@ getauthinfo(fd) int nleft; char ibuf[MAXNAME + 1]; static char hbuf[MAXNAME * 2 + 2]; - extern char *hostnamebyanyaddr(); falen = sizeof RealHostAddr; if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || @@ -1104,6 +1125,8 @@ getauthinfo(fd) { /* translate that to a host name */ RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); + if (strlen(RealHostName) > MAXNAME) + RealHostName[MAXNAME - 1] = '\0'; } if (TimeOuts.to_ident == 0) @@ -1170,6 +1193,9 @@ getauthinfo(fd) { p += i; nleft -= i; + *p = '\0'; + if (strchr(ibuf, '\n') != NULL) + break; } (void) close(s); clrevent(ev); @@ -1207,14 +1233,6 @@ getauthinfo(fd) } /* p now points to the OSTYPE field */ - while (isascii(*p) && isspace(*p)) - p++; - if (strncasecmp(p, "other", 5) == 0 && - (p[5] == ':' || p[5] == ' ' || p[5] == ',' || p[5] == '\0')) - { - /* not useful information */ - goto noident; - } p = strchr(p, ':'); if (p == NULL) { @@ -1432,25 +1450,28 @@ host_map_lookup(map, name, av, statp) if (*name != '[') { - extern bool getcanonname(); - if (tTd(9, 1)) printf("host_map_lookup(%s) => ", name); s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ - if (strlen(name) < sizeof hbuf) snprintf(hbuf, sizeof hbuf, "%s", name); if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX)) { if (tTd(9, 1)) printf("%s\n", hbuf); - cp = map_rewrite(map, hbuf, strlen(hbuf), av); - s->s_namecanon.nc_cname = newstr(cp); + if (bitset(MF_MATCHONLY, map->map_mflags)) + { + cp = map_rewrite(map, name, strlen(name), av); + s->s_namecanon.nc_cname = newstr(hbuf); + } + else + { + cp = map_rewrite(map, hbuf, strlen(hbuf), av); + s->s_namecanon.nc_cname = newstr(cp); + } return cp; } else { - register struct hostent *hp; - s->s_namecanon.nc_errno = errno; #if NAMED_BIND s->s_namecanon.nc_herrno = h_errno; diff --git a/usr.sbin/sendmail/src/deliver.c b/usr.sbin/sendmail/src/deliver.c index 34c6c1a..f446f53 100644 --- a/usr.sbin/sendmail/src/deliver.c +++ b/usr.sbin/sendmail/src/deliver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)deliver.c 8.185.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)deliver.c 8.246 (Berkeley) 10/17/96"; #endif /* not lint */ #include "sendmail.h" @@ -69,7 +69,7 @@ extern char SmtpError[]; void sendall(e, mode) ENVELOPE *e; - char mode; + int mode; { register ADDRESS *q; char *owner; @@ -125,6 +125,8 @@ sendall(e, mode) */ CurEnv = e; + if (tTd(62, 1)) + checkfds(NULL); if (e->e_hopcount > MaxHopCount) { @@ -184,12 +186,21 @@ sendall(e, mode) q->q_owner = NULL; } + if (tTd(13, 25)) + { + printf("\nAfter first owner pass, sendq =\n"); + printaddr(e->e_sendqueue, TRUE); + } + owner = ""; otherowners = 1; while (owner != NULL && otherowners > 0) { + if (tTd(13, 28)) + printf("owner = \"%s\", otherowners = %d\n", + owner, otherowners); owner = NULL; - otherowners = 0; + otherowners = bitset(EF_SENDRECEIPT, e->e_flags) ? 1 : 0; for (q = e->e_sendqueue; q != NULL; q = q->q_next) { @@ -204,27 +215,49 @@ sendall(e, mode) printf(" ... QDONTSEND\n"); continue; } + if (tTd(13, 29) && !tTd(13, 30)) + { + printf("Checking "); + printaddr(q, FALSE); + } if (q->q_owner != NULL) { if (owner == NULL) + { + if (tTd(13, 40)) + printf(" ... First owner = \"%s\"\n", + q->q_owner); owner = q->q_owner; + } else if (owner != q->q_owner) { if (strcmp(owner, q->q_owner) == 0) { + if (tTd(13, 40)) + printf(" ... Same owner = \"%s\"\n", + owner); + /* make future comparisons cheap */ q->q_owner = owner; } else { + if (tTd(13, 40)) + printf(" ... Another owner \"%s\"\n", + q->q_owner); otherowners++; } owner = q->q_owner; } + else if (tTd(13, 40)) + printf(" ... Same owner = \"%s\"\n", + owner); } else { + if (tTd(13, 40)) + printf(" ... Null owner\n"); otherowners++; } @@ -273,8 +306,8 @@ sendall(e, mode) (void) queuename(ee, '\0'); if (tTd(13, 1)) - printf("sendall: split %s into %s\n", - e->e_id, ee->e_id); + printf("sendall: split %s into %s, owner = \"%s\", otherowners = %d\n", + e->e_id, ee->e_id, owner, otherowners); ee->e_header = copyheader(e->e_header); ee->e_sendqueue = copyqueue(e->e_sendqueue); @@ -299,7 +332,10 @@ sendall(e, mode) if (q->q_owner == owner) { q->q_flags |= QDONTSEND; - q->q_flags &= ~QQUEUEUP; + q->q_flags &= ~(QQUEUEUP|QBADADDR); + if (tTd(13, 6)) + printf("\t... stripping %s from original envelope\n", + q->q_paddr); } } for (q = ee->e_sendqueue; q != NULL; q = q->q_next) @@ -307,13 +343,19 @@ sendall(e, mode) if (q->q_owner != owner) { q->q_flags |= QDONTSEND; - q->q_flags &= ~QQUEUEUP; + q->q_flags &= ~(QQUEUEUP|QBADADDR); + if (tTd(13, 6)) + printf("\t... dropping %s from cloned envelope\n", + q->q_paddr); } else { /* clear DSN parameters */ - q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); - q->q_flags |= QPINGONFAILURE|QPINGONDELAY; + q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); + q->q_flags |= DefaultNotify & ~QPINGONSUCCESS; + if (tTd(13, 6)) + printf("\t... moving %s to cloned envelope\n", + q->q_paddr); } } @@ -368,6 +410,7 @@ sendall(e, mode) e->e_from.q_flags |= QDONTSEND; e->e_errormode = EM_MAIL; e->e_flags |= EF_NORECEIPT; + e->e_flags &= ~EF_FATALERRS; } /* if nothing to be delivered, just queue up everything */ @@ -382,7 +425,7 @@ sendall(e, mode) # ifdef QUEUE if ((mode == SM_QUEUE || mode == SM_DEFER || mode == SM_FORK || (mode != SM_VERIFY && SuperSafe)) && - !bitset(EF_INQUEUE, e->e_flags)) + (!bitset(EF_INQUEUE, e->e_flags) || splitenv != NULL)) { /* be sure everything is instantiated in the queue */ queueup(e, mode == SM_QUEUE || mode == SM_DEFER); @@ -391,12 +434,31 @@ sendall(e, mode) } #endif /* QUEUE */ + if (tTd(62, 10)) + checkfds("after envelope splitting"); + /* ** If we belong in background, fork now. */ if (tTd(13, 20)) + { printf("sendall: final mode = %c\n", mode); + if (tTd(13, 21)) + { + printf("\n================ Final Send Queue(s) =====================\n"); + printf("\n *** Envelope %s, e_from=%s ***\n", + e->e_id, e->e_from.q_paddr); + printaddr(e->e_sendqueue, TRUE); + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + printf("\n *** Envelope %s, e_from=%s ***\n", + ee->e_id, ee->e_from.q_paddr); + printaddr(ee->e_sendqueue, TRUE); + } + printf("==========================================================\n\n"); + } + } switch (mode) { case SM_VERIFY: @@ -428,15 +490,26 @@ sendall(e, mode) /* now drop the envelope in the parent */ e->e_flags |= EF_INQUEUE; - dropenvelope(e); + dropenvelope(e, FALSE); - /* and reacquire in the child */ - (void) dowork(qid, TRUE, FALSE, e); + /* arrange to reacquire lock after fork */ + e->e_id = qid; } - return; + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + /* save id for future use */ + char *qid = ee->e_id; + + /* drop envelope in parent */ + ee->e_flags |= EF_INQUEUE; + dropenvelope(ee, FALSE); + + /* and save qid for reacquisition */ + ee->e_id = qid; + } -# else /* HASFLOCK */ +# endif /* !HASFLOCK */ pid = fork(); if (pid < 0) @@ -445,6 +518,7 @@ sendall(e, mode) } else if (pid > 0) { +# if HASFLOCK /* be sure we leave the temp files to our child */ /* can't call unlockqueue to avoid unlink of xfp */ if (e->e_lockfp != NULL) @@ -456,8 +530,11 @@ sendall(e, mode) if (e->e_dfp != NULL) (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); e->e_dfp = NULL; - e->e_id = NULL; e->e_flags &= ~EF_HAS_DF; +# endif + + /* make sure the parent doesn't own the envelope */ + e->e_id = NULL; /* catch intermediate zombie */ (void) waitfor(pid); @@ -491,31 +568,33 @@ sendall(e, mode) mci_flush(FALSE, NULL); -# endif /* HASFLOCK */ - +# if HASFLOCK break; - } - - if (splitenv != NULL) - { - if (tTd(13, 2)) - { - printf("\nsendall: Split queue; remaining queue:\n"); - printaddr(e->e_sendqueue, TRUE); - } +# else - for (ee = splitenv; ee != NULL; ee = ee->e_sibling) - { - CurEnv = ee; - if (mode != SM_VERIFY) - openxscript(ee); - sendenvelope(ee, mode); - dropenvelope(ee); - } + /* + ** Now reacquire and run the various queue files. + */ - CurEnv = e; + for (ee = splitenv; ee != NULL; ee = e->e_sibling) + (void) dowork(ee->e_id, FALSE, FALSE, ee); + (void) dowork(e->e_id, FALSE, FALSE, e); + finis(); +# endif /* !HASFLOCK */ } + sendenvelope(e, mode); + dropenvelope(e, TRUE); + for (ee = splitenv; ee != NULL; ee = ee->e_sibling) + { + CurEnv = ee; + if (mode != SM_VERIFY) + openxscript(ee); + sendenvelope(ee, mode); + dropenvelope(ee, TRUE); + } + CurEnv = e; + Verbose = oldverbose; if (mode == SM_FORK) finis(); @@ -563,6 +642,8 @@ sendenvelope(e, mode) e->e_nsent = 0; e->e_flags |= EF_GLOBALERRS; + define(macid("{envid}", NULL), e->e_envid, e); + define(macid("{bodytype}", NULL), e->e_bodytype, e); didany = FALSE; /* now run through the queue */ @@ -593,6 +674,8 @@ sendenvelope(e, mode) } else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) { + extern int deliver __P((ENVELOPE *, ADDRESS *)); + # ifdef QUEUE /* ** Checkpoint the send list every few addresses @@ -704,6 +787,13 @@ dofork() ** The standard input is passed off to someone. */ +#ifndef NO_UID +# define NO_UID ((uid_t) -1) +#endif +#ifndef NO_GID +# define NO_GID ((gid_t) -1) +#endif + int deliver(e, firstto) register ENVELOPE *e; @@ -716,6 +806,7 @@ deliver(e, firstto) register char *p; register MAILER *m; /* mailer for this recipient */ ADDRESS *volatile ctladdr; + ADDRESS *volatile contextaddr = NULL; register MCI *volatile mci; register ADDRESS *to = firstto; volatile bool clever = FALSE; /* running user smtp to this mailer */ @@ -724,7 +815,9 @@ deliver(e, firstto) char *firstsig; /* signature of firstto */ int pid = -1; char *volatile curhost; + register volatile u_short port = 0; time_t xstart; + bool suidwarn; int mpvect[2]; int rpvect[2]; char *pv[MAXPV+1]; @@ -738,6 +831,8 @@ deliver(e, firstto) if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) return (0); + suidwarn = geteuid() == 0; + #if NAMED_BIND /* unless interactive, try twice, over a minute */ if (OpMode == MD_DAEMON || OpMode == MD_SMTP) @@ -888,7 +983,7 @@ deliver(e, firstto) /* compute effective uid/gid when sending */ if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) - ctladdr = getctladdr(to); + contextaddr = ctladdr = getctladdr(to); if (tTd(10, 2)) { @@ -921,7 +1016,15 @@ deliver(e, firstto) #if NAMED_BIND h_errno = 0; #endif - rcode = checkcompat(to, e); + + /* do config file checking of compatibility */ + rcode = rscheck("check_compat", + e->e_from.q_paddr, to->q_paddr, e); + if (rcode == EX_OK) + { + /* do in-code checking */ + rcode = checkcompat(to, e); + } if (rcode != EX_OK) { markfailure(e, to, NULL, rcode); @@ -956,9 +1059,6 @@ deliver(e, firstto) if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) continue; - /* save statistics.... */ - markstats(e, to); - /* ** See if this user name is "special". ** If the user name has a slash in it, assume that this @@ -975,9 +1075,9 @@ deliver(e, firstto) if (rcode == EX_OK) { to->q_flags |= QSENT; + markstats(e, to); if (bitnset(M_LOCALMAILER, m->m_flags) && - (e->e_receiptto != NULL || - bitset(QPINGONSUCCESS, to->q_flags))) + bitset(QPINGONSUCCESS, to->q_flags)) { to->q_flags |= QDELIVERED; to->q_status = "2.1.5"; @@ -1114,6 +1214,9 @@ deliver(e, firstto) goto give_up; } + if (tTd(62, 8)) + checkfds("before delivery"); + /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { @@ -1129,7 +1232,6 @@ deliver(e, firstto) { #ifdef DAEMON register int i; - register volatile u_short port = 0; if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') { @@ -1172,11 +1274,12 @@ tryhost: { register char *p; static char hostbuf[MAXNAME + 1]; + extern int makeconnection __P((char *, u_short, MCI *, ENVELOPE *)); /* pull the next host from the signature */ p = strchr(curhost, ':'); if (p == NULL) - p = &curhost[strlen(curhost)]; + p = (char *) &curhost[strlen(curhost)]; if (p == curhost) { syserr("deliver: null host name in signature"); @@ -1209,12 +1312,21 @@ tryhost: if (mci->mci_exitstat != EX_OK) continue; + if (mci_lock_host(mci) != EX_OK) + { + mci->mci_exitstat = EX_TEMPFAIL; + continue; + } + /* try the connection */ setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); - message("Connecting to %s via %s...", - hostbuf, m->m_name); - i = makeconnection(hostbuf, port, mci, - bitnset(M_SECURE_PORT, m->m_flags)); + if (port == 0) + message("Connecting to %s via %s...", + hostbuf, m->m_name); + else + message("Connecting to %s port %d via %s...", + hostbuf, port, m->m_name); + i = makeconnection(hostbuf, port, mci, e); mci->mci_lastuse = curtime(); mci->mci_exitstat = i; mci->mci_errno = errno; @@ -1226,13 +1338,17 @@ tryhost: mci->mci_state = MCIS_OPENING; mci_cache(mci); if (TrafficLogFile != NULL) - fprintf(TrafficLogFile, "%05d == CONNECT %s\n", + fprintf(TrafficLogFile, "%05d === CONNECT %s\n", getpid(), hostbuf); break; } - else if (tTd(11, 1)) - printf("openmailer: makeconnection => stat=%d, errno=%d\n", - i, errno); + else + { + if (tTd(11, 1)) + printf("openmailer: makeconnection => stat=%d, errno=%d\n", + i, errno); + mci_unlock_host(mci); + } /* enter status of this host */ setstat(i); @@ -1242,7 +1358,7 @@ tryhost: if (mci == NULL) { syserr("deliver: no host name"); - rcode = EX_OSERR; + rcode = EX_SOFTWARE; goto give_up; } mci->mci_pid = 0; @@ -1274,6 +1390,10 @@ tryhost: fprintf(TrafficLogFile, "\n"); } +#if XDEBUG + checkfd012("before creating mail pipe"); +#endif + /* create a pipe to shove the mail through */ if (pipe(mpvect) < 0) { @@ -1285,19 +1405,59 @@ tryhost: goto give_up; } - /* if this mailer speaks smtp, create a return pipe */ -#ifdef SMTP - if (clever && pipe(rpvect) < 0) +#if XDEBUG + /* make sure we didn't get one of the standard I/O files */ + if (mpvect[0] < 3 || mpvect[1] < 3) { - syserr("%s... openmailer(%s): pipe (from mailer)", - shortenstring(e->e_to, 203), m->m_name); - (void) close(mpvect[0]); - (void) close(mpvect[1]); + syserr("%s... openmailer(%s): bogus mpvect %d %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1]); + printopenfds(TRUE); if (tTd(11, 1)) printf("openmailer: NULL\n"); rcode = EX_OSERR; goto give_up; } + + /* make sure system call isn't dead meat */ + checkfdopen(mpvect[0], "mpvect[0]"); + checkfdopen(mpvect[1], "mpvect[1]"); + if (mpvect[0] == mpvect[1] || + (e->e_lockfp != NULL && + (mpvect[0] == fileno(e->e_lockfp) || + mpvect[1] == fileno(e->e_lockfp)))) + { + if (e->e_lockfp == NULL) + syserr("%s... openmailer(%s): overlapping mpvect %d %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1]); + else + syserr("%s... openmailer(%s): overlapping mpvect %d %d, lockfp = %d", + shortenstring(e->e_to, 203), m->m_name, + mpvect[0], mpvect[1], fileno(e->e_lockfp)); + } +#endif + + /* if this mailer speaks smtp, create a return pipe */ +#ifdef SMTP + if (clever) + { + if (pipe(rpvect) < 0) + { + syserr("%s... openmailer(%s): pipe (from mailer)", + shortenstring(e->e_to, 203), m->m_name); + (void) close(mpvect[0]); + (void) close(mpvect[1]); + if (tTd(11, 1)) + printf("openmailer: NULL\n"); + rcode = EX_OSERR; + goto give_up; + } +# if XDEBUG + checkfdopen(rpvect[0], "rpvect[0]"); + checkfdopen(rpvect[1], "rpvect[1]"); +# endif + } #endif /* @@ -1339,6 +1499,9 @@ tryhost: { int i; int saveerrno; + uid_t new_euid = NO_UID; + uid_t new_ruid = NO_UID; + gid_t new_gid = NO_GID; struct stat stb; extern int DtableSize; @@ -1353,58 +1516,96 @@ tryhost: if (m != FileMailer || stat(tochain->q_user, &stb) < 0) stb.st_mode = 0; +#if HASSETUSERCONTEXT + /* + ** Set user resources. + */ + + if (contextaddr != NULL) + { + struct passwd *pwd; + + if (contextaddr->q_ruser != NULL) + pwd = sm_getpwnam(contextaddr->q_ruser); + else + pwd = sm_getpwnam(contextaddr->q_user); + if (pwd != NULL) + (void) setusercontext(NULL, + pwd, pwd->m_uid, + LOGIN_SETRESOURCES|LOGIN_SETPRIORITY); + } +#endif + /* tweak niceness */ if (m->m_nice != 0) nice(m->m_nice); /* reset group id */ if (bitnset(M_SPECIFIC_UID, m->m_flags)) - (void) setgid(m->m_gid); + new_gid = m->m_gid; else if (bitset(S_ISGID, stb.st_mode)) - (void) setgid(stb.st_gid); + new_gid = stb.st_gid; else if (ctladdr != NULL && ctladdr->q_gid != 0) { if (!DontInitGroups) (void) initgroups(ctladdr->q_ruser != NULL ? ctladdr->q_ruser : ctladdr->q_user, ctladdr->q_gid); - (void) setgid(ctladdr->q_gid); + new_gid = ctladdr->q_gid; } else { if (!DontInitGroups) (void) initgroups(DefUser, DefGid); if (m->m_gid == 0) - (void) setgid(DefGid); + new_gid = DefGid; else - (void) setgid(m->m_gid); + new_gid = m->m_gid; } + if (new_gid != NO_GID && setgid(new_gid) < 0 && suidwarn) + syserr("openmailer: setgid(%ld) failed", + (long) new_gid); /* reset user id */ endpwent(); if (bitnset(M_SPECIFIC_UID, m->m_flags)) + new_euid = m->m_uid; + if (bitset(S_ISUID, stb.st_mode)) + new_ruid = stb.st_uid; + else if (ctladdr != NULL && ctladdr->q_uid != 0) + new_ruid = ctladdr->q_uid; + else { + if (m->m_uid == 0) + new_ruid = DefUid; + else + new_ruid = m->m_uid; + } + if (new_euid != NO_UID) + { + vendor_set_uid(new_euid); #if USESETEUID - (void) seteuid(m->m_uid); + if (seteuid(new_euid) < 0 && suidwarn) + syserr("openmailer: seteuid(%ld) failed", + (long) new_euid); #else # if HASSETREUID - (void) setreuid(-1, m->m_uid); + if (setreuid(new_ruid, new_euid) < 0 && suidwarn) + syserr("openmailer: setreuid(%ld, %ld) failed", + (long) new_ruid, (long) new_euid); # else - if (m->m_uid != geteuid()) - (void) setuid(m->m_uid); + if (new_euid != geteuid() && setuid(new_euid) < 0 && suidwarn) + syserr("openmailer: setuid(%ld) failed", + (long) new_euid); # endif #endif } - else if (bitset(S_ISUID, stb.st_mode)) - (void) setuid(stb.st_uid); - else if (ctladdr != NULL && ctladdr->q_uid != 0) - (void) setuid(ctladdr->q_uid); - else + else if (new_ruid != NO_UID) { - if (m->m_uid == 0) - (void) setuid(DefUid); - else - (void) setuid(m->m_uid); + vendor_set_uid(new_ruid); + if (setuid(new_ruid) < 0 && suidwarn) + syserr("openmailer: setuid(%ld) failed", + (long) new_ruid); } if (tTd(11, 2)) @@ -1559,7 +1760,11 @@ tryhost: mci->mci_flags |= MCIF_7BIT; #ifdef SMTP if (clever && mci->mci_state != MCIS_CLOSED) + { + extern void smtpinit __P((MAILER *, MCI *, ENVELOPE *)); + smtpinit(m, mci, e); + } #endif if (bitset(EF_HAS8BIT, e->e_flags) && @@ -1569,6 +1774,22 @@ tryhost: else mci->mci_flags &= ~MCIF_CVT8TO7; +#if MIME7TO8 + if (bitnset(M_MAKE8BIT, m->m_flags) && + !bitset(MCIF_7BIT, mci->mci_flags) && + (p = hvalue("Content-Transfer-Encoding", e->e_header)) != NULL && + (strcasecmp(p, "quoted-printable") == 0 || + strcasecmp(p, "base64") == 0) && + (p = hvalue("Content-Type", e->e_header)) != NULL) + { + /* may want to convert 7 -> 8 */ + /* XXX should really parse it here -- and use a class XXX */ + if (strncasecmp(p, "text/plain", 10) == 0 && + (p[10] == '\0' || p[10] == ' ' || p[10] == ';')) + mci->mci_flags |= MCIF_CVT7TO8; + } +#endif + if (tTd(11, 1)) { printf("openmailer: "); @@ -1586,8 +1807,10 @@ tryhost: if (rcode == EX_OK) { /* shouldn't happen */ - syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", - rcode, mci->mci_state, firstsig); + syserr("554 deliver: mci=%lx rcode=%d errno=%d state=%d sig=%s", + (long) mci, rcode, errno, mci->mci_state, + firstsig); + mci_dump_all(TRUE); rcode = EX_SOFTWARE; } #ifdef DAEMON @@ -1614,6 +1837,10 @@ tryhost: else #ifdef SMTP { + extern int smtpmailfrom __P((MAILER *, MCI *, ENVELOPE *)); + extern int smtprcpt __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *)); + extern int smtpdata __P((MAILER *, MCI *, ENVELOPE *)); + /* ** Send the MAIL FROM: protocol */ @@ -1661,7 +1888,7 @@ tryhost: if (!bitset(MCIF_CACHED, mci->mci_flags)) smtpquit(m, mci, e); } - if (rcode != EX_OK && curhost != NULL && *curhost != '\0') + if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0') { /* try next MX site */ goto tryhost; @@ -1679,13 +1906,8 @@ tryhost: _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ #endif - /* arrange a return receipt if requested */ - if (rcode == EX_OK && e->e_receiptto != NULL && - bitnset(M_LOCALMAILER, m->m_flags)) - { - e->e_flags |= EF_SENDRECEIPT; - /* do we want to send back more info? */ - } + if (tTd(62, 1)) + checkfds("after delivery"); /* ** Do final status disposal. @@ -1697,6 +1919,10 @@ tryhost: give_up: if (tobuf[0] != '\0') giveresponse(rcode, m, mci, ctladdr, xstart, e); + if (rcode == EX_OK) + markstats(e, tochain); + mci_store_persistent(mci); + for (to = tochain; to != NULL; to = to->q_tchain) { /* see if address already marked */ @@ -1715,8 +1941,7 @@ tryhost: to->q_statdate = curtime(); e->e_nsent++; if (bitnset(M_LOCALMAILER, m->m_flags) && - (e->e_receiptto != NULL || - bitset(QPINGONSUCCESS, to->q_flags))) + bitset(QPINGONSUCCESS, to->q_flags)) { to->q_flags |= QDELIVERED; to->q_status = "2.1.5"; @@ -1798,11 +2023,17 @@ markfailure(e, q, mci, rcode) } /* find most specific error code possible */ - if (q->q_status == NULL && mci != NULL) + if (mci != NULL && mci->mci_status != NULL) + { q->q_status = mci->mci_status; - if (q->q_status == NULL) + q->q_rstatus = mci->mci_rstatus; + } + else if (e->e_status != NULL) + { q->q_status = e->e_status; - if (q->q_status == NULL) + q->q_rstatus = NULL; + } + else { switch (rcode) { @@ -1903,6 +2134,10 @@ endmailer(mci, e, pv) if (mci->mci_pid == 0) return (EX_OK); +#ifdef FFR_TIMEOUT_WAIT + put a timeout around the wait +#endif + /* wait for the mailer process to die and collect status */ st = waitfor(mci->mci_pid); if (st == -1) @@ -2219,7 +2454,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) bp += strlen(bp); (void) strcpy(bp, shortenstring(stat, (STATLEN))); - + /* id, to: max 13 + TOBUFSIZE bytes */ l = SYSLOG_BUFSIZE - 100 - strlen(buf); p = e->e_to; @@ -2239,7 +2474,7 @@ logdelivery(m, mci, stat, ctladdr, xstart, e) l = SYSLOG_BUFSIZE - 85; p = e->e_to; - while (strlen(p) >= l) + while (strlen(p) >= (SIZE_T) l) { register char *q = strchr(p + l, ','); @@ -2342,6 +2577,7 @@ putfromline(mci, e) { char *template = UnixFromLine; char buf[MAXLINE]; + char xbuf[MAXLINE]; if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) return; @@ -2349,14 +2585,29 @@ putfromline(mci, e) if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) { char *bang; - char xbuf[MAXLINE]; expand("\201g", buf, sizeof buf, e); bang = strchr(buf, '!'); if (bang == NULL) { - errno = 0; - syserr("554 No ! in UUCP From address! (%s given)", buf); + char *at; + char hname[MAXNAME]; + + /* + ** If we can construct a UUCP path, do so + */ + + at = strrchr(buf, '@'); + if (at == NULL) + { + expand( "\201k", hname, sizeof hname, e); + at = hname; + } + else + *at++ = '\0'; + (void) snprintf(xbuf, sizeof xbuf, + "From %.800s \201d remote from %.100s\n", + buf, at); } else { @@ -2461,6 +2712,12 @@ putbody(mci, e, separator) boundaries[0] = NULL; mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); } +# if MIME7TO8 + else if (bitset(MCIF_CVT7TO8, mci->mci_flags)) + { + mime7to8(mci, e->e_header, e); + } +# endif else #endif { @@ -2593,6 +2850,7 @@ putbody(mci, e, separator) /* had a naked carriage return */ *pbp++ = c; c = '\r'; + ostate = OS_INLINE; goto putch; case OS_INLINE: @@ -2631,8 +2889,10 @@ putch: { *bp = '\0'; fputs(buf, mci->mci_out); - fputs(mci->mci_mailer->m_eol, mci->mci_out); + pos += bp - buf; } + if (pos > 0) + fputs(mci->mci_mailer->m_eol, mci->mci_out); } if (ferror(e->e_dfp)) @@ -2693,6 +2953,7 @@ mailfile(filename, ctladdr, sfflags, e) register FILE *f; register int pid = -1; int mode; + bool suidwarn = geteuid() == 0; if (tTd(11, 1)) { @@ -2704,6 +2965,14 @@ mailfile(filename, ctladdr, sfflags, e) fflush(e->e_xfp); /* + ** Special case /dev/null. This allows us to restrict file + ** delivery to regular files only. + */ + + if (strcmp(filename, "/dev/null") == 0) + return EX_OK; + + /* ** Fork so we can change permissions here. ** Note that we MUST use fork, not vfork, because of ** the complications of calling subroutines, etc. @@ -2717,7 +2986,6 @@ mailfile(filename, ctladdr, sfflags, e) { /* child -- actually write to file */ struct stat stb; - struct stat fsb; MCI mcibuf; int oflags = O_WRONLY|O_APPEND; @@ -2816,12 +3084,9 @@ mailfile(filename, ctladdr, sfflags, e) RealGid = DefGid; } - /* now set the group and user ids */ - endpwent(); + /* set group id list (needs /etc/group access) */ if (RealUserName != NULL && !DontInitGroups) (void) initgroups(RealUserName, RealGid); - (void) setgid(RealGid); - (void) setuid(RealUid); /* if you have a safe environment, go into it */ if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') @@ -2841,6 +3106,14 @@ mailfile(filename, ctladdr, sfflags, e) if (chdir("/") < 0) syserr("mailfile: cannot chdir(/)"); + /* now reset the group and user ids */ + endpwent(); + if (setgid(RealGid) < 0 && suidwarn) + syserr("mailfile: setgid(%ld) failed", (long) RealGid); + vendor_set_uid(RealUid); + if (setuid(RealUid) < 0 && suidwarn) + syserr("mailfile: setuid(%ld) failed", (long) RealUid); + sfflags |= SFF_NOPATHCHECK; sfflags &= ~SFF_OPENASROOT; f = safefopen(filename, oflags, FileMode, sfflags); @@ -2897,6 +3170,7 @@ mailfile(filename, ctladdr, sfflags, e) } /*NOTREACHED*/ } + return EX_UNAVAILABLE; /* avoid compiler warning on IRIX */ } /* ** HOSTSIGNATURE -- return the "signature" for a host. @@ -2929,7 +3203,6 @@ hostsignature(m, host, e) int len; #if NAMED_BIND int nmx; - auto int rcode; char *hp; char *endp; int oldoptions = _res.options; @@ -2969,23 +3242,33 @@ hostsignature(m, host, e) if (endp != NULL) *endp = '\0'; - nmx = getmxrr(hp, mxhosts, TRUE, &rcode); - - if (nmx <= 0) + if (bitnset(M_NOMX, m->m_flags)) { - register MCI *mci; - - /* update the connection info for this host */ - mci = mci_get(hp, m); - mci->mci_lastuse = curtime(); - mci->mci_exitstat = rcode; - mci->mci_errno = errno; - mci->mci_herrno = h_errno; - - /* and return the original host name as the signature */ + /* skip MX lookups */ nmx = 1; mxhosts[0] = hp; } + else + { + auto int rcode; + + nmx = getmxrr(hp, mxhosts, TRUE, &rcode); + if (nmx <= 0) + { + register MCI *mci; + + /* update the connection info for this host */ + mci = mci_get(hp, m); + mci->mci_lastuse = curtime(); + mci->mci_exitstat = rcode; + mci->mci_errno = errno; + mci->mci_herrno = h_errno; + + /* use the original host name as signature */ + nmx = 1; + mxhosts[0] = hp; + } + } len = 0; for (i = 0; i < nmx; i++) diff --git a/usr.sbin/sendmail/src/domain.c b/usr.sbin/sendmail/src/domain.c index f446e74..1db714a 100644 --- a/usr.sbin/sendmail/src/domain.c +++ b/usr.sbin/sendmail/src/domain.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1986, 1995 Eric P. Allman + * Copyright (c) 1986, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if NAMED_BIND -static char sccsid[] = "@(#)domain.c 8.54.1.2 (Berkeley) 9/16/96 (with name server)"; +static char sccsid[] = "@(#)domain.c 8.63 (Berkeley) 9/15/96 (with name server)"; #else -static char sccsid[] = "@(#)domain.c 8.54.1.2 (Berkeley) 9/16/96 (without name server)"; +static char sccsid[] = "@(#)domain.c 8.63 (Berkeley) 9/15/96 (without name server)"; #endif #endif /* not lint */ @@ -46,6 +46,7 @@ static char sccsid[] = "@(#)domain.c 8.54.1.2 (Berkeley) 9/16/96 (without name s #include <errno.h> #include <resolv.h> +#include <arpa/inet.h> typedef union { @@ -53,14 +54,18 @@ typedef union u_char qb2[PACKETSZ]; } querybuf; -static char MXHostBuf[MAXMXHOSTS*PACKETSZ]; +#ifndef MXHOSTBUFSIZE +# define MXHOSTBUFSIZE (128 * MAXMXHOSTS) +#endif + +static char MXHostBuf[MXHOSTBUFSIZE]; #ifndef MAXDNSRCH -#define MAXDNSRCH 6 /* number of possible domains to search */ +# define MAXDNSRCH 6 /* number of possible domains to search */ #endif #ifndef MAX -#define MAX(a, b) ((a) > (b) ? (a) : (b)) +# define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef NO_DATA @@ -114,32 +119,21 @@ getmxrr(host, mxhosts, droplocalhost, rcode) u_short pref, type; u_short localpref = 256; char *fallbackMX = FallBackMX; - static bool firsttime = TRUE; bool trycanon = FALSE; int (*resfunc)(); extern int res_query(), res_search(); u_short prefer[MAXMXHOSTS]; int weight[MAXMXHOSTS]; - extern bool getcanonname(); + extern int mxrand __P((char *)); if (tTd(8, 2)) printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost); - if (fallbackMX != NULL) + if (fallbackMX != NULL && droplocalhost && + wordinclass(fallbackMX, 'w')) { - if (firsttime && - res_query(FallBackMX, C_IN, T_A, - (u_char *) &answer, sizeof answer) < 0) - { - /* this entry is bogus */ - fallbackMX = FallBackMX = NULL; - } - else if (droplocalhost && wordinclass(fallbackMX, 'w')) - { - /* don't use fallback for this pass */ - fallbackMX = NULL; - } - firsttime = FALSE; + /* don't use fallback for this pass */ + fallbackMX = NULL; } *rcode = EX_OK; @@ -356,8 +350,11 @@ punt: if (p != NULL) { *p = '\0'; - if (inet_addr(&MXHostBuf[1]) != -1) + if (inet_addr(&MXHostBuf[1]) != INADDR_NONE) + { + nmx++; *p = ']'; + } else { trycanon = TRUE; diff --git a/usr.sbin/sendmail/src/headers.c b/usr.sbin/sendmail/src/headers.c index 72092d7..6ab97e4 100644 --- a/usr.sbin/sendmail/src/headers.c +++ b/usr.sbin/sendmail/src/headers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)headers.c 8.82.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)headers.c 8.100 (Berkeley) 9/15/96"; #endif /* not lint */ # include <errno.h> @@ -74,7 +74,6 @@ chompheader(line, def, hdrp, e) bool cond = FALSE; bool headeronly; BITMAP mopts; - char buf[MAXNAME + 1]; if (tTd(31, 6)) { @@ -158,7 +157,6 @@ chompheader(line, def, hdrp, e) if (bitset(H_EOH, hi->hi_flags)) return (hi->hi_flags); -#ifdef LOTUS_NOTES_HACK /* ** Horrible hack to work around problem with Lotus Notes SMTP ** mail gateway, which generates From: headers with newlines in @@ -172,7 +170,6 @@ chompheader(line, def, hdrp, e) while ((p = strchr(fvalue, '\n')) != NULL) *p = ' '; } -#endif /* ** Drop explicit From: if same as what we would generate. @@ -195,46 +192,6 @@ chompheader(line, def, hdrp, e) (strcmp(fvalue, e->e_from.q_paddr) == 0 || strcmp(fvalue, e->e_from.q_user) == 0)) return (hi->hi_flags); -#ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ -#if USERDB - else - { - auto ADDRESS a; - char *fancy; - bool oldSuprErrs = SuprErrs; - extern char *crackaddr(); - extern char *udbsender(); - - /* - ** Try doing USERDB rewriting even on fully commented - ** names; this saves the "comment" information (such - ** as full name) and rewrites the electronic part. - ** - ** XXX This code doesn't belong here -- parsing should - ** XXX not be done during collect() phase because - ** XXX error messages can confuse the SMTP phase. - ** XXX Setting SuprErrs is a crude hack around this - ** XXX problem. - */ - - if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) - SuprErrs = TRUE; - fancy = crackaddr(fvalue); - if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && - bitnset(M_CHECKUDB, a.q_mailer->m_flags) && - (p = udbsender(a.q_user)) != NULL) - { - char *oldg = macvalue('g', e); - - define('g', p, e); - expand(fancy, buf, sizeof buf, e); - define('g', oldg, e); - fvalue = buf; - } - SuprErrs = oldSuprErrs; - } -#endif -#endif } /* delete default value for this header */ @@ -433,6 +390,7 @@ eatheader(e, full) int hopcnt = 0; char *msgid; char buf[MAXLINE]; + extern int priencode __P((char *)); /* ** Set up macros for possible expansion in headers. @@ -522,10 +480,6 @@ eatheader(e, full) while (isascii(*msgid) && isspace(*msgid)) msgid++; } - - /* see if this is a return-receipt header */ - if (bitset(H_RECEIPTTO, h->h_flags)) - e->e_receiptto = h->h_value; } if (tTd(32, 1)) printf("----------------------------\n"); @@ -558,11 +512,11 @@ eatheader(e, full) if (p != NULL) { /* (this should be in the configuration file) */ - if (strcasecmp(p, "urgent")) + if (strcasecmp(p, "urgent") == 0) e->e_timeoutclass = TOC_URGENT; - else if (strcasecmp(p, "normal")) + else if (strcasecmp(p, "normal") == 0) e->e_timeoutclass = TOC_NORMAL; - else if (strcasecmp(p, "non-urgent")) + else if (strcasecmp(p, "non-urgent") == 0) e->e_timeoutclass = TOC_NONURGENT; } @@ -807,6 +761,7 @@ crackaddr(addr) int realcmtlev; int anglelev, realanglelev; int copylev; + int bracklev; bool qmode; bool realqmode; bool skipping; @@ -833,9 +788,10 @@ crackaddr(addr) */ bp = bufhead = buf; - buflim = &buf[sizeof buf - 5]; + buflim = &buf[sizeof buf - 6]; p = addrhead = addr; copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; + bracklev = 0; qmode = realqmode = FALSE; while ((c = *p++) != '\0') @@ -892,7 +848,8 @@ crackaddr(addr) realcmtlev++; if (copylev++ <= 0) { - *bp++ = ' '; + if (bp != bufhead) + *bp++ = ' '; *bp++ = c; } } @@ -918,20 +875,33 @@ crackaddr(addr) bp--; } + /* count nesting on [ ... ] (for IPv6 domain literals) */ + if (c == '[') + bracklev++; + else if (c == ']') + bracklev--; + /* check for group: list; syntax */ - if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) + if (c == ':' && anglelev <= 0 && bracklev <= 0 && + !gotcolon && !ColonOkInAddr) { register char *q; - if (*p == ':') + /* + ** Check for DECnet phase IV ``::'' (host::user) + ** or ** DECnet phase V ``:.'' syntaxes. The latter + ** covers ``user@DEC:.tay.myhost'' and + ** ``DEC:.tay.myhost::user'' syntaxes (bletch). + */ + + if (*p == ':' || *p == '.') { - /* special case -- :: syntax */ if (cmtlev <= 0 && !qmode) quoteit = TRUE; if (copylev > 0 && !skipping) { *bp++ = c; - *bp++ = c; + *bp++ = *p; } p++; goto putg; @@ -1086,6 +1056,8 @@ crackaddr(addr) putg: if (copylev <= 0 && !putgmac) { + if (bp > bufhead && bp[-1] == ')') + *bp++ = ' '; *bp++ = MACROEXPAND; *bp++ = 'g'; putgmac = TRUE; @@ -1102,7 +1074,11 @@ crackaddr(addr) *bp++ = '\0'; if (tTd(33, 1)) - printf("crackaddr=>`%s'\n", buf); + { + printf("crackaddr=>`"); + xputs(buf); + printf("'\n"); + } return (buf); } @@ -1129,11 +1105,12 @@ crackaddr(addr) #endif void -putheader(mci, h, e) +putheader(mci, hdr, e) register MCI *mci; - register HDR *h; + HDR *hdr; register ENVELOPE *e; { + register HDR *h; char buf[MAX(MAXLINE,BUFSIZ)]; char obuf[MAXLINE]; @@ -1142,7 +1119,7 @@ putheader(mci, h, e) mci->mci_mailer->m_name); mci->mci_flags |= MCIF_INHEADER; - for (; h != NULL; h = h->h_link) + for (h = hdr; h != NULL; h = h->h_link) { register char *p = h->h_value; extern bool bitintersect(); @@ -1155,7 +1132,7 @@ putheader(mci, h, e) /* suppress Content-Transfer-Encoding: if we are MIMEing */ if (bitset(H_CTE, h->h_flags) && - bitset(MCIF_CVT8TO7|MCIF_INMIME, mci->mci_flags)) + bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags)) { if (tTd(34, 11)) printf(" (skipped (content-transfer-encoding))\n"); @@ -1166,7 +1143,8 @@ putheader(mci, h, e) { if (tTd(34, 11)) printf("\n"); - goto vanilla; + put_vanilla_header(h, p, mci); + continue; } if (bitset(H_CHECK|H_ACHECK, h->h_flags) && @@ -1239,31 +1217,7 @@ putheader(mci, h, e) } else { - /* vanilla header line */ - register char *nlp; - register char *obp; - -vanilla: - obp = obuf; - (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", - h->h_field); - obp = obuf + strlen(obuf); - while ((nlp = strchr(p, '\n')) != NULL) - { - - *nlp = '\0'; - snprintf(obp, SPACELEFT(obuf, obp), "%.*s", - sizeof obuf - (obp - obuf) - 1, p); - *nlp = '\n'; - putline(obuf, mci); - p = ++nlp; - obp = obuf; - if (*p != ' ' && *p != '\t') - *obp++ = ' '; - } - snprintf(obp, SPACELEFT(obuf, obp), "%.*s", - sizeof obuf - (obp - obuf) - 1, p); - putline(obuf, mci); + put_vanilla_header(h, p, mci); } } @@ -1277,7 +1231,7 @@ vanilla: bitset(EF_HAS8BIT, e->e_flags) && !bitset(EF_DONT_MIME, e->e_flags) && !bitnset(M_8BITS, mci->mci_mailer->m_flags) && - !bitset(MCIF_CVT8TO7, mci->mci_flags)) + !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8, mci->mci_flags)) { if (hvalue("MIME-Version", e->e_header) == NULL) putline("MIME-Version: 1.0", mci); @@ -1294,6 +1248,49 @@ vanilla: #endif } /* +** PUT_VANILLA_HEADER -- output a fairly ordinary header +** +** Parameters: +** h -- the structure describing this header +** v -- the value of this header +** mci -- the connection info for output +** +** Returns: +** none. +*/ + +void +put_vanilla_header(h, v, mci) + HDR *h; + char *v; + MCI *mci; +{ + register char *nlp; + register char *obp; + char obuf[MAXLINE]; + + (void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field); + obp = obuf + strlen(obuf); + while ((nlp = strchr(v, '\n')) != NULL) + { + int l; + + l = nlp - v; + if (sizeof obuf - (obp - obuf) < l) + l = sizeof obuf - (obp - obuf); + + snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); + putline(obuf, mci); + v += l + 1; + obp = obuf; + if (*v != ' ' && *v != '\t') + *obp++ = ' '; + } + snprintf(obp, SPACELEFT(obuf, obp), "%.*s", + sizeof obuf - (obp - obuf) - 1, v); + putline(obuf, mci); +} +/* ** COMMAIZE -- output a header field, making a comma-translated list. ** ** Parameters: diff --git a/usr.sbin/sendmail/src/main.c b/usr.sbin/sendmail/src/main.c index e19efa4..504fba3 100644 --- a/usr.sbin/sendmail/src/main.c +++ b/usr.sbin/sendmail/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -39,12 +39,13 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.162.1.3 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)main.c 8.211 (Berkeley) 10/12/96"; #endif /* not lint */ #define _DEFINE #include "sendmail.h" +#include <arpa/inet.h> #if NAMED_BIND #include <resolv.h> #endif @@ -75,14 +76,16 @@ char edata, end; ** See the associated documentation for details. ** ** Author: -** Eric Allman, UCB/INGRES (until 10/81) +** Eric Allman, UCB/INGRES (until 10/81). ** Britton-Lee, Inc., purveyors of fine -** database computers (from 11/81) -** Now back at UCB at the Mammoth project. -** The support of the INGRES Project and Britton-Lee is -** gratefully acknowledged. Britton-Lee in -** particular had absolutely nothing to gain from -** my involvement in this project. +** database computers (11/81 - 10/88). +** International Computer Science Institute +** (11/88 - 9/89). +** UCB/Mammoth Project (10/89 - 7/95). +** InReference, Inc. (8/95 - present). +** The support of the my employers is gratefully acknowledged. +** Few of them (Britton-Lee in particular) have had +** anything to gain from my involvement in this project. */ @@ -97,6 +100,8 @@ bool Warn_Q_option = FALSE; /* warn about Q option use */ char **SaveArgv; /* argument vector for re-execing */ static void obsolete(); +extern void printmailer __P((MAILER *)); +extern void tTflag __P((char *)); #ifdef DAEMON #ifndef SMTP @@ -104,7 +109,7 @@ ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR #endif /* SMTP */ #endif /* DAEMON */ -#define MAXCONFIGLEVEL 6 /* highest config version level known */ +#define MAXCONFIGLEVEL 7 /* highest config version level known */ int main(argc, argv, envp) @@ -124,26 +129,40 @@ main(argc, argv, envp) bool safecf = TRUE; bool warn_C_flag = FALSE; char warn_f_flag = '\0'; + bool run_in_foreground = FALSE; /* -bD mode */ static bool reenter = FALSE; struct passwd *pw; struct stat stb; struct hostent *hp; + bool nullserver; char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ static char rnamebuf[MAXNAME]; /* holds RealUserName */ + char *emptyenviron[1]; extern int DtableSize; extern int optind; extern int opterr; + extern char *optarg; + extern char **environ; extern time_t convtime(); extern void intsig(); extern struct hostent *myhostname(); - extern char *arpadate(); extern char *getauthinfo(); extern char *getcfname(); - extern char *optarg; - extern char **environ; extern void sigusr1(); extern void sighup(); extern void initmacros __P((ENVELOPE *)); + extern void init_md __P((int, char **)); + extern int getdtsize __P((void)); + extern void tTsetup __P((u_char *, int, char *)); + extern void setdefaults __P((ENVELOPE *)); + extern void initsetproctitle __P((int, char **, char **)); + extern void init_vendor_macros __P((ENVELOPE *)); + extern void load_if_names __P((void)); + extern void vendor_pre_defaults __P((ENVELOPE *)); + extern void vendor_post_defaults __P((ENVELOPE *)); + extern void readcf __P((char *, bool, ENVELOPE *)); + extern void printqueue __P((void)); + extern void sendtoargv __P((char **, ENVELOPE *)); extern void resetlimits __P((void)); /* @@ -159,6 +178,9 @@ main(argc, argv, envp) } reenter = TRUE; + /* avoid null pointer dereferences */ + TermEscape.te_rv_on = TermEscape.te_rv_off = ""; + /* do machine-dependent initializations */ init_md(argc, argv); @@ -205,6 +227,42 @@ main(argc, argv, envp) tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); + /* Handle any non-getoptable constructions. */ + obsolete(argv); + + /* + ** Do a quick prescan of the argument list. + */ + +#if defined(__osf__) || defined(_AIX3) +# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:x" +#endif +#if defined(sony_news) +# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mN:nO:o:p:q:R:r:sTtUV:vX:" +#endif +#ifndef OPTIONS +# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mN:nO:o:p:q:R:r:sTtUV:vX:" +#endif + opterr = 0; + while ((j = getopt(argc, argv, OPTIONS)) != EOF) + { + switch (j) + { + case 'd': + /* hack attack -- see if should use ANSI mode */ + if (strcmp(optarg, "ANSI") == 0) + { + TermEscape.te_rv_on = "\033[7m"; + TermEscape.te_rv_off = "\033[0m"; + break; + } + tTflag(optarg); + setbuf(stdout, (char *) NULL); + break; + } + } + opterr = 1; + /* set up the blank envelope */ BlankEnvelope.e_puthdr = putheader; BlankEnvelope.e_putbody = putbody; @@ -247,35 +305,6 @@ main(argc, argv, envp) } SaveArgv[i] = NULL; - /* Handle any non-getoptable constructions. */ - obsolete(argv); - - /* - ** Do a quick prescan of the argument list. - */ - -#if defined(__osf__) || defined(_AIX3) -# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:x" -#endif -#if defined(sony_news) -# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:M:mnO:o:p:q:r:sTtvX:" -#endif -#ifndef OPTIONS -# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:" -#endif - opterr = 0; - while ((j = getopt(argc, argv, OPTIONS)) != EOF) - { - switch (j) - { - case 'd': - tTflag(optarg); - setbuf(stdout, (char *) NULL); - break; - } - } - opterr = 1; - if (tTd(0, 1)) { int ll; @@ -308,7 +337,7 @@ main(argc, argv, envp) int ll; extern char *OsCompileOptions[]; - printf(" OS Defines:", Version); + printf(" OS Defines:"); av = OsCompileOptions; ll = 7; while (*av != NULL) @@ -332,7 +361,7 @@ main(argc, argv, envp) #ifdef _PATH_UNIX printf("Kernel symbols:\t%s\n", _PATH_UNIX); #endif - printf(" Config file:\t%s\n", getcfname()); + printf(" Def Conf file:\t%s\n", getcfname()); printf(" Pid file:\t%s\n", PidFile); } @@ -342,6 +371,11 @@ main(argc, argv, envp) /* initialize for setproctitle */ initsetproctitle(argc, argv, envp); + /* clear sendmail's environment */ + ExternalEnviron = environ; + emptyenviron[0] = NULL; + environ = emptyenviron; + /* prime the child environment */ setuserenv("AGENT", "sendmail"); @@ -351,7 +385,7 @@ main(argc, argv, envp) (void) setsignal(SIGPIPE, SIG_IGN); OldUmask = umask(022); OpMode = MD_DELIVER; - FullName = getenv("NAME"); + FullName = getextenv("NAME"); #if NAMED_BIND if (tTd(8, 8)) @@ -393,6 +427,8 @@ main(argc, argv, envp) while (p != NULL && strchr(&p[1], '.') != NULL) { *p = '\0'; + if (tTd(0, 4)) + printf("\ta.k.a.: %s\n", jbuf); setclass('w', jbuf); *p++ = '.'; p = strchr(p, '.'); @@ -449,13 +485,6 @@ main(argc, argv, envp) define('b', arpadate((char *) NULL), CurEnv); /* - ** Find our real host name for future logging. - */ - - p = getauthinfo(STDIN_FILENO); - define('_', p, CurEnv); - - /* ** Crack argv. */ @@ -469,6 +498,10 @@ main(argc, argv, envp) OpMode = MD_PRINT; else if (strcmp(p, "smtpd") == 0) OpMode = MD_DAEMON; + else if (strcmp(p, "hoststat") == 0) + OpMode = MD_HOSTSTAT; + else if (strcmp(p, "purgestat") == 0) + OpMode = MD_PURGESTAT; optind = 1; while ((j = getopt(argc, argv, OPTIONS)) != EOF) @@ -479,12 +512,15 @@ main(argc, argv, envp) switch (j = *optarg) { case MD_DAEMON: + case MD_FGDAEMON: # ifdef DAEMON - if (RealUid != 0) { + if (RealUid != 0) + { usrerr("Permission denied"); - exit (EX_USAGE); + exit(EX_USAGE); } - (void) unsetenv("HOSTALIASES"); + vendor_daemon_setup(CurEnv); + /* fall through ... */ # else usrerr("Daemon mode not implemented"); ExitStat = EX_USAGE; @@ -496,11 +532,16 @@ main(argc, argv, envp) ExitStat = EX_USAGE; break; # endif /* SMTP */ + + case MD_INITALIAS: + /* fall through ... */ + case MD_DELIVER: case MD_VERIFY: case MD_TEST: - case MD_INITALIAS: case MD_PRINT: + case MD_HOSTSTAT: + case MD_PURGESTAT: case MD_ARPAFTP: OpMode = j; break; @@ -557,7 +598,6 @@ main(argc, argv, envp) { usrerr("Bad hop count (%s)", optarg); ExitStat = EX_USAGE; - break; } break; @@ -565,6 +605,29 @@ main(argc, argv, envp) NoAlias = TRUE; break; + case 'N': /* delivery status notifications */ + DefaultNotify |= QHASNOTIFY; + if (strcasecmp(optarg, "never") == 0) + break; + for (p = optarg; p != NULL; optarg = p) + { + p = strchr(p, ','); + if (p != NULL) + *p++ = '\0'; + if (strcasecmp(optarg, "success") == 0) + DefaultNotify |= QPINGONSUCCESS; + else if (strcasecmp(optarg, "failure") == 0) + DefaultNotify |= QPINGONFAILURE; + else if (strcasecmp(optarg, "delay") == 0) + DefaultNotify |= QPINGONDELAY; + else + { + usrerr("Invalid -N argument"); + ExitStat = EX_USAGE; + } + } + break; + case 'o': /* set option */ setoption(*optarg, optarg + 1, FALSE, TRUE, CurEnv); break; @@ -595,7 +658,6 @@ main(argc, argv, envp) case 'q': /* run queue files at intervals */ # ifdef QUEUE - (void) unsetenv("HOSTALIASES"); FullName = NULL; queuemode = TRUE; switch (optarg[0]) @@ -622,10 +684,41 @@ main(argc, argv, envp) # endif /* QUEUE */ break; + case 'R': /* DSN RET: what to return */ + if (bitset(EF_RET_PARAM, CurEnv->e_flags)) + { + usrerr("Duplicate -R flag"); + ExitStat = EX_USAGE; + break; + } + CurEnv->e_flags |= EF_RET_PARAM; + if (strcasecmp(optarg, "hdrs") == 0) + CurEnv->e_flags |= EF_NO_BODY_RETN; + else if (strcasecmp(optarg, "full") != 0) + { + usrerr("Invalid -R value"); + ExitStat = EX_USAGE; + } + break; + case 't': /* read recipients from message */ GrabTo = TRUE; break; + case 'U': /* initial (user) submission */ + UserSubmission = TRUE; + break; + + case 'V': /* DSN ENVID: set "original" envelope id */ + if (!xtextok(optarg)) + { + usrerr("Invalid syntax in -V flag"); + ExitStat = EX_USAGE; + } + else + CurEnv->e_envid = newstr(optarg); + break; + case 'X': /* traffic log file */ endpwent(); setgid(RealGid); @@ -634,6 +727,7 @@ main(argc, argv, envp) if (TrafficLogFile == NULL) { syserr("cannot open %s", optarg); + ExitStat = EX_CANTCREAT; break; } #ifdef HASSETVBUF @@ -706,11 +800,28 @@ main(argc, argv, envp) #endif vendor_pre_defaults(CurEnv); readcf(getcfname(), safecf, CurEnv); + ConfigFileRead = TRUE; vendor_post_defaults(CurEnv); /* avoid denial-of-service attacks */ resetlimits(); + if (OpMode != MD_DAEMON && OpMode != MD_FGDAEMON) + { + /* drop privileges -- daemon mode done after socket/bind */ + if (RunAsGid != 0) + (void) setgid(RunAsGid); + if (RunAsUid != 0) + (void) setuid(RunAsUid); + } + + /* + ** Find our real host name for future logging. + */ + + p = getauthinfo(STDIN_FILENO); + define('_', p, CurEnv); + /* suppress error printing if errors mailed back or whatever */ if (CurEnv->e_errormode != EM_PRINT) HoldErrs = TRUE; @@ -770,6 +881,10 @@ main(argc, argv, envp) CurEnv->e_bodytype = NULL; } + /* tweak default DSN notifications */ + if (DefaultNotify == 0) + DefaultNotify = QPINGONFAILURE|QPINGONDELAY; + /* Enforce use of local time (null string overrides this) */ if (TimeZoneSpec == NULL) unsetenv("TZ"); @@ -786,18 +901,49 @@ main(argc, argv, envp) ConfigLevel, MAXCONFIGLEVEL); } + /* need MCI cache to have persistence */ + if (HostStatDir != NULL && MaxMciCache == 0) + { + HostStatDir = NULL; + printf("Warning: HostStatusDirectory disabled with ConnectionCacheSize = 0\n"); + } + + /* need HostStatusDir in order to have SingleThreadDelivery */ + if (SingleThreadDelivery && HostStatDir == NULL) + { + SingleThreadDelivery = FALSE; + printf("Warning: HostStatusDirectory required for SingleThreadDelivery\n"); + } + if (MeToo) BlankEnvelope.e_flags |= EF_METOO; switch (OpMode) { + case MD_TEST: + /* don't have persistent host status in test mode */ + HostStatDir = NULL; + break; + + case MD_FGDAEMON: + run_in_foreground = TRUE; + OpMode = MD_DAEMON; + /* fall through ... */ + case MD_DAEMON: /* remove things that don't make sense in daemon mode */ FullName = NULL; GrabTo = FALSE; /* arrange to restart on hangup signal */ +#ifdef LOG + if (SaveArgv[0] == NULL || SaveArgv[0][0] != '/') + syslog(LOG_WARNING, "daemon invoked without full pathname; kill -1 won't work"); +#endif setsignal(SIGHUP, sighup); + + /* workaround: can't seem to release the signal in the parent */ + releasesignal(SIGHUP); break; case MD_INITALIAS: @@ -908,11 +1054,20 @@ main(argc, argv, envp) setuserenv("ISP", NULL); setuserenv("SYSTYPE", NULL); } + if (ConfigLevel < 7) + { + if (LocalMailer != NULL) + setbitn(M_VRFY250, LocalMailer->m_flags); + if (ProgMailer != NULL) + setbitn(M_VRFY250, ProgMailer->m_flags); + if (FileMailer != NULL) + setbitn(M_VRFY250, FileMailer->m_flags); + } /* MIME Content-Types that cannot be transfer encoded */ setclass('n', "multipart/signed"); - /* MIME message/* subtypes that can be treated as messages */ + /* MIME message/xxx subtypes that can be treated as messages */ setclass('s', "rfc822"); /* MIME Content-Transfer-Encodings that can be encoded */ @@ -920,11 +1075,36 @@ main(argc, argv, envp) setclass('e', "8bit"); setclass('e', "binary"); +#ifdef USE_B_CLASS + /* MIME Content-Types that should be treated as binary */ + setclass('b', "image"); + setclass('b', "audio"); + setclass('b', "video"); + setclass('b', "application/octet-stream"); +#endif + /* operate in queue directory */ - if (OpMode != MD_TEST && chdir(QueueDir) < 0) + if (OpMode == MD_TEST) + /* nothing -- just avoid further if clauses */ ; + else if (QueueDir == NULL) + { + syserr("QueueDirectory (Q) option must be set"); + ExitStat = EX_CONFIG; + } + else if (chdir(QueueDir) < 0) { syserr("cannot chdir(%s)", QueueDir); - ExitStat = EX_SOFTWARE; + ExitStat = EX_CONFIG; + } + + /* check host status directory for validity */ + if (HostStatDir != NULL && !path_is_dir(HostStatDir, FALSE)) + { + /* cannot use this value */ + if (tTd(0, 2)) + printf("Cannot use HostStatusDirectory = %s: %s\n", + HostStatDir, errstring(errno)); + HostStatDir = NULL; } # ifdef QUEUE @@ -965,7 +1145,7 @@ main(argc, argv, envp) case MD_PRINT: /* print the queue */ #ifdef QUEUE - dropenvelope(CurEnv); + dropenvelope(CurEnv, TRUE); printqueue(); endpwent(); setuid(RealUid); @@ -975,15 +1155,33 @@ main(argc, argv, envp) finis(); #endif /* QUEUE */ + case MD_HOSTSTAT: + mci_traverse_persistent(mci_print_persistent, NULL); + exit(EX_OK); + break; + + case MD_PURGESTAT: + mci_traverse_persistent(mci_purge_persistent, NULL); + exit(EX_OK); + break; + case MD_INITALIAS: /* initialize alias database */ initmaps(TRUE, CurEnv); endpwent(); setuid(RealUid); - exit(EX_OK); + exit(ExitStat); - case MD_DAEMON: case MD_SMTP: + nullserver = FALSE; + /* fall through... */ + + case MD_DAEMON: + /* reset DSN parameters */ + DefaultNotify = QPINGONFAILURE|QPINGONDELAY; + CurEnv->e_envid = NULL; + CurEnv->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); + /* don't open alias database -- done in srvrsmtp */ break; @@ -995,6 +1193,8 @@ main(argc, argv, envp) if (tTd(0, 15)) { + extern void printrules __P((void)); + /* print configuration table (or at least part of it) */ if (tTd(0, 90)) printrules(); @@ -1075,8 +1275,9 @@ main(argc, argv, envp) if (OpMode == MD_DAEMON || QueueIntvl != 0) { char dtype[200]; + extern bool getrequests __P((ENVELOPE *)); - if (!tTd(99, 100)) + if (!run_in_foreground && !tTd(99, 100)) { /* put us in background */ i = fork(); @@ -1116,10 +1317,16 @@ main(argc, argv, envp) pause(); } # endif /* QUEUE */ - dropenvelope(CurEnv); + dropenvelope(CurEnv, TRUE); #ifdef DAEMON - getrequests(); + nullserver = getrequests(CurEnv); + + /* drop privileges */ + if (RunAsGid != 0) + (void) setgid(RunAsGid); + if (RunAsUid != 0) + (void) setuid(RunAsUid); /* at this point we are in a child: reset state */ (void) newenvelope(CurEnv, CurEnv); @@ -1129,8 +1336,7 @@ main(argc, argv, envp) */ p = getauthinfo(fileno(InChannel)); - define('_', p, CurEnv); - + define('_', p, &BlankEnvelope); #endif /* DAEMON */ } @@ -1141,14 +1347,34 @@ main(argc, argv, envp) */ if (OpMode == MD_SMTP || OpMode == MD_DAEMON) - smtp(CurEnv); + { + char pbuf[20]; + extern void smtp __P((bool, ENVELOPE *)); + + /* + ** Save some macros for check_* rulesets. + */ + + define(macid("{client_name}", NULL), RealHostName, &BlankEnvelope); + define(macid("{client_addr}", NULL), + newstr(anynet_ntoa(&RealHostAddr)), &BlankEnvelope); + if (RealHostAddr.sa.sa_family == AF_INET) + snprintf(pbuf, sizeof pbuf, "%d", RealHostAddr.sin.sin_port); + else + snprintf(pbuf, sizeof pbuf, "0"); + define(macid("{client_port}", NULL), newstr(pbuf), &BlankEnvelope); + + smtp(nullserver, CurEnv); + } # endif /* SMTP */ + clearenvelope(CurEnv, FALSE); if (OpMode == MD_VERIFY) { CurEnv->e_sendmode = SM_VERIFY; - CurEnv->e_errormode = EM_QUIET; + CurEnv->e_errormode = EM_PRINT; PostMasterCopy = NULL; + HoldErrs = FALSE; } else { @@ -1224,6 +1450,8 @@ main(argc, argv, envp) */ finis(); + /*NOTREACHED*/ + return -1; } @@ -1264,7 +1492,8 @@ finis() /* clean up temp files */ CurEnv->e_to = NULL; - dropenvelope(CurEnv); + if (CurEnv->e_id != NULL) + dropenvelope(CurEnv, TRUE); /* flush any cached connections */ mci_flush(TRUE, NULL); @@ -1307,6 +1536,11 @@ finis() void intsig() { +#ifdef LOG + if (LogLevel > 79) + syslog(LOG_DEBUG, "%s: interrupt", + CurEnv->e_id == NULL ? "[NOQUEUE]" : CurEnv->e_id); +#endif FileName = NULL; unlockqueue(CurEnv); #ifdef XLA @@ -1338,24 +1572,24 @@ intsig() struct metamac MetaMacros[] = { /* LHS pattern matching characters */ - '*', MATCHZANY, '+', MATCHANY, '-', MATCHONE, - '=', MATCHCLASS, '~', MATCHNCLASS, + { '*', MATCHZANY }, { '+', MATCHANY }, { '-', MATCHONE }, + { '=', MATCHCLASS }, { '~', MATCHNCLASS }, /* these are RHS metasymbols */ - '#', CANONNET, '@', CANONHOST, ':', CANONUSER, - '>', CALLSUBR, + { '#', CANONNET }, { '@', CANONHOST }, { ':', CANONUSER }, + { '>', CALLSUBR }, /* the conditional operations */ - '?', CONDIF, '|', CONDELSE, '.', CONDFI, + { '?', CONDIF }, { '|', CONDELSE }, { '.', CONDFI }, /* the hostname lookup characters */ - '[', HOSTBEGIN, ']', HOSTEND, - '(', LOOKUPBEGIN, ')', LOOKUPEND, + { '[', HOSTBEGIN }, { ']', HOSTEND }, + { '(', LOOKUPBEGIN }, { ')', LOOKUPEND }, /* miscellaneous control characters */ - '&', MACRODEXPAND, + { '&', MACRODEXPAND }, - '\0' + { '\0' } }; #define MACBINDING(name, mid) \ @@ -1427,6 +1661,11 @@ disconnect(droplev, e) printf("don't\n"); return; } +#ifdef LOG + if (LogLevel > 93) + syslog(LOG_DEBUG, "%s: disconnect level %d", + e->e_id == NULL ? "[NOQUEUE]" : e->e_id, droplev); +#endif /* be sure we don't get nasty signals */ (void) setsignal(SIGINT, SIG_IGN); @@ -1576,7 +1815,7 @@ auth_warning(e, msg, va_alist) (void) snprintf(buf, sizeof buf, "%s: ", hostbuf); p = &buf[strlen(buf)]; VA_START(msg); - vsnprintf(p, sizeof buf - (p - buf), msg, ap); + vsnprintf(p, SPACELEFT(buf, p), msg, ap); VA_END; addheader("X-Authentication-Warning", buf, &e->e_header); #ifdef LOG @@ -1587,6 +1826,31 @@ auth_warning(e, msg, va_alist) } } /* +** GETEXTENV -- get from external environment +** +** Parameters: +** envar -- the name of the variable to retrieve +** +** Returns: +** The value, if any. +*/ + +char * +getextenv(envar) + const char *envar; +{ + char **envp; + int l; + + l = strlen(envar); + for (envp = ExternalEnviron; *envp != NULL; envp++) + { + if (strncmp(*envp, envar, l) == 0 && (*envp)[l] == '=') + return &(*envp)[l + 1]; + } + return NULL; +} +/* ** SETUSERENV -- set an environment in the propogated environment ** ** Parameters: @@ -1611,7 +1875,7 @@ setuserenv(envar, value) if (value == NULL) { - value = getenv(envar); + value = getextenv(envar); if (value == NULL) return; } @@ -1650,6 +1914,7 @@ dumpstate(when) { #ifdef LOG register char *j = macvalue('j', CurEnv); + int rs; syslog(LOG_DEBUG, "--- dumping state on %s: $j = %s ---", when, @@ -1664,16 +1929,18 @@ dumpstate(when) printopenfds(TRUE); syslog(LOG_DEBUG, "--- connection cache: ---"); mci_dump_all(TRUE); - if (RewriteRules[89] != NULL) + rs = strtorwset("debug_dumpstate", NULL, ST_FIND); + if (rs > 0) { int stat; register char **pvp; char *pv[MAXATOM + 1]; pv[0] = NULL; - stat = rewrite(pv, 89, 0, CurEnv); - syslog(LOG_DEBUG, "--- ruleset 89 returns stat %d, pv: ---", - stat); + stat = rewrite(pv, rs, 0, CurEnv); + syslog(LOG_DEBUG, + "--- ruleset debug_dumpstate returns stat %d, pv: ---", + stat); for (pvp = pv; *pvp != NULL; pvp++) syslog(LOG_DEBUG, "%s", *pvp); } @@ -1739,6 +2006,7 @@ testmodeline(line, e) extern char *crackaddr __P((char *)); extern void dump_class __P((STAB *, int)); extern void translate_dollars __P((char *)); + extern void help __P((char *)); switch (line[0]) { @@ -1805,7 +2073,10 @@ testmodeline(line, e) case 'S': /* dump rule set */ rs = strtorwset(&line[2], NULL, ST_FIND); if (rs < 0) + { + printf("Undefined ruleset %s\n", &line[2]); return; + } rw = RewriteRules[rs]; if (rw == NULL) return; @@ -1827,7 +2098,7 @@ testmodeline(line, e) putchar(' '); } putchar('\n'); - } while (rw = rw->r_next); + } while ((rw = rw->r_next) != NULL); break; case 'M': @@ -1926,7 +2197,6 @@ testmodeline(line, e) } else if (strcasecmp(&line[1], "canon") == 0) { - auto int rcode = EX_OK; char host[MAXHOSTNAMELEN]; if (*p == '\0') @@ -1940,9 +2210,8 @@ testmodeline(line, e) return; } strcpy(host, p); - getcanonname(host, sizeof(host), HasWildcardMX, &rcode); - printf("getcanonname(%s) returns %s (%d)\n", - p, host, rcode); + (void) getcanonname(host, sizeof(host), HasWildcardMX); + printf("getcanonname(%s) returns %s\n", p, host); } else if (strcasecmp(&line[1], "map") == 0) { @@ -2006,6 +2275,7 @@ testmodeline(line, e) p = remotename(q, m, tryflags, &rcode, CurEnv); printf("Rcode = %d, addr = %s\n", rcode, p == NULL ? "<NULL>" : p); + e->e_to = NULL; } else if (strcasecmp(&line[1], "tryflags") == 0) { @@ -2061,6 +2331,7 @@ testmodeline(line, e) else printf("mailer %s, user %s\n", a.q_mailer->m_name, a.q_user); + e->e_to = NULL; } else { @@ -2098,7 +2369,10 @@ testmodeline(line, e) int rs = strtorwset(p, NULL, ST_FIND); if (rs < 0) + { + printf("Undefined ruleset %s\n", p); break; + } stat = rewrite(pvp, rs, 0, e); if (stat != EX_OK) printf("== Ruleset %s (%d) status %d\n", diff --git a/usr.sbin/sendmail/src/parseaddr.c b/usr.sbin/sendmail/src/parseaddr.c index 7507b83..3b466f9 100644 --- a/usr.sbin/sendmail/src/parseaddr.c +++ b/usr.sbin/sendmail/src/parseaddr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)parseaddr.c 8.87.1.1 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)parseaddr.c 8.114 (Berkeley) 9/20/96"; #endif /* not lint */ # include "sendmail.h" @@ -169,7 +169,7 @@ parseaddr(addr, a, flags, delim, delimptr, e) ** If there was a parsing failure, mark it for queueing. */ - if (queueup) + if (queueup && OpMode != MD_INITALIAS) { char *msg = "Transient parse error -- message queued for future delivery"; @@ -220,14 +220,6 @@ invalidaddr(addr, delimptr) if (savedelim != '\0') *delimptr = '\0'; } -#if 0 - /* for testing.... */ - if (strcmp(addr, "INvalidADDR") == 0) - { - usrerr("553 INvalid ADDRess"); - goto addrfailure; - } -#endif for (; *addr != '\0'; addr++) { if ((*addr & 0340) == 0200) @@ -241,7 +233,6 @@ invalidaddr(addr, delimptr) } setstat(EX_USAGE); usrerr("553 Address contained invalid control characters"); - addrfailure: if (delimptr != NULL && savedelim != '\0') *delimptr = savedelim; return TRUE; @@ -343,12 +334,12 @@ allocaddr(a, flags, paddr) static short StateTab[NSTATES][NSTATES] = { /* oldst chtype> OPR ATM QST SPC ONE ILL */ - /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB, - /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB, - /*QST*/ QST, QST, OPR, QST, QST, QST, - /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ILL|MB, - /*ONE*/ OPR, OPR, OPR, OPR, OPR, ILL|MB, - /*ILL*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M, + /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, + /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, + /*QST*/ { QST, QST, OPR, QST, QST, QST }, + /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, + /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, + /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, }; /* token type table -- it gets modified with $o characters */ @@ -444,6 +435,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) register int c; char **avp; bool bslashmode; + bool route_syntax; int cmntcnt; int anglecnt; char *tok; @@ -483,6 +475,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) q = pvpbuf; bslashmode = FALSE; + route_syntax = FALSE; cmntcnt = 0; anglecnt = 0; avp = av; @@ -510,7 +503,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) if (q >= &pvpbuf[pvpbsize - 5]) { usrerr("553 Address too long"); - if (strlen(addr) > MAXNAME) + if (strlen(addr) > (SIZE_T) MAXNAME) addr[MAXNAME] = '\0'; returnnull: if (delimptr != NULL) @@ -548,9 +541,19 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) p--; } - else if (c == delim && anglecnt <= 0 && - cmntcnt <= 0 && state != QST) - break; + else if (c == delim && cmntcnt <= 0 && state != QST) + { + if (anglecnt <= 0) + break; + + /* special case for better error management */ + if (delim == ',' && !route_syntax) + { + usrerr("653 Unbalanced '<'"); + c = '>'; + p--; + } + } if (tTd(22, 101)) printf("c=%c, s=%d; ", c, state); @@ -600,7 +603,15 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) else if (cmntcnt > 0) c = NOCHAR; else if (c == '<') + { + char *q = p; + anglecnt++; + while (isascii(*q) && isspace(*q)) + q++; + if (*q == '@') + route_syntax = TRUE; + } else if (c == '>') { if (anglecnt <= 0) @@ -610,6 +621,7 @@ prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) } else anglecnt--; + route_syntax = FALSE; } else if (delim == ' ' && isascii(c) && isspace(c)) c = ' '; @@ -743,10 +755,11 @@ rewrite(pvp, ruleset, reclevel, e) int loopcount; struct match mlist[MAXMATCH]; /* stores match on LHS */ char *npvp[MAXATOM+1]; /* temporary space for rebuild */ + extern int callsubr __P((char**, int, ENVELOPE *)); if (OpMode == MD_TEST || tTd(21, 1)) { - printf("rewrite: ruleset %2d input:", ruleset); + printf("rewrite: ruleset %3d input:", ruleset); printav(pvp); } if (ruleset < 0 || ruleset >= MAXRWSETS) @@ -772,6 +785,12 @@ rewrite(pvp, ruleset, reclevel, e) loopcount = 0; for (rwr = RewriteRules[ruleset]; rwr != NULL; ) { + int stat; + + /* if already canonical, quit now */ + if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) + break; + if (tTd(21, 12)) { printf("-----trying rule:"); @@ -1002,8 +1021,6 @@ rewrite(pvp, ruleset, reclevel, e) rvp++; rwr = NULL; } - else if ((*rp & 0377) == CANONNET) - rwr = NULL; /* substitute */ for (avp = npvp; *rvp != NULL; rvp++) @@ -1091,6 +1108,7 @@ rewrite(pvp, ruleset, reclevel, e) char *argvect[10]; char pvpbuf[PSBUFSIZE]; char *nullpvp[1]; + extern char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); if ((**rvp & 0377) != HOSTBEGIN && (**rvp & 0377) != LOOKUPBEGIN) @@ -1173,55 +1191,7 @@ rewrite(pvp, ruleset, reclevel, e) /* look it up */ cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); argvect[0] = buf; - if (e->e_sendmode == SM_DEFER) - { - /* don't do any map lookups */ - if (tTd(60, 1)) - printf("map_lookup(%s, %s) => DEFERRED\n", - mapname, buf); - replac = NULL; - rstat = EX_TEMPFAIL; - } - else if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) - { - auto int stat = EX_OK; - - if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags)) - stripquotes(buf); - - /* XXX should try to auto-open the map here */ - - if (tTd(60, 1)) - printf("map_lookup(%s, %s) => ", - mapname, buf); - replac = (*map->s_map.map_class->map_lookup)(&map->s_map, - buf, argvect, &stat); - if (tTd(60, 1)) - printf("%s (%d)\n", - replac ? replac : "NOT FOUND", - stat); - - /* should recover if stat == EX_TEMPFAIL */ - if (stat == EX_TEMPFAIL) - { - rstat = EX_TEMPFAIL; - if (tTd(60, 1)) - printf("map_lookup(%s, %s) tempfail: errno=%d\n", - mapname, buf, errno); - if (e->e_message == NULL) - { - char mbuf[300]; - - snprintf(mbuf, sizeof mbuf, - "%.80s map: lookup (%s): deferred", - mapname, - shortenstring(buf, 203)); - e->e_message = newstr(mbuf); - } - } - } - else - replac = NULL; + replac = map_lookup(map, buf, argvect, &rstat, e); /* if no replacement, use default */ if (replac == NULL && default_rvp != NULL) @@ -1273,38 +1243,16 @@ rewrite(pvp, ruleset, reclevel, e) ** Check for subroutine calls. */ - if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) - { - int stat; + stat = callsubr(npvp, reclevel, e); + if (rstat == EX_OK || stat == EX_TEMPFAIL) + rstat = stat; - if (npvp[1] == NULL) - { - syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", - ruleset, ruleno); - *pvp = NULL; - } - else - { - int ruleset; - STAB *s; - - bcopy((char *) &npvp[2], (char *) pvp, - (int) (avp - npvp - 2) * sizeof *avp); - if (tTd(21, 3)) - printf("-----callsubr %s\n", npvp[1]); - ruleset = strtorwset(npvp[1], NULL, ST_FIND); - stat = rewrite(pvp, ruleset, reclevel, e); - if (rstat == EX_OK || stat == EX_TEMPFAIL) - rstat = stat; - if (*pvp != NULL && (**pvp & 0377) == CANONNET) - rwr = NULL; - } - } - else - { - bcopy((char *) npvp, (char *) pvp, - (int) (avp - npvp) * sizeof *avp); - } + /* copy vector back into original space. */ + for (avp = npvp; *avp++ != NULL;) + continue; + bcopy((char *) npvp, (char *) pvp, + (int) (avp - npvp) * sizeof *avp); + if (tTd(21, 4)) { printf("rewritten as:"); @@ -1314,13 +1262,192 @@ rewrite(pvp, ruleset, reclevel, e) if (OpMode == MD_TEST || tTd(21, 1)) { - printf("rewrite: ruleset %2d returns:", ruleset); + printf("rewrite: ruleset %3d returns:", ruleset); printav(pvp); } return rstat; } /* +** CALLSUBR -- call subroutines in rewrite vector +** +** Parameters: +** pvp -- pointer to token vector. +** reclevel -- the current recursion level. +** e -- the current envelope. +** +** Returns: +** The status from the subroutine call. +** +** Side Effects: +** pvp is modified. +*/ + +int +callsubr(pvp, reclevel, e) + char **pvp; + int reclevel; + ENVELOPE *e; +{ + char **avp; + char **rvp; + register int i; + int subr; + int stat; + int rstat = EX_OK; + char *tpvp[MAXATOM + 1]; + + for (avp = pvp; *avp != NULL; avp++) + { + if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) + { + subr = strtorwset(avp[1], NULL, ST_FIND); + if (subr < 0) + { + syserr("Unknown ruleset %s", avp[1]); + return EX_CONFIG; + } + + if (tTd(21, 3)) + printf("-----callsubr %s (%d)\n", avp[1], subr); + + /* + ** Take care of possible inner calls first. + ** use a full size temporary buffer to avoid + ** overflows in rewrite, but strip off the + ** subroutine call. + */ + + for (i = 2; avp[i] != NULL; i++) + tpvp[i - 2] = avp[i]; + tpvp[i - 2] = NULL; + + stat = callsubr(tpvp, reclevel, e); + if (rstat == EX_OK || stat == EX_TEMPFAIL) + rstat = stat; + + /* + ** Now we need to call the ruleset specified for + ** the subroutine. we can do this with the + ** temporary buffer that we set up earlier, + ** since it has all the data we want to rewrite. + */ + + stat = rewrite(tpvp, subr, reclevel, e); + if (rstat == EX_OK || stat == EX_TEMPFAIL) + rstat = stat; + + /* + ** Find length of tpvp and current offset into + ** pvp, if the total is greater than MAXATOM, + ** then it would overflow the buffer if we copied + ** it back in to pvp, in which case we throw a + ** fit. + */ + + for (rvp = tpvp; *rvp != NULL; rvp++) + continue; + if (((rvp - tpvp) + (avp - pvp)) > MAXATOM) + { + syserr("554 callsubr: expansion too long"); + return EX_DATAERR; + } + + /* + ** Now we can copy the rewritten code over + ** the initial subroutine call in the buffer. + */ + + for (i = 0; tpvp[i] != NULL; i++) + avp[i] = tpvp[i]; + avp[i] = NULL; + + /* + ** If we got this far, we've processed the left + ** most subroutine, and recursively called ourselves + ** to handle any other subroutines. We're done. + */ + + break; + } + } + return rstat; +} +/* +** MAP_LOOKUP -- do lookup in map +** +** Parameters: +** map -- the map to use for the lookup. +** key -- the key to look up. +** argvect -- arguments to pass to the map lookup. +** pstat -- a pointer to an integer in which to store the +** status from the lookup. +** e -- the current envelope. +** +** Returns: +** The result of the lookup. +** NULL -- if there was no data for the given key. +*/ + +char * +map_lookup(map, key, argvect, pstat, e) + STAB *map; + char key[]; + char **argvect; + int *pstat; + ENVELOPE *e; +{ + auto int stat = EX_OK; + char *replac; + + if (e->e_sendmode == SM_DEFER) + { + /* don't do any map lookups */ + if (tTd(60, 1)) + printf("map_lookup(%s, %s) => DEFERRED\n", + map->s_name, key); + *pstat = EX_TEMPFAIL; + return NULL; + } + if (map == NULL || !bitset(MF_OPEN, map->s_map.map_mflags)) + return NULL; + + if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags)) + stripquotes(key); + + /* XXX should try to auto-open the map here */ + + if (tTd(60, 1)) + printf("map_lookup(%s, %s) => ", + map->s_name, key); + replac = (*map->s_map.map_class->map_lookup)(&map->s_map, + key, argvect, &stat); + if (tTd(60, 1)) + printf("%s (%d)\n", + replac != NULL ? replac : "NOT FOUND", + stat); + + /* should recover if stat == EX_TEMPFAIL */ + if (stat == EX_TEMPFAIL && !bitset(MF_NODEFER, map->s_map.map_mflags)) + { + *pstat = EX_TEMPFAIL; + if (tTd(60, 1)) + printf("map_lookup(%s, %s) tempfail: errno=%d\n", + map->s_name, key, errno); + if (e->e_message == NULL) + { + char mbuf[300]; + + snprintf(mbuf, sizeof mbuf, + "%.80s map: lookup (%s): deferred", + map->s_name, + shortenstring(key, 203)); + e->e_message = newstr(mbuf); + } + } + return replac; +} +/* ** BUILDADDR -- build address from token vector. ** ** Parameters: @@ -1345,17 +1472,17 @@ struct errcodes int ec_code; /* numeric code */ } ErrorCodes[] = { - "usage", EX_USAGE, - "nouser", EX_NOUSER, - "nohost", EX_NOHOST, - "unavailable", EX_UNAVAILABLE, - "software", EX_SOFTWARE, - "tempfail", EX_TEMPFAIL, - "protocol", EX_PROTOCOL, + { "usage", EX_USAGE }, + { "nouser", EX_NOUSER }, + { "nohost", EX_NOHOST }, + { "unavailable", EX_UNAVAILABLE }, + { "software", EX_SOFTWARE }, + { "tempfail", EX_TEMPFAIL }, + { "protocol", EX_PROTOCOL }, #ifdef EX_CONFIG - "config", EX_CONFIG, + { "config", EX_CONFIG }, #endif - NULL, EX_UNAVAILABLE, + { NULL, EX_UNAVAILABLE } }; ADDRESS * @@ -1386,7 +1513,7 @@ buildaddr(tv, a, flags, e) bzero((char *) a, sizeof *a); /* set up default error return flags */ - a->q_flags |= QPINGONFAILURE|QPINGONDELAY; + a->q_flags |= DefaultNotify; /* figure out what net/mailer to use */ if (*tv == NULL || (**tv & 0377) != CANONNET) @@ -1407,7 +1534,7 @@ badaddr: mname = *++tv; /* extract host and user portions */ - if ((**++tv & 0377) == CANONHOST) + if (*++tv != NULL && (**tv & 0377) == CANONHOST) hostp = ++tv; else hostp = NULL; @@ -1433,6 +1560,8 @@ badaddr: if (strchr(hbuf, '.') != NULL) { + extern int dsntoexitstat __P((char *)); + a->q_status = newstr(hbuf); setstat(dsntoexitstat(hbuf)); } @@ -1703,27 +1832,27 @@ struct qflags struct qflags AddressFlags[] = { - "QDONTSEND", QDONTSEND, - "QBADADDR", QBADADDR, - "QGOODUID", QGOODUID, - "QPRIMARY", QPRIMARY, - "QQUEUEUP", QQUEUEUP, - "QSENT", QSENT, - "QNOTREMOTE", QNOTREMOTE, - "QSELFREF", QSELFREF, - "QVERIFIED", QVERIFIED, - "QBOGUSSHELL", QBOGUSSHELL, - "QUNSAFEADDR", QUNSAFEADDR, - "QPINGONSUCCESS", QPINGONSUCCESS, - "QPINGONFAILURE", QPINGONFAILURE, - "QPINGONDELAY", QPINGONDELAY, - "QHASNOTIFY", QHASNOTIFY, - "QRELAYED", QRELAYED, - "QEXPANDED", QEXPANDED, - "QDELIVERED", QDELIVERED, - "QDELAYED", QDELAYED, - "QTHISPASS", QTHISPASS, - NULL + { "QDONTSEND", QDONTSEND }, + { "QBADADDR", QBADADDR }, + { "QGOODUID", QGOODUID }, + { "QPRIMARY", QPRIMARY }, + { "QQUEUEUP", QQUEUEUP }, + { "QSENT", QSENT }, + { "QNOTREMOTE", QNOTREMOTE }, + { "QSELFREF", QSELFREF }, + { "QVERIFIED", QVERIFIED }, + { "QBOGUSSHELL", QBOGUSSHELL }, + { "QUNSAFEADDR", QUNSAFEADDR }, + { "QPINGONSUCCESS", QPINGONSUCCESS }, + { "QPINGONFAILURE", QPINGONFAILURE }, + { "QPINGONDELAY", QPINGONDELAY }, + { "QHASNOTIFY", QHASNOTIFY }, + { "QRELAYED", QRELAYED }, + { "QEXPANDED", QEXPANDED }, + { "QDELIVERED", QDELIVERED }, + { "QDELAYED", QDELAYED }, + { "QTHISPASS", QTHISPASS }, + { NULL } }; void @@ -1781,10 +1910,14 @@ printaddr(a, follow) a->q_owner == NULL ? "(none)" : a->q_owner, a->q_home == NULL ? "(none)" : a->q_home, a->q_fullname == NULL ? "(none)" : a->q_fullname); - printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", + printf("\torcpt=\"%s\", statmta=%s, status=%s\n", a->q_orcpt == NULL ? "(none)" : a->q_orcpt, a->q_statmta == NULL ? "(none)" : a->q_statmta, + a->q_status == NULL ? "(none)" : a->q_status); + printf("\trstatus=\"%s\"\n", a->q_rstatus == NULL ? "(none)" : a->q_rstatus); + printf("\tspecificity=%d, statdate=%s\n", + a->q_specificity, ctime(&a->q_statdate)); if (!follow) return; @@ -1993,7 +2126,12 @@ maplocaluser(a, sendq, aliaslevel, e) if (pvp == NULL) return; - (void) rewrite(pvp, 5, 0, e); + if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL) + { + a->q_flags |= QQUEUEUP; + a->q_status = "4.4.3"; + return; + } if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) return; @@ -2154,5 +2292,111 @@ dequote_map(map, name, av, statp) quotemode || quotecnt <= 0 || spacecnt != 0) return NULL; *q++ = '\0'; - return name; + return map_rewrite(map, name, strlen(name), NULL); +} +/* +** RSCHECK -- check string(s) for validity using rewriting sets +** +** Parameters: +** rwset -- the rewriting set to use. +** p1 -- the first string to check. +** p2 -- the second string to check -- may be null. +** e -- the current envelope. +** +** Returns: +** EX_OK -- if the rwset doesn't resolve to $#error +** else -- the failure status (message printed) +*/ + +int +rscheck(rwset, p1, p2, e) + char *rwset; + char *p1; + char *p2; + ENVELOPE *e; +{ + char *buf; + int bufsize; + int saveexitstat; + int rstat; + char **pvp; + int rsno; + auto ADDRESS a1; + bool saveQuickAbort = QuickAbort; + char buf0[MAXLINE]; + char pvpbuf[PSBUFSIZE]; + extern char MsgBuf[]; + + if (tTd(48, 2)) + printf("rscheck(%s, %s, %s)\n", rwset, p1, + p2 == NULL ? "(NULL)" : p2); + + rsno = strtorwset(rwset, NULL, ST_FIND); + if (rsno < 0) + return EX_OK; + + if (p2 != NULL) + { + bufsize = strlen(p1) + strlen(p2) + 2; + if (bufsize > sizeof buf0) + buf = xalloc(bufsize); + else + { + buf = buf0; + bufsize = sizeof buf0; + } + (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); + } + else + { + bufsize = strlen(p1) + 1; + if (bufsize > sizeof buf0) + buf = xalloc(bufsize); + else + { + buf = buf0; + bufsize = sizeof buf0; + } + (void) snprintf(buf, bufsize, "%s", p1); + } + pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); + if (pvp == NULL) + { + rstat = EX_DATAERR; + goto finis; + } + (void) rewrite(pvp, rsno, 0, e); + if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || + pvp[1] == NULL || strcmp(pvp[1], "error") != 0) + return EX_OK; + + /* got an error -- process it */ + saveexitstat = ExitStat; + QuickAbort = FALSE; + (void) buildaddr(pvp, &a1, 0, e); + QuickAbort = saveQuickAbort; + rstat = ExitStat; + ExitStat = saveexitstat; + +#ifdef LOG + if (LogLevel >= 4) + { + if (p2 == NULL) + syslog(LOG_NOTICE, "Ruleset %s (%s) rejection: %s", + rwset, p1, MsgBuf); + else + syslog(LOG_NOTICE, "Ruleset %s (%s, %s) rejection: %s", + rwset, p1, p2, MsgBuf); + } +#endif + + if (QuickAbort) + longjmp(TopFrame, 2); + + /* clean up */ + finis: + setstat(rstat); + if (buf != buf0) + free(buf); + return rstat; } diff --git a/usr.sbin/sendmail/src/readcf.c b/usr.sbin/sendmail/src/readcf.c index b41c8ac..172e372 100644 --- a/usr.sbin/sendmail/src/readcf.c +++ b/usr.sbin/sendmail/src/readcf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)readcf.c 8.139 (Berkeley) 11/29/95"; +static char sccsid[] = "@(#)readcf.c 8.174 (Berkeley) 10/9/96"; #endif /* not lint */ # include "sendmail.h" @@ -112,10 +112,11 @@ readcf(cfname, safe, e) char exbuf[MAXLINE]; char pvpbuf[MAXLINE + MAXATOM]; static char *null_list[1] = { NULL }; - extern char *munchstring __P((char *, char **)); + extern char *munchstring __P((char *, char **, int)); extern void fileclass __P((int, char *, char *, bool, bool)); extern void toomany __P((int, int)); extern void translate_dollars __P((char *)); + extern void inithostmaps __P((void)); FileName = cfname; LineNumber = 0; @@ -246,10 +247,6 @@ readcf(cfname, safe, e) botch = "$?"; break; - case CONDELSE: - botch = "$|"; - break; - case CONDFI: botch = "$."; break; @@ -354,16 +351,17 @@ readcf(cfname, safe, e) rwp = RewriteRules[ruleset]; if (rwp != NULL) { + if (OpMode == MD_TEST || tTd(37, 1)) + printf("WARNING: Ruleset %s has multiple definitions\n", + &bp[1]); while (rwp->r_next != NULL) rwp = rwp->r_next; - fprintf(stderr, "WARNING: Ruleset %s redefined\n", - &bp[1]); } break; case 'D': /* macro definition */ mid = macid(&bp[1], &ep); - p = munchstring(ep, NULL); + p = munchstring(ep, NULL, '\0'); define(mid, newstr(p), e); break; @@ -441,6 +439,13 @@ readcf(cfname, safe, e) break; #endif +#ifdef SUN_EXTENSIONS + case 'L': /* lookup macro */ + case 'G': /* lookup class */ + /* reserved for Sun -- NIS+ database lookup */ + goto badline; +#endif + case 'M': /* define mailer */ makemailer(&bp[1]); break; @@ -499,6 +504,8 @@ readcf(cfname, safe, e) if (*ep++ == '/') { + extern bool setvendor __P((char *)); + /* extract vendor code */ for (p = ep; isascii(*p) && isalpha(*p); ) p++; @@ -837,13 +844,11 @@ makemailer(line) auto char *endp; extern int NextMailer; extern char **makeargv(); - extern char *munchstring(); + extern char *munchstring __P((char *, char **, int)); /* allocate a mailer and set up defaults */ m = (struct mailer *) xalloc(sizeof *m); bzero((char *) m, sizeof *m); - m->m_eol = "\n"; - m->m_uid = m->m_gid = 0; /* collect the mailer name */ for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) @@ -875,7 +880,7 @@ makemailer(line) p++; /* p now points to the field body */ - p = munchstring(p, &delimptr); + p = munchstring(p, &delimptr, ','); /* install the field into the mailer struct */ switch (fcode) @@ -1089,6 +1094,29 @@ makemailer(line) m->m_diagtype = "smtp"; } + if (m->m_eol == NULL) + { + char **pp; + + /* default for SMTP is \r\n; use \n for local delivery */ + for (pp = m->m_argv; *pp != NULL; pp++) + { + char *p; + + for (p = *pp; *p != '\0'; ) + { + if ((*p++ & 0377) == MACROEXPAND && *p == 'u') + break; + } + if (*p != '\0') + break; + } + if (*pp == NULL) + m->m_eol = "\r\n"; + else + m->m_eol = "\n"; + } + /* enter the mailer into the symbol table */ s = stab(m->m_name, ST_MAILER, ST_ENTER); if (s->s_mailer != NULL) @@ -1110,15 +1138,17 @@ makemailer(line) ** p -- the string to munch. ** delimptr -- if non-NULL, set to the pointer of the ** field delimiter character. +** delim -- the delimiter for the field. ** ** Returns: ** the munched string. */ char * -munchstring(p, delimptr) +munchstring(p, delimptr, delim) register char *p; char **delimptr; + int delim; { register char *q; bool backslash = FALSE; @@ -1157,7 +1187,7 @@ munchstring(p, delimptr) backslash = TRUE; else if (*p == '"') quotemode = !quotemode; - else if (quotemode || *p != ',') + else if (quotemode || *p != delim) *q++ = *p; else break; @@ -1322,17 +1352,17 @@ struct resolverflags long rf_bits; /* bits to set/clear */ } ResolverFlags[] = { - "debug", RES_DEBUG, - "aaonly", RES_AAONLY, - "usevc", RES_USEVC, - "primary", RES_PRIMARY, - "igntc", RES_IGNTC, - "recurse", RES_RECURSE, - "defnames", RES_DEFNAMES, - "stayopen", RES_STAYOPEN, - "dnsrch", RES_DNSRCH, - "true", 0, /* to avoid error on old syntax */ - NULL, 0 + { "debug", RES_DEBUG }, + { "aaonly", RES_AAONLY }, + { "usevc", RES_USEVC }, + { "primary", RES_PRIMARY }, + { "igntc", RES_IGNTC }, + { "recurse", RES_RECURSE }, + { "defnames", RES_DEFNAMES }, + { "stayopen", RES_STAYOPEN }, + { "dnsrch", RES_DNSRCH }, + { "true", 0 }, /* avoid error on old syntax */ + { NULL, 0 } }; #endif @@ -1344,108 +1374,112 @@ struct optioninfo bool o_safe; /* safe for random people to use */ } OptionTab[] = { - "SevenBitInput", '7', TRUE, + { "SevenBitInput", '7', TRUE }, #if MIME8TO7 - "EightBitMode", '8', TRUE, + { "EightBitMode", '8', TRUE }, #endif - "AliasFile", 'A', FALSE, - "AliasWait", 'a', FALSE, - "BlankSub", 'B', FALSE, - "MinFreeBlocks", 'b', TRUE, - "CheckpointInterval", 'C', TRUE, - "HoldExpensive", 'c', FALSE, - "AutoRebuildAliases", 'D', FALSE, - "DeliveryMode", 'd', TRUE, - "ErrorHeader", 'E', FALSE, - "ErrorMode", 'e', TRUE, - "TempFileMode", 'F', FALSE, - "SaveFromLine", 'f', FALSE, - "MatchGECOS", 'G', FALSE, - "HelpFile", 'H', FALSE, - "MaxHopCount", 'h', FALSE, - "ResolverOptions", 'I', FALSE, - "IgnoreDots", 'i', TRUE, - "ForwardPath", 'J', FALSE, - "SendMimeErrors", 'j', TRUE, - "ConnectionCacheSize", 'k', FALSE, - "ConnectionCacheTimeout", 'K', FALSE, - "UseErrorsTo", 'l', FALSE, - "LogLevel", 'L', FALSE, - "MeToo", 'm', TRUE, - "CheckAliases", 'n', FALSE, - "OldStyleHeaders", 'o', TRUE, - "DaemonPortOptions", 'O', FALSE, - "PrivacyOptions", 'p', TRUE, - "PostmasterCopy", 'P', FALSE, - "QueueFactor", 'q', FALSE, - "QueueDirectory", 'Q', FALSE, - "DontPruneRoutes", 'R', FALSE, - "Timeout", 'r', TRUE, - "StatusFile", 'S', FALSE, - "SuperSafe", 's', TRUE, - "QueueTimeout", 'T', FALSE, - "TimeZoneSpec", 't', FALSE, - "UserDatabaseSpec", 'U', FALSE, - "DefaultUser", 'u', FALSE, - "FallbackMXhost", 'V', FALSE, - "Verbose", 'v', TRUE, - "TryNullMXList", 'w', TRUE, - "QueueLA", 'x', FALSE, - "RefuseLA", 'X', FALSE, - "RecipientFactor", 'y', FALSE, - "ForkEachJob", 'Y', FALSE, - "ClassFactor", 'z', FALSE, - "RetryFactor", 'Z', FALSE, + { "AliasFile", 'A', FALSE }, + { "AliasWait", 'a', FALSE }, + { "BlankSub", 'B', FALSE }, + { "MinFreeBlocks", 'b', TRUE }, + { "CheckpointInterval", 'C', TRUE }, + { "HoldExpensive", 'c', FALSE }, + { "AutoRebuildAliases", 'D', FALSE }, + { "DeliveryMode", 'd', TRUE }, + { "ErrorHeader", 'E', FALSE }, + { "ErrorMode", 'e', TRUE }, + { "TempFileMode", 'F', FALSE }, + { "SaveFromLine", 'f', FALSE }, + { "MatchGECOS", 'G', FALSE }, + { "HelpFile", 'H', FALSE }, + { "MaxHopCount", 'h', FALSE }, + { "ResolverOptions", 'I', FALSE }, + { "IgnoreDots", 'i', TRUE }, + { "ForwardPath", 'J', FALSE }, + { "SendMimeErrors", 'j', TRUE }, + { "ConnectionCacheSize", 'k', FALSE }, + { "ConnectionCacheTimeout", 'K', FALSE }, + { "UseErrorsTo", 'l', FALSE }, + { "LogLevel", 'L', TRUE }, + { "MeToo", 'm', TRUE }, + { "CheckAliases", 'n', FALSE }, + { "OldStyleHeaders", 'o', TRUE }, + { "DaemonPortOptions", 'O', FALSE }, + { "PrivacyOptions", 'p', TRUE }, + { "PostmasterCopy", 'P', FALSE }, + { "QueueFactor", 'q', FALSE }, + { "QueueDirectory", 'Q', FALSE }, + { "DontPruneRoutes", 'R', FALSE }, + { "Timeout", 'r', FALSE }, + { "StatusFile", 'S', FALSE }, + { "SuperSafe", 's', TRUE }, + { "QueueTimeout", 'T', FALSE }, + { "TimeZoneSpec", 't', FALSE }, + { "UserDatabaseSpec", 'U', FALSE }, + { "DefaultUser", 'u', FALSE }, + { "FallbackMXhost", 'V', FALSE }, + { "Verbose", 'v', TRUE }, + { "TryNullMXList", 'w', TRUE }, + { "QueueLA", 'x', FALSE }, + { "RefuseLA", 'X', FALSE }, + { "RecipientFactor", 'y', FALSE }, + { "ForkEachJob", 'Y', FALSE }, + { "ClassFactor", 'z', FALSE }, + { "RetryFactor", 'Z', FALSE }, #define O_QUEUESORTORD 0x81 - "QueueSortOrder", O_QUEUESORTORD, TRUE, + { "QueueSortOrder", O_QUEUESORTORD, TRUE }, #define O_HOSTSFILE 0x82 - "HostsFile", O_HOSTSFILE, FALSE, + { "HostsFile", O_HOSTSFILE, FALSE }, #define O_MQA 0x83 - "MinQueueAge", O_MQA, TRUE, -#define O_MHSA 0x84 -/* - "MaxHostStatAge", O_MHSA, TRUE, -*/ + { "MinQueueAge", O_MQA, TRUE }, #define O_DEFCHARSET 0x85 - "DefaultCharSet", O_DEFCHARSET, TRUE, + { "DefaultCharSet", O_DEFCHARSET, TRUE }, #define O_SSFILE 0x86 - "ServiceSwitchFile", O_SSFILE, FALSE, + { "ServiceSwitchFile", O_SSFILE, FALSE }, #define O_DIALDELAY 0x87 - "DialDelay", O_DIALDELAY, TRUE, + { "DialDelay", O_DIALDELAY, TRUE }, #define O_NORCPTACTION 0x88 - "NoRecipientAction", O_NORCPTACTION, TRUE, + { "NoRecipientAction", O_NORCPTACTION, TRUE }, #define O_SAFEFILEENV 0x89 - "SafeFileEnvironment", O_SAFEFILEENV, FALSE, + { "SafeFileEnvironment", O_SAFEFILEENV, FALSE }, #define O_MAXMSGSIZE 0x8a - "MaxMessageSize", O_MAXMSGSIZE, FALSE, + { "MaxMessageSize", O_MAXMSGSIZE, FALSE }, #define O_COLONOKINADDR 0x8b - "ColonOkInAddr", O_COLONOKINADDR, TRUE, + { "ColonOkInAddr", O_COLONOKINADDR, TRUE }, #define O_MAXQUEUERUN 0x8c - "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, + { "MaxQueueRunSize", O_MAXQUEUERUN, TRUE }, #define O_MAXCHILDREN 0x8d -/* - "MaxDaemonChildren", O_MAXCHILDREN, FALSE, -*/ + { "MaxDaemonChildren", O_MAXCHILDREN, FALSE }, #define O_KEEPCNAMES 0x8e - "DontExpandCnames", O_KEEPCNAMES, FALSE, + { "DontExpandCnames", O_KEEPCNAMES, FALSE }, #define O_MUSTQUOTE 0x8f -/* - "MustQuoteChars", O_MUSTQUOTE, FALSE, -*/ + { "MustQuoteChars", O_MUSTQUOTE, FALSE }, #define O_SMTPGREETING 0x90 - "SmtpGreetingMessage", O_SMTPGREETING, FALSE, + { "SmtpGreetingMessage", O_SMTPGREETING, FALSE }, #define O_UNIXFROM 0x91 - "UnixFromLine", O_UNIXFROM, FALSE, + { "UnixFromLine", O_UNIXFROM, FALSE }, #define O_OPCHARS 0x92 - "OperatorChars", O_OPCHARS, FALSE, + { "OperatorChars", O_OPCHARS, FALSE }, #define O_DONTINITGRPS 0x93 - "DontInitGroups", O_DONTINITGRPS, TRUE, + { "DontInitGroups", O_DONTINITGRPS, TRUE }, #define O_SLFH 0x94 -#ifdef LOTUS_NOTES_HACK - "SingleLineFromHeader", O_SLFH, TRUE, -#endif - - NULL, '\0', FALSE, + { "SingleLineFromHeader", O_SLFH, TRUE }, +#define O_ABH 0x95 + { "AllowBogusHELO", O_ABH, TRUE }, +#define O_CONNTHROT 0x97 + { "ConnectionRateThrottle", O_CONNTHROT, FALSE }, +#define O_UGW 0x99 + { "UnsafeGroupWrites", O_UGW, FALSE }, +#define O_DBLBOUNCE 0x9a + { "DoubleBounceAddress", O_DBLBOUNCE, FALSE }, +#define O_HSDIR 0x9b + { "HostStatusDirectory", O_HSDIR, FALSE }, +#define O_SINGTHREAD 0x9c + { "SingleThreadDelivery", O_SINGTHREAD, FALSE }, +#define O_RUNASUSER 0x9d + { "RunAsUser", O_RUNASUSER, FALSE }, + + { NULL, '\0', FALSE } }; @@ -1461,12 +1495,18 @@ setoption(opt, val, safe, sticky, e) register char *p; register struct optioninfo *o; char *subopt; + int mid; + auto char *ep; char buf[50]; extern bool atobool(); extern time_t convtime(); extern int QueueLA; extern int RefuseLA; extern bool Warn_Q_option; + extern void setalias __P((char *)); + extern int atooct __P((char *)); + extern void setdefuser __P((void)); + extern void setdaemonoptions __P((char *)); errno = 0; if (opt == ' ') @@ -1843,10 +1883,11 @@ setoption(opt, val, safe, sticky, e) break; case 'M': /* define macro */ - p = newstr(&val[1]); + mid = macid(val, &ep); + p = newstr(ep); if (!safe) cleanstrcpy(p, p, MAXNAME); - define(val[0], p, CurEnv); + define(mid, p, CurEnv); sticky = FALSE; break; @@ -1986,6 +2027,14 @@ setoption(opt, val, safe, sticky, e) DefGid = pw->pw_gid; } } + +#ifdef UID_MAX + if (DefUid > UID_MAX) + { + syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", + DefUid, UID_MAX); + } +#endif setdefuser(); /* handle the group if it is there */ @@ -1995,7 +2044,8 @@ setoption(opt, val, safe, sticky, e) goto g_opt; case 'V': /* fallback MX host */ - FallBackMX = newstr(val); + if (val[0] != '\0') + FallBackMX = newstr(val); break; case 'v': /* run in verbose mode */ @@ -2045,6 +2095,11 @@ setoption(opt, val, safe, sticky, e) QueueSortOrder = QS_BYPRIORITY; break; + case 't': /* Submission time */ + case 'T': + QueueSortOrder = QS_BYTIME; + break; + default: syserr("Invalid queue sort order \"%s\"", val); } @@ -2058,10 +2113,6 @@ setoption(opt, val, safe, sticky, e) MinQueueAge = convtime(val, 'm'); break; - case O_MHSA: /* maximum age of cached host status */ - MaxHostStatAge = convtime(val, 'm'); - break; - case O_DEFCHARSET: /* default character set for mimefying */ DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); break; @@ -2115,21 +2166,21 @@ setoption(opt, val, safe, sticky, e) case O_MUSTQUOTE: /* must quote these characters in phrases */ strcpy(buf, "@,;:\\()[]"); - if (strlen(val) < sizeof buf - 10) + if (strlen(val) < (SIZE_T) sizeof buf - 10) strcat(buf, val); MustQuoteChars = newstr(buf); break; case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ - SmtpGreeting = newstr(munchstring(val, NULL)); + SmtpGreeting = newstr(munchstring(val, NULL, '\0')); break; case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ - UnixFromLine = newstr(munchstring(val, NULL)); + UnixFromLine = newstr(munchstring(val, NULL, '\0')); break; case O_OPCHARS: /* operator characters (old $o macro) */ - OperatorChars = newstr(munchstring(val, NULL)); + OperatorChars = newstr(munchstring(val, NULL, '\0')); break; case O_DONTINITGRPS: /* don't call initgroups(3) */ @@ -2140,6 +2191,75 @@ setoption(opt, val, safe, sticky, e) SingleLineFromHeader = atobool(val); break; + case O_ABH: /* allow HELO commands with syntax errors */ + AllowBogusHELO = atobool(val); + break; + + case O_CONNTHROT: /* connection rate throttle */ + ConnRateThrottle = atoi(val); + break; + + case O_UGW: /* group writable files are unsafe */ + UnsafeGroupWrites = atobool(val); + break; + + case O_DBLBOUNCE: /* address to which to send double bounces */ + if (val[0] != '\0') + DoubleBounceAddr = newstr(val); + else + syserr("readcf: option DoubleBounceAddress: value required"); + break; + + case O_HSDIR: /* persistent host status directory */ + if (val[0] != '\0') + HostStatDir = newstr(val); + break; + + case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ + SingleThreadDelivery = atobool(val); + break; + + case O_RUNASUSER: /* run bulk of code as this user */ + for (p = val; *p != '\0'; p++) + { + if (*p == '.' || *p == '/' || *p == ':') + { + *p++ = '\0'; + break; + } + } + if (isascii(*val) && isdigit(*val)) + RunAsUid = atoi(val); + else + { + register struct passwd *pw; + + pw = sm_getpwnam(val); + if (pw == NULL) + syserr("readcf: option RunAsUser: unknown user %s", val); + else + { + RunAsUid = pw->pw_uid; + RunAsGid = pw->pw_gid; + } + } + if (*p == '\0') + break; + if (isascii(*p) && isdigit(*p)) + DefGid = atoi(p); + else + { + register struct group *gr; + + gr = getgrnam(p); + if (gr == NULL) + syserr("readcf: option RunAsUser: unknown group %s", + p); + else + RunAsGid = gr->gr_gid; + } + break; + default: if (tTd(37, 1)) { @@ -2249,7 +2369,7 @@ makemapentry(line) if (tTd(37, 5)) { - printf("map %s, class %s, flags %x, file %s,\n", + printf("map %s, class %s, flags %lx, file %s,\n", s->s_map.map_mname, s->s_map.map_class->map_cname, s->s_map.map_mflags, s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); @@ -2327,10 +2447,7 @@ strtorwset(p, endp, stabmode) *p = delim; if (s == NULL) - { - syserr("unknown ruleset %s", q); return -1; - } if (stabmode == ST_ENTER && delim == '=') { @@ -2368,7 +2485,7 @@ strtorwset(p, endp, stabmode) if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) { syserr("%s: ruleset changed value (old %d, new %d)", - q, ruleset, s->s_ruleset); + q, s->s_ruleset, ruleset); ruleset = s->s_ruleset; } else if (ruleset > 0) @@ -2403,6 +2520,8 @@ inittimeouts(val) register char *p; extern time_t convtime(); + if (tTd(37, 2)) + printf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); if (val == NULL) { TimeOuts.to_connect = (time_t) 0 SECONDS; @@ -2423,6 +2542,24 @@ inittimeouts(val) TimeOuts.to_ident = (time_t) 0 SECONDS; #endif TimeOuts.to_fileopen = (time_t) 60 SECONDS; + if (tTd(37, 5)) + { + printf("Timeouts:\n"); + printf(" connect = %ld\n", TimeOuts.to_connect); + printf(" initial = %ld\n", TimeOuts.to_initial); + printf(" helo = %ld\n", TimeOuts.to_helo); + printf(" mail = %ld\n", TimeOuts.to_mail); + printf(" rcpt = %ld\n", TimeOuts.to_rcpt); + printf(" datainit = %ld\n", TimeOuts.to_datainit); + printf(" datablock = %ld\n", TimeOuts.to_datablock); + printf(" datafinal = %ld\n", TimeOuts.to_datafinal); + printf(" rset = %ld\n", TimeOuts.to_rset); + printf(" quit = %ld\n", TimeOuts.to_quit); + printf(" nextcommand = %ld\n", TimeOuts.to_nextcommand); + printf(" miscshort = %ld\n", TimeOuts.to_miscshort); + printf(" ident = %ld\n", TimeOuts.to_ident); + printf(" fileopen = %ld\n", TimeOuts.to_fileopen); + } return; } @@ -2482,6 +2619,9 @@ settimeout(name, val) time_t to; extern time_t convtime(); + if (tTd(37, 2)) + printf("settimeout(%s = %s)\n", name, val); + to = convtime(val, 'm'); p = strchr(name, '.'); if (p != NULL) @@ -2515,6 +2655,8 @@ settimeout(name, val) TimeOuts.to_fileopen = to; else if (strcasecmp(name, "connect") == 0) TimeOuts.to_connect = to; + else if (strcasecmp(name, "iconnect") == 0) + TimeOuts.to_iconnect = to; else if (strcasecmp(name, "queuewarn") == 0) { to = convtime(val, 'h'); @@ -2551,6 +2693,8 @@ settimeout(name, val) else syserr("settimeout: invalid queuereturn subtimeout %s", p); } + else if (strcasecmp(name, "hoststatus") == 0) + MciInfoTimeout = convtime(val, 'm'); else syserr("settimeout: invalid timeout %s", name); } diff --git a/usr.sbin/sendmail/src/recipient.c b/usr.sbin/sendmail/src/recipient.c index 4675247..dae5156 100644 --- a/usr.sbin/sendmail/src/recipient.c +++ b/usr.sbin/sendmail/src/recipient.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)recipient.c 8.108.1.1 (Berkeley) 9/12/96"; +static char sccsid[] = "@(#)recipient.c 8.116 (Berkeley) 8/17/96"; #endif /* not lint */ # include "sendmail.h" @@ -241,7 +241,7 @@ recipient(a, sendq, aliaslevel, e) int i; char *buf; char buf0[MAXNAME + 1]; /* unquoted image of the user name */ - extern int safefile(); + extern void alias __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); e->e_to = a->q_paddr; m = a->q_mailer; @@ -267,7 +267,7 @@ recipient(a, sendq, aliaslevel, e) if (aliaslevel > MaxAliasRecursion) { a->q_status = "5.4.6"; - usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max", + usrerr("554 aliasing/forwarding loop broken (%d aliases deep; %d max)", aliaslevel, MaxAliasRecursion); return (a); } @@ -482,6 +482,8 @@ recipient(a, sendq, aliaslevel, e) ConfigLevel >= 2 && RewriteRules[5] != NULL && bitnset(M_TRYRULESET5, m->m_flags)) { + extern void maplocaluser __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); + maplocaluser(a, sendq, aliaslevel + 1, e); } @@ -495,7 +497,7 @@ recipient(a, sendq, aliaslevel, e) { auto bool fuzzy; register struct passwd *pw; - extern struct passwd *finduser(); + extern void forward __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); /* warning -- finduser may trash buf */ pw = finduser(buf, &fuzzy); @@ -738,8 +740,7 @@ finduser(name, fuzzyp) { if (tTd(29, 4)) printf("found (case wrapped)\n"); - *fuzzyp = TRUE; - return pw; + break; } # endif @@ -749,17 +750,22 @@ finduser(name, fuzzyp) if (tTd(29, 4)) printf("fuzzy matches %s\n", pw->pw_name); message("sending to login name %s", pw->pw_name); - *fuzzyp = TRUE; - return (pw); + break; } } - if (tTd(29, 4)) + if (pw != NULL) + *fuzzyp = TRUE; + else if (tTd(29, 4)) printf("no fuzzy match found\n"); +# if DEC_OSF_BROKEN_GETPWENT /* DEC OSF/1 3.2 or earlier */ + endpwent(); +# endif + return pw; #else if (tTd(29, 4)) printf("not found (fuzzy disabled)\n"); + return NULL; #endif - return (NULL); } /* ** WRITABLE -- predicate returning if the file is writable. @@ -1122,19 +1128,21 @@ resetuid: /* ** Check to see if some bad guy can write this file ** - ** This should really do something clever with group - ** permissions; currently we just view world writable - ** as unsafe. Also, we don't check for writable + ** Group write checking could be more clever, e.g., + ** guessing as to which groups are actually safe ("sys" + ** may be; "user" probably is not). + ** Also, we don't check for writable ** directories in the path. We've got to leave ** something for the local sysad to do. */ - if (bitset(S_IWOTH, st.st_mode)) + if (bitset(S_IWOTH | (UnsafeGroupWrites ? S_IWGRP : 0), st.st_mode)) { #ifdef LOG if (LogLevel >= 12) - syslog(LOG_INFO, "%s: world writable %s file, marked unsafe", + syslog(LOG_INFO, "%s: %s writable %s file, marked unsafe", shortenstring(fname, 203), + bitset(S_IWOTH, st.st_mode) ? "world" : "group", forwarding ? "forward" : ":include:"); #endif ctladdr->q_flags |= QUNSAFEADDR; diff --git a/usr.sbin/sendmail/src/savemail.c b/usr.sbin/sendmail/src/savemail.c index 80639b1..baa1a04 100644 --- a/usr.sbin/sendmail/src/savemail.c +++ b/usr.sbin/sendmail/src/savemail.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)savemail.c 8.87.1.2 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)savemail.c 8.100 (Berkeley) 9/27/96"; #endif /* not lint */ # include "sendmail.h" @@ -86,7 +86,7 @@ savemail(e, sendbody) auto ADDRESS *q = NULL; register char *p; MCI mcibuf; - int sfflags; + int flags; char buf[MAXLINE+1]; extern char *ttypath(); typedef int (*fnptr)(); @@ -283,7 +283,9 @@ savemail(e, sendbody) break; } if (returntosender(e->e_message, e->e_errorqueue, - sendbody, e) == 0) + sendbody ? RTSF_SEND_BODY + : RTSF_NO_BODY, + e) == 0) { state = ESM_DONE; break; @@ -299,14 +301,17 @@ savemail(e, sendbody) */ q = NULL; - if (sendtolist("postmaster", NULL, &q, 0, e) <= 0) + if (sendtolist(DoubleBounceAddr, NULL, &q, 0, e) <= 0) { - syserr("553 cannot parse postmaster!"); + syserr("553 cannot parse %s!", DoubleBounceAddr); ExitStat = EX_SOFTWARE; state = ESM_USRTMP; break; } - if (returntosender(e->e_message, q, sendbody, e) == 0) + flags = RTSF_PM_BOUNCE; + if (sendbody) + flags |= RTSF_SEND_BODY; + if (returntosender(e->e_message, q, flags, e) == 0) { state = ESM_DONE; break; @@ -344,9 +349,9 @@ savemail(e, sendbody) /* we have a home directory; write dead.letter */ define('z', p, e); expand("\201z/dead.letter", buf, sizeof buf, e); - sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; + flags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; e->e_to = buf; - if (mailfile(buf, NULL, sfflags, e) == EX_OK) + if (mailfile(buf, NULL, flags, e) == EX_OK) { bool oldverb = Verbose; @@ -378,10 +383,10 @@ savemail(e, sendbody) snprintf(buf, sizeof buf, "%sdead.letter", _PATH_VARTMP); - sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT; - if (!writable(buf, NULL, sfflags) || + flags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT; + if (!writable(buf, NULL, flags) || (fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND, - FileMode, sfflags)) == NULL) + FileMode, flags)) == NULL) { state = ESM_PANIC; break; @@ -398,7 +403,9 @@ savemail(e, sendbody) (*e->e_putbody)(&mcibuf, e, NULL); putline("\n", &mcibuf); (void) fflush(fp); - if (!ferror(fp)) + if (ferror(fp)) + state = ESM_PANIC; + else { bool oldverb = Verbose; @@ -410,9 +417,7 @@ savemail(e, sendbody) syslog(LOG_NOTICE, "Saved message in %s", buf); #endif state = ESM_DONE; - break; } - state = ESM_PANIC; (void) xfclose(fp, "savemail", buf); break; @@ -434,8 +439,10 @@ savemail(e, sendbody) ** Parameters: ** msg -- the explanatory message. ** returnq -- the queue of people to send the message to. -** sendbody -- if TRUE, also send back the body of the -** message; otherwise just send the header. +** flags -- flags tweaking the operation: +** RTSF_SENDBODY -- include body of message (otherwise +** just send the header). +** RTSF_PMBOUNCE -- this is a postmaster bounce. ** e -- the current envelope. ** ** Returns: @@ -451,10 +458,10 @@ savemail(e, sendbody) #define ERRORFUDGE 100 /* nominal size of error message text */ int -returntosender(msg, returnq, sendbody, e) +returntosender(msg, returnq, flags, e) char *msg; ADDRESS *returnq; - bool sendbody; + int flags; register ENVELOPE *e; { register ENVELOPE *ee; @@ -509,16 +516,21 @@ returntosender(msg, returnq, sendbody, e) ee->e_flags &= ~EF_OLDSTYLE; ee->e_sendqueue = returnq; ee->e_msgsize = ERRORFUDGE; - if (sendbody) + if (bitset(RTSF_SEND_BODY, flags)) ee->e_msgsize += e->e_msgsize; else ee->e_flags |= EF_NO_BODY_RETN; initsys(ee); for (q = returnq; q != NULL; q = q->q_next) { + extern bool pruneroute __P((char *)); + if (bitset(QBADADDR, q->q_flags)) continue; + q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); + q->q_flags |= QPINGONFAILURE; + if (!DontPruneRoutes && pruneroute(q->q_paddr)) { register ADDRESS *p; @@ -543,8 +555,10 @@ returntosender(msg, returnq, sendbody, e) { if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags)) p = "return to sender"; - else + else if (bitset(RTSF_PM_BOUNCE, flags)) p = "postmaster notify"; + else + p = "DSN"; syslog(LOG_INFO, "%s: %s: %s: %s", e->e_id, ee->e_id, p, shortenstring(msg, 203)); } @@ -589,6 +603,13 @@ returntosender(msg, returnq, sendbody, e) addheader("Subject", msg, &ee->e_header); p = "return-receipt"; } + else if (bitset(RTSF_PM_BOUNCE, flags)) + { + snprintf(buf, sizeof buf, "Postmaster notify: %.*s", + sizeof buf - 20, msg); + addheader("Subject", buf, &ee->e_header); + p = "postmaster-notification"; + } else { snprintf(buf, sizeof buf, "Returned mail: %.*s", @@ -608,6 +629,8 @@ returntosender(msg, returnq, sendbody, e) returndepth--; return (-1); } + ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS); + ee->e_from.q_flags |= QPINGONFAILURE; ee->e_sender = ee->e_from.q_paddr; /* push state into submessage */ @@ -623,7 +646,7 @@ returntosender(msg, returnq, sendbody, e) sendall(ee, SM_DEFAULT); /* restore state */ - dropenvelope(ee); + dropenvelope(ee, TRUE); CurEnv = oldcur; returndepth--; @@ -647,7 +670,6 @@ returntosender(msg, returnq, sendbody, e) ** mci -- the mailer connection information. ** e -- the envelope we are working in. ** separator -- any possible MIME separator. -** flags -- to modify the behaviour. ** ** Returns: ** none @@ -667,8 +689,8 @@ errbody(mci, e, separator) register ADDRESS *q; bool printheader; bool sendbody; + bool pm_notify; char buf[MAXLINE]; - extern char *xuntextify(); if (bitset(MCIF_INHEADER, mci->mci_flags)) { @@ -699,10 +721,17 @@ errbody(mci, e, separator) ** Output introductory information. */ - for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) - if (bitset(QBADADDR, q->q_flags)) - break; - if (q == NULL && + pm_notify = FALSE; + p = hvalue("subject", e->e_header); + if (p != NULL && strncmp(p, "Postmaster ", 11) == 0) + pm_notify = TRUE; + else + { + for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) + if (bitset(QBADADDR, q->q_flags)) + break; + } + if (!pm_notify && q == NULL && !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) { putline(" **********************************************", @@ -757,16 +786,63 @@ errbody(mci, e, separator) printheader = TRUE; for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) { - if (bitset(QBADADDR, q->q_flags)) + if (!bitset(QBADADDR, q->q_flags) || + !bitset(QPINGONFAILURE, q->q_flags)) + continue; + + if (printheader) { - if (!bitset(QPINGONFAILURE, q->q_flags)) - continue; - p = "unrecoverable error"; + putline(" ----- The following addresses had permanent fatal errors -----", + mci); + printheader = FALSE; } - else if (!bitset(QPRIMARY, q->q_flags)) + + snprintf(buf, sizeof buf, "%s", shortenstring(q->q_paddr, 203)); + putline(buf, mci); + if (q->q_alias != NULL) + { + snprintf(buf, sizeof buf, " (expanded from: %s)", + shortenstring(q->q_alias->q_paddr, 203)); + putline(buf, mci); + } + } + if (!printheader) + putline("", mci); + + printheader = TRUE; + for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) + { + if (bitset(QBADADDR, q->q_flags) || + !bitset(QPRIMARY, q->q_flags) || + !bitset(QDELAYED, q->q_flags)) + continue; + + if (printheader) + { + putline(" ----- The following addresses had transient non-fatal errors -----", + mci); + printheader = FALSE; + } + + snprintf(buf, sizeof buf, "%s", shortenstring(q->q_paddr, 203)); + putline(buf, mci); + if (q->q_alias != NULL) + { + snprintf(buf, sizeof buf, " (expanded from: %s)", + shortenstring(q->q_alias->q_paddr, 203)); + putline(buf, mci); + } + } + if (!printheader) + putline("", mci); + + printheader = TRUE; + for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) + { + if (bitset(QBADADDR, q->q_flags) || + !bitset(QPRIMARY, q->q_flags) || + bitset(QDELAYED, q->q_flags)) continue; - else if (bitset(QDELAYED, q->q_flags)) - p = "transient failure"; else if (!bitset(QPINGONSUCCESS, q->q_flags)) continue; else if (bitset(QRELAYED, q->q_flags)) @@ -785,7 +861,7 @@ errbody(mci, e, separator) if (printheader) { - putline(" ----- The following addresses have delivery notifications -----", + putline(" ----- The following addresses had successful delivery notifications -----", mci); printheader = FALSE; } @@ -801,7 +877,7 @@ errbody(mci, e, separator) } } if (!printheader) - putline("\n", mci); + putline("", mci); /* ** Output transcript of errors @@ -1164,14 +1240,16 @@ smtptodsn(smtpstat) ** ** Parameters: ** t -- the text to convert. +** taboo -- additional characters that must be encoded. ** ** Returns: ** The xtext-ified version of the same string. */ char * -xtextify(t) +xtextify(t, taboo) register char *t; + char *taboo; { register char *p; int l; @@ -1179,6 +1257,9 @@ xtextify(t) static char *bp = NULL; static int bplen = 0; + if (taboo == NULL) + taboo = ""; + /* figure out how long this xtext will have to be */ nbogus = l = 0; for (p = t; *p != '\0'; p++) @@ -1186,7 +1267,8 @@ xtextify(t) register int c = (*p & 0xff); /* ASCII dependence here -- this is the way the spec words it */ - if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') + if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || + strchr(taboo, c) != NULL) nbogus++; l++; } @@ -1209,7 +1291,8 @@ xtextify(t) register int c = (*t++ & 0xff); /* ASCII dependence here -- this is the way the spec words it */ - if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') + if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' || + strchr(taboo, c) != NULL) { *p++ = '+'; *p++ = "0123456789abcdef"[c >> 4]; @@ -1298,6 +1381,7 @@ xuntextify(t) c -= 'a' - 10; *p++ |= c; } + *p = '\0'; return bp; } /* diff --git a/usr.sbin/sendmail/src/sendmail.8 b/usr.sbin/sendmail/src/sendmail.8 index 58060de..34c3f44 100644 --- a/usr.sbin/sendmail/src/sendmail.8 +++ b/usr.sbin/sendmail/src/sendmail.8 @@ -29,14 +29,14 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)sendmail.8 8.6 (Berkeley) 5/27/95 +.\" @(#)sendmail.8 8.10 (Berkeley) 9/20/96 .\" -.Dd May 27, 1995 +.Dd September 20, 1996 .Dt SENDMAIL 8 .Os BSD 4 .Sh NAME .Nm sendmail -.Nd send mail over the internet +.Nd an electronic mail transport agent .Sh SYNOPSIS .Nm sendmail .Op Ar flags @@ -108,6 +108,14 @@ listening on socket 25 for incoming connections. This is normally run from .Pa /etc/rc . +.It Fl bD +Same as +.Fl bd +except runs in foreground. +.It Fl bh +Print the persistent host status database. +.It Fl bH +Purge the persistent host status database. .It Fl bi Initialize the alias database. .It Fl bm @@ -165,14 +173,41 @@ the mail is returned with an error message, the victim of an aliasing loop. If not specified, ``Received:'' lines in the message are counted. +.It Fl i +Ignore dots alone on lines by themselves in incoming messages. +This should be set if you are reading data from a file. +.It Fl N Ar dsn +Set delivery status notification conditions to +.Ar dsn, +which can be +.Ql never +for no notifications +or a comma separated list of the values +.Ql failure +to be notified if delivery failed, +.Ql delay +to be notified if delivery is delayed, and +.Ql success +to be notified when the message is successfully delivered. .It Fl n Don't do aliasing. +.It Fl O Ar option Ns = Ns Em value +Set option +.Ar option +to the specified +.Em value . +This form uses long names. +See below for more details. .It Fl o Ns Ar x Em value Set option .Ar x to the specified .Em value . -Options are described below. +This form uses single character names only. +The short names are not described in this manual page; +see the +.%T "Sendmail Installation and Operation Guide" +for details. .It Fl p Ns Ar protocol Set the name of the protocol used to receive the message. This can be a simple protocol name such as ``UUCP'' @@ -221,6 +256,16 @@ as a substring of one of the recipients. Limit processed jobs to those containing .Ar substr as a substring of the sender. +.It Fl R Ar return +Set the amount of the message to be returned +if the message bounces. +The +.Ar return +parameter can be +.Ql full +to return the entire message or +.Ql hdrs +to return only the headers. .It Fl r Ns Ar name An alternate and obsolete form of the .Fl f @@ -234,6 +279,22 @@ that is, they will .Em not receive copies even if listed in the message header. +.It Fl U +Initial (user) submission. +This should +.Em always +be set when called from a user agent such as +.Nm Mail +or +.Nm exmh +and +.Em never +be set when called by a network delivery agent such as +.Nm rmail . +.It Fl V Ar envid +Set the original envelope id. +This is propogated across SMTP to servers that support DSNs +and is returned in DSN-compliant error messages. .It Fl v Go into verbose mode. Alias expansions will be announced, etc. @@ -249,22 +310,25 @@ Normally these will only be used by a system administrator. Options may be set either on the command line using the .Fl o -flag +flag (for short names), +the +.Fl O +flag (for long names), or in the configuration file. -This is a partial list; +This is a partial list limited to those options that are likely to be useful +on the command line +and only shows the long names; for a complete list (and details), consult the .%T "Sendmail Installation and Operation Guide" . The options are: .Bl -tag -width Fl -.It Li A Ns Ar file +.It Li AliasFile= Ns Ar file Use alternate alias file. -.It Li b Ns Ar nblocks -The minimum number of free blocks needed on the spool filesystem. -.It Li c +.It Li HoldExpensive On mailers that are considered ``expensive'' to connect to, don't initiate immediate connection. This requires queueing. -.It Li C Ar N +.It Li CheckpointInterval= Ns Ar N Checkpoint the queue file after every .Ar N successful deliveries (default 10). @@ -272,7 +336,7 @@ This avoids excessive duplicate deliveries when sending to long mailing lists interrupted by system crashes. .ne 1i -.It Li d Ns Ar x +.It Li DeliveryMode= Ns Ar x Set the delivery mode to .Ar x . Delivery modes are @@ -280,14 +344,14 @@ Delivery modes are for interactive (synchronous) delivery, .Ql b for background (asynchronous) delivery, -and .Ql q for queue only \- i.e., -actual delivery is done the next time the queue is run. -.It Li D -Try to automatically rebuild the alias database -if necessary. -.It Li e Ns Ar x +actual delivery is done the next time the queue is run, and +.Ql d +for deferred \- the same as +.Ql q +except that database lookups (notably DNS and NIS lookups) are avoided. +.It Li ErrorMode= Ns Ar x Set error processing to mode .Ar x . Valid modes are @@ -315,41 +379,33 @@ and if the sender is local to this machine, a copy of the message is appended to the file .Pa dead.letter in the sender's home directory. -.It Li f +.It Li SaveFromLine Save .Tn UNIX Ns \-style From lines at the front of messages. -.It Li G -Match local mail names against the GECOS portion of the password file. -.It Li g Ar N -The default group id to use when calling mailers. -.It Li H Ns Ar file -The -.Tn SMTP -help file. -.It Li h Ar N +.It Li MaxHopCount= Ar N The maximum number of times a message is allowed to ``hop'' before we decide it is in a loop. -.It Li i +.It Li IgnoreDots Do not take dots on a line by themselves as a message terminator. -.It Li j +.It Li SendMimeErrors Send error messages in MIME format. -.It Li K Ns Ar timeout +If not set, the DSN (Delivery Status Notification) SMTP extension +is disabled. +.It Li ConnectionCacheTimeout= Ns Ar timeout Set connection cache timeout. -.It Li k Ns Ar N +.It Li ConnectionCacheSize= Ns Ar N Set connection cache size. -.It Li L Ns Ar n +.It Li LogLevel= Ns Ar n The log level. -.It Li l -Pay attention to the Errors-To: header. -.It Li m +.It Li MeToo Send to ``me'' (the sender) also if I am in an alias expansion. -.It Li n +.It Li CheckAliases Validate the right hand side of aliases during a .Xr newaliases 1 command. -.It Li o +.It Li OldStyleHeaders If set, this message may have old style headers. If not set, @@ -357,24 +413,18 @@ this message is guaranteed to have new style headers (i.e., commas instead of spaces between addresses). If set, an adaptive algorithm is used that will correctly determine the header format in most cases. -.It Li Q Ns Ar queuedir +.It Li QueueDirectory= Ns Ar queuedir Select the directory in which to queue messages. -.It Li S Ns Ar file +.It Li StatusFile= Ns Ar file Save statistics in the named file. -.It Li s -Always instantiate the queue file, -even under circumstances where it is not strictly necessary. -This provides safety against system crashes during delivery. -.It Li T Ns Ar time +.It Li Timeout.queuereturn= Ns Ar time Set the timeout on undelivered messages in the queue to the specified time. After delivery has failed (e.g., because of a host being down) for this amount of time, failed messages will be returned to the sender. -The default is three days. -.It Li t Ns Ar stz , Ar dtz -Set the name of the time zone. -.It Li U Ns Ar userdatabase +The default is five days. +.It Li UserDatabaseSpec= Ns Ar userdatabase If set, a user database is consulted to get forwarding information. You can consider this an adjunct to the aliasing mechanism, except that the database is intended to be distributed; @@ -382,13 +432,54 @@ aliases are local to a particular host. This may not be available if your sendmail does not have the .Dv USERDB option compiled in. -.It Li u Ns Ar N -Set the default user id for mailers. -.It Li Y +.It Li ForkEachJob Fork each job during queue runs. May be convenient on memory-poor machines. -.It Li 7 +.It Li SevenBitInput Strip incoming messages to seven bits. +.It Li EightBitMode= Ns Ar mode +Set the handling of eight bit input to seven bit destinations to +.Ar mode : +.Li m +(mimefy) will convert to seven-bit MIME format, +.Li p +(pass) will pass it as eight bits (but violates protocols), +and +.Li s +(strict) will bounce the message. +.It Li MinQueueAge= Ns Ar timeout +Sets how long a job must ferment in the queue between attempts to send it. +.It Li DefaultCharSet= Ns Ar charset +Sets the default character set used to label 8-bit data +that is not otherwise labelled. +.It Li DialDelay= Ns Ar sleeptime +If opening a connection fails, +sleep for +.Ar sleeptime +seconds and try again. +Useful on dial-on-demand sites. +.It Li NoRecipientAction= Ns Ar action +Set the behaviour when there are no recipient headers (To:, Cc: or Bcc:) +in the message to +.Ar action : +.Li none +leaves the message unchanged, +.Li add-to +adds a To: header with the envelope recipients, +.Li add-apparently-to +adds an Apparently-To: header with the envelope recipients, +.Li add-bcc +adds an empty Bcc: header, and +.Li add-to-undisclosed +adds a header reading +.Ql "To: undisclosed-recipients:;" . +.It Li MaxDaemonChildren= Ns Ar N +Sets the maximum number of children that an incoming SMTP daemon +will allow to spawn at any time to +.Ar N . +.It Li ConnectionRateThrottle= Ns Ar N +Sets the maximum number of connections per second to the SMTP port to +.Ar N . .El .Pp In aliases, diff --git a/usr.sbin/sendmail/src/sendmail.h b/usr.sbin/sendmail/src/sendmail.h index fb2f145..62b0bb9 100644 --- a/usr.sbin/sendmail/src/sendmail.h +++ b/usr.sbin/sendmail/src/sendmail.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)sendmail.h 8.159.1.3 (Berkeley) 9/16/96 + * @(#)sendmail.h 8.206 (Berkeley) 10/17/96 */ /* @@ -41,7 +41,7 @@ # ifdef _DEFINE # define EXTERN # ifndef lint -static char SmailSccsId[] = "@(#)sendmail.h 8.159.1.3 9/16/96"; +static char SmailSccsId[] = "@(#)sendmail.h 8.206 10/17/96"; # endif # else /* _DEFINE */ # define EXTERN extern @@ -179,12 +179,15 @@ typedef struct address ADDRESS; # define QEXPANDED 0x00020000 /* DSN: undergone list expansion */ # define QDELIVERED 0x00040000 /* DSN: successful final delivery */ # define QDELAYED 0x00080000 /* DSN: message delayed */ -# define QTHISPASS 0x80000000 /* temp: address set this pass */ +# define QTHISPASS 0x40000000 /* temp: address set this pass */ + +# define Q_PINGFLAGS (QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY) # define NULLADDR ((ADDRESS *) NULL) /* functions */ extern ADDRESS *parseaddr __P((char *, ADDRESS *, int, int, char **, ENVELOPE *)); +extern ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); extern ADDRESS *recipient __P((ADDRESS *, ADDRESS **, int, ENVELOPE *)); extern char **prescan __P((char *, int, char[], int, char **, u_char *)); extern int rewrite __P((char **, int, int, ENVELOPE *)); @@ -250,6 +253,7 @@ struct mailer # define M_INTERNAL 'I' /* SMTP to another sendmail site */ # define M_UDBRECIPIENT 'j' /* do udbsender rewriting on recipient lines */ # define M_NOLOOPCHECK 'k' /* don't check for loops in HELO command */ +# define M_CHUNKING 'K' /* CHUNKING: reserved for future use */ # define M_LOCALMAILER 'l' /* delivery is to this host */ # define M_LIMITS 'L' /* must enforce SMTP line limits */ # define M_MUSER 'm' /* can handle multiple users at once */ @@ -259,6 +263,7 @@ struct mailer # define M_RUNASRCPT 'o' /* always run mailer as recipient */ # define M_FROMPATH 'p' /* use reverse-path in MAIL FROM: */ /* 'P' CF: include Return-Path: */ +# define M_VRFY250 'q' /* VRFY command returns 250 instead of 252 */ # define M_ROPT 'r' /* mailer takes picky -r flag */ # define M_SECURE_PORT 'R' /* try to send on a reserved TCP port */ # define M_STRIPQ 's' /* strip quote chars from user/host */ @@ -270,6 +275,7 @@ struct mailer # define M_HASPWENT 'w' /* check for /etc/passwd entry */ /* 'x' CF: include Full-Name: */ # define M_XDOT 'X' /* use hidden-dot algorithm */ +# define M_NOMX '0' /* turn off MX lookups */ # define M_EBCDIC '3' /* extend Q-P encoding for EBCDIC */ # define M_TRYRULESET5 '5' /* use ruleset 5 after local aliasing */ # define M_7BITS '7' /* use 7-bit path */ @@ -279,6 +285,7 @@ struct mailer # define M_CHECKPROG '|' /* check for |program addresses */ # define M_CHECKFILE '/' /* check for /file addresses */ # define M_CHECKUDB '@' /* user can be user database key */ +# define M_CHECKHDIR '~' /* SGI: check for valid home directory */ EXTERN MAILER *Mailer[MAXMAILERS+1]; @@ -287,52 +294,6 @@ EXTERN MAILER *ProgMailer; /* ptr to program mailer */ EXTERN MAILER *FileMailer; /* ptr to *file* mailer */ EXTERN MAILER *InclMailer; /* ptr to *include* mailer */ /* -** Header structure. -** This structure is used internally to store header items. -*/ - -struct header -{ - char *h_field; /* the name of the field */ - char *h_value; /* the value of that field */ - struct header *h_link; /* the next header */ - u_short h_flags; /* status bits, see below */ - BITMAP h_mflags; /* m_flags bits needed */ -}; - -typedef struct header HDR; - -/* -** Header information structure. -** Defined in conf.c, this struct declares the header fields -** that have some magic meaning. -*/ - -struct hdrinfo -{ - char *hi_field; /* the name of the field */ - u_short hi_flags; /* status bits, see below */ -}; - -extern struct hdrinfo HdrInfo[]; - -/* bits for h_flags and hi_flags */ -# define H_EOH 0x0001 /* this field terminates header */ -# define H_RCPT 0x0002 /* contains recipient addresses */ -# define H_DEFAULT 0x0004 /* if another value is found, drop this */ -# define H_RESENT 0x0008 /* this address is a "Resent-..." address */ -# define H_CHECK 0x0010 /* check h_mflags against m_flags */ -# define H_ACHECK 0x0020 /* ditto, but always (not just default) */ -# define H_FORCE 0x0040 /* force this field, even if default */ -# define H_TRACE 0x0080 /* this field contains trace information */ -# define H_FROM 0x0100 /* this is a from-type field */ -# define H_VALID 0x0200 /* this field has a validated value */ -# define H_RECEIPTTO 0x0400 /* this field has return receipt info */ -# define H_ERRORSTO 0x0800 /* this field has error address info */ -# define H_CTE 0x1000 /* this field is a content-transfer-encoding */ -# define H_CTYPE 0x2000 /* this is a content-type field */ -# define H_BCC 0x4000 /* Bcc: header: strip value or delete */ -/* ** Information about currently open connections to mailers, or to ** hosts that we have looked up recently. */ @@ -354,7 +315,9 @@ MCI struct mailer *mci_mailer; /* ptr to the mailer for this conn */ char *mci_host; /* host name */ char *mci_status; /* DSN status to be copied to addrs */ + char *mci_rstatus; /* SMTP status to be copied to addrs */ time_t mci_lastuse; /* last usage time */ + FILE *mci_statfile; /* long term status file */ }; @@ -388,6 +351,72 @@ MCI extern MCI *mci_get __P((char *, MAILER *)); extern void mci_cache __P((MCI *)); extern void mci_flush __P((bool, MCI *)); +extern void mci_dump __P((MCI *, bool)); +extern void mci_dump_all __P((bool)); +extern MCI **mci_scan __P((MCI *)); +extern int mci_traverse_persistent __P((int (), char *)); +extern int mci_print_persistent __P((char *, char *)); +extern int mci_purge_persistent __P((char *, char *)); +extern int mci_lock_host __P((MCI *)); +extern void mci_unlock_host __P((MCI *)); +extern int mci_lock_host_statfile __P((MCI *)); +extern void mci_store_persistent __P((MCI *)); +extern int mci_read_persistent __P((FILE *, MCI *)); +/* +** Header structure. +** This structure is used internally to store header items. +*/ + +struct header +{ + char *h_field; /* the name of the field */ + char *h_value; /* the value of that field */ + struct header *h_link; /* the next header */ + u_short h_flags; /* status bits, see below */ + BITMAP h_mflags; /* m_flags bits needed */ +}; + +typedef struct header HDR; + +/* +** Header information structure. +** Defined in conf.c, this struct declares the header fields +** that have some magic meaning. +*/ + +struct hdrinfo +{ + char *hi_field; /* the name of the field */ + u_short hi_flags; /* status bits, see below */ +}; + +extern struct hdrinfo HdrInfo[]; + +/* bits for h_flags and hi_flags */ +# define H_EOH 0x0001 /* this field terminates header */ +# define H_RCPT 0x0002 /* contains recipient addresses */ +# define H_DEFAULT 0x0004 /* if another value is found, drop this */ +# define H_RESENT 0x0008 /* this address is a "Resent-..." address */ +# define H_CHECK 0x0010 /* check h_mflags against m_flags */ +# define H_ACHECK 0x0020 /* ditto, but always (not just default) */ +# define H_FORCE 0x0040 /* force this field, even if default */ +# define H_TRACE 0x0080 /* this field contains trace information */ +# define H_FROM 0x0100 /* this is a from-type field */ +# define H_VALID 0x0200 /* this field has a validated value */ +# define H_RECEIPTTO 0x0400 /* this field has return receipt info */ +# define H_ERRORSTO 0x0800 /* this field has error address info */ +# define H_CTE 0x1000 /* this field is a content-transfer-encoding */ +# define H_CTYPE 0x2000 /* this is a content-type field */ +# define H_BCC 0x4000 /* Bcc: header: strip value or delete */ +# define H_ENCODABLE 0x8000 /* field can be RFC 1522 encoded */ + +/* functions */ +extern void addheader __P((char *, char *, HDR **)); +extern char *hvalue __P((char *, HDR *)); +extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *)); +extern void put_vanilla_header __P((HDR *, char *, MCI *)); +extern void eatheader __P((ENVELOPE *e, bool)); +extern int chompheader __P((char *, bool, HDR **, ENVELOPE *)); /* ** Envelope structure. ** This structure defines the message itself. There is usually @@ -403,7 +432,6 @@ struct envelope long e_msgpriority; /* adjusted priority of this message */ time_t e_ctime; /* time message appeared in the queue */ char *e_to; /* the target person */ - char *e_receiptto; /* return receipt address */ ADDRESS e_from; /* the person it is from */ char *e_sender; /* e_from.q_paddr w comments stripped */ char **e_fromdomain; /* the domain part of the sender */ @@ -472,7 +500,7 @@ EXTERN ENVELOPE *CurEnv; /* envelope currently being processed */ /* functions */ extern ENVELOPE *newenvelope __P((ENVELOPE *, ENVELOPE *)); -extern void dropenvelope __P((ENVELOPE *)); +extern void dropenvelope __P((ENVELOPE *, bool)); extern void clearenvelope __P((ENVELOPE *, bool)); extern void putheader __P((MCI *, HDR *, ENVELOPE *)); @@ -636,7 +664,8 @@ MAP char *map_domain; /* the (nominal) NIS domain */ char *map_rebuild; /* program to run to do auto-rebuild */ time_t map_mtime; /* last database modification time */ - short map_specificity; /* specificity of alaases */ + int map_lockfd; /* auxiliary lock file descriptor */ + short map_specificity; /* specificity of aliases */ MAP *map_stack[MAXMAPSTACK]; /* list for stacked maps */ short map_return[MAXMAPACTIONS]; /* return bitmaps for stacked maps */ }; @@ -659,6 +688,7 @@ MAP # define MF_UNSAFEDB 0x00004000 /* this map is world writable */ # define MF_APPEND 0x00008000 /* append new entry on rebuiled */ # define MF_KEEPQUOTES 0x00010000 /* don't dequote key before lookup */ +# define MF_NODEFER 0x00020000 /* don't defer if map lookup fails */ /* indices for map_actions */ # define MA_NOTFOUND 0 /* member map returned "not found" */ @@ -695,6 +725,7 @@ MAPCLASS /* functions */ extern char *map_rewrite __P((MAP *, char *, int, char **)); extern MAP *makemapentry __P((char *)); +extern void initmaps __P((bool, ENVELOPE *)); /* ** Symbol table definitions */ @@ -702,7 +733,8 @@ extern MAP *makemapentry __P((char *)); struct symtab { char *s_name; /* name to be entered */ - char s_type; /* general type (see below) */ + short s_type; /* general type (see below) */ + short s_len; /* length of this entry */ struct symtab *s_next; /* pointer to next in chain */ union { @@ -717,6 +749,7 @@ struct symtab NAMECANON sv_namecanon; /* canonical name cache */ int sv_macro; /* macro name => id mapping */ int sv_ruleset; /* ruleset index */ + char *sv_service[MAXMAPSTACK]; /* service switch */ } s_value; }; @@ -734,6 +767,7 @@ typedef struct symtab STAB; # define ST_NAMECANON 8 /* cached canonical name */ # define ST_MACRO 9 /* macro name to id mapping */ # define ST_RULESET 10 /* ruleset index */ +# define ST_SERVICE 11 /* service switch entry */ # define ST_MCI 16 /* mailer connection info (offset) */ # define s_class s_value.sv_class @@ -747,6 +781,7 @@ typedef struct symtab STAB; # define s_namecanon s_value.sv_namecanon # define s_macro s_value.sv_macro # define s_ruleset s_value.sv_ruleset +# define s_service s_value.sv_service extern STAB *stab __P((char *, int, int)); extern void stabapply __P((void (*)(STAB *, int), int)); @@ -802,12 +837,14 @@ EXTERN char OpMode; /* operation mode, see below */ #define MD_SMTP 's' /* run SMTP on standard input */ #define MD_ARPAFTP 'a' /* obsolete ARPANET mode (Grey Book) */ #define MD_DAEMON 'd' /* run as a daemon */ +#define MD_FGDAEMON 'D' /* run daemon in foreground */ #define MD_VERIFY 'v' /* verify: don't collect or deliver */ #define MD_TEST 't' /* test mode: resolve addrs only */ #define MD_INITALIAS 'i' /* initialize alias database */ #define MD_PRINT 'p' /* print the queue */ #define MD_FREEZE 'z' /* freeze the configuration file */ - +#define MD_HOSTSTAT 'h' /* print persistent host stat info */ +#define MD_PURGESTAT 'H' /* purge persistent host stat info */ /* values for e_sendmode -- send modes */ #define SM_DELIVER 'i' /* interactive delivery */ @@ -841,6 +878,7 @@ EXTERN int QueueSortOrder; #define QS_BYPRIORITY 0 /* sort by message priority */ #define QS_BYHOST 1 /* sort by first host name */ +#define QS_BYTIME 2 /* sort by submission time */ /* how to handle messages without any recipient addresses */ @@ -856,7 +894,7 @@ EXTERN int NoRecipientAction; /* flags to putxline */ #define PXLF_NOTHINGSPECIAL 0 /* no special mapping */ #define PXLF_MAPFROM 0x0001 /* map From_ to >From_ */ -#define PXLF_STRIP8BIT 0x0002 /* strip 8th bit *e +#define PXLF_STRIP8BIT 0x0002 /* strip 8th bit */ /* ** Additional definitions */ @@ -918,6 +956,9 @@ struct prival /* flags that are actually specific to safefopen */ #define SFF_OPENASROOT 0x1000 /* open as root instead of real user */ +/* functions */ +extern int safefile __P((char *, UID_T, GID_T, char *, int, int, struct stat *)); + /* ** Flags passed to mime8to7. @@ -929,6 +970,15 @@ struct prival /* +** Flags passed to returntosender. +*/ + +#define RTSF_NO_BODY 0 /* send headers only */ +#define RTSF_SEND_BODY 0x0001 /* include body of message in return */ +#define RTSF_PM_BOUNCE 0x0002 /* this is a postmaster bounce */ + + +/* ** Regular UNIX sockaddrs are too small to handle ISO addresses, so ** we are forced to declare a supertype here. */ @@ -957,6 +1007,8 @@ union bigsockaddr #define SOCKADDR union bigsockaddr EXTERN SOCKADDR RealHostAddr; /* address of host we are talking to */ + +extern char *hostnamebyanyaddr __P((SOCKADDR *)); extern char *anynet_ntoa __P((SOCKADDR *)); #endif @@ -983,6 +1035,34 @@ extern char *anynet_ntoa __P((SOCKADDR *)); #define VENDOR_IBM 4 /* IBM specific config syntax */ EXTERN int VendorCode; /* vendor-specific operation enhancements */ + +/* prototypes for vendor-specific hook routines */ +extern void vendor_set_uid __P((UID_T)); +extern void vendor_daemon_setup __P((ENVELOPE *)); + + +/* +** Terminal escape codes. +** +** To make debugging output clearer. +*/ + +struct termescape +{ + char *te_rv_on; /* turn reverse-video on */ + char *te_rv_off; /* turn reverse-video off */ +}; + +EXTERN struct termescape TermEscape; + + +/* +** Error return from inet_addr(3), in case not defined in /usr/include. +*/ + +#ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +#endif /* ** Global variables. */ @@ -1005,6 +1085,7 @@ EXTERN bool UseNameServer; /* using DNS -- interpret h_errno & MX RRs */ EXTERN bool UseHesiod; /* using Hesiod -- interpret Hesiod errors */ EXTERN bool SevenBitInput; /* force 7-bit data on input */ EXTERN bool HasEightBits; /* has at least one eight bit input byte */ +EXTERN bool ConfigFileRead; /* configuration file has been read */ EXTERN time_t SafeAlias; /* interval to wait until @:@ in alias file */ EXTERN FILE *InChannel; /* input connection */ EXTERN FILE *OutChannel; /* output connection */ @@ -1061,11 +1142,11 @@ EXTERN char *ForwardPath; /* path to search for .forward files */ EXTERN long MinBlocksFree; /* min # of blocks free on queue fs */ EXTERN char *FallBackMX; /* fall back MX host */ EXTERN long MaxMessageSize; /* advertised max size we will accept */ -EXTERN time_t MaxHostStatAge; /* max age of cached host status info */ EXTERN time_t MinQueueAge; /* min delivery interval */ EXTERN time_t DialDelay; /* delay between dial-on-demand tries */ EXTERN char *SafeFileEnv; /* chroot location for file delivery */ EXTERN char *HostsFile; /* path to /etc/hosts file */ +EXTERN char *HostStatDir; /* location of host status information */ EXTERN int MaxQueueRun; /* maximum number of jobs in one queue run */ EXTERN int MaxChildren; /* maximum number of daemonic children */ EXTERN int CurChildren; /* current number of daemonic children */ @@ -1073,8 +1154,17 @@ EXTERN char *SmtpGreeting; /* SMTP greeting message (old $e macro) */ EXTERN char *UnixFromLine; /* UNIX From_ line (old $l macro) */ EXTERN char *OperatorChars; /* operators (old $o macro) */ EXTERN bool DontInitGroups; /* avoid initgroups() because of NIS cost */ +EXTERN int DefaultNotify; /* default DSN notification flags */ +EXTERN bool AllowBogusHELO; /* allow syntax errors on HELO command */ +EXTERN bool UserSubmission; /* initial (user) mail submission */ +EXTERN uid_t RunAsUid; /* UID to become for bulk of run */ +EXTERN gid_t RunAsGid; /* GID to become for bulk of run */ +EXTERN bool SingleThreadDelivery; /* single thread hosts on delivery */ +EXTERN bool UnsafeGroupWrites; /* group-writable files are unsafe */ EXTERN bool SingleLineFromHeader; /* force From: header to be one line */ +EXTERN int ConnRateThrottle; /* throttle for SMTP connection rate */ EXTERN int MaxAliasRecursion; /* maximum depth of alias recursion */ +EXTERN int MaxMacroRecursion; /* maximum depth of macro recursion */ EXTERN int MaxRuleRecursion; /* maximum depth of ruleset recursion */ EXTERN char *MustQuoteChars; /* quote these characters in phrases */ EXTERN char *ServiceSwitchFile; /* backup service switch */ @@ -1085,12 +1175,16 @@ EXTERN int CheckpointInterval; /* queue file checkpoint interval */ EXTERN bool DontPruneRoutes; /* don't prune source routes */ EXTERN bool DontExpandCnames; /* do not $[...$] expand CNAMEs */ EXTERN int MaxMciCache; /* maximum entries in MCI cache */ +EXTERN time_t ServiceCacheTime; /* time service switch was cached */ +EXTERN time_t ServiceCacheMaxAge; /* refresh interval for cache */ EXTERN time_t MciCacheTimeout; /* maximum idle time on connections */ EXTERN time_t MciInfoTimeout; /* how long 'til we retry down hosts */ EXTERN char *QueueLimitRecipient; /* limit queue runs to this recipient */ EXTERN char *QueueLimitSender; /* limit queue runs to this sender */ EXTERN char *QueueLimitId; /* limit queue runs to this id */ EXTERN FILE *TrafficLogFile; /* file in which to log all traffic */ +EXTERN char *DoubleBounceAddr; /* where to send double bounces */ +EXTERN char **ExternalEnviron; /* input environment */ EXTERN char *UserEnviron[MAXUSERENVIRON + 1]; /* saved user environment */ extern int errno; @@ -1113,7 +1207,8 @@ EXTERN struct time_t to_datafinal; /* DATA completion [10m] */ time_t to_nextcommand; /* next command [5m] */ /* following timeouts are not mentioned in RFC 1123 */ - time_t to_connect; /* initial connection timeout */ + time_t to_iconnect; /* initial connection timeout (first try) */ + time_t to_connect; /* initial connection timeout (later tries) */ time_t to_rset; /* RSET command */ time_t to_helo; /* HELO command */ time_t to_quit; /* QUIT command */ @@ -1161,6 +1256,7 @@ EXTERN u_char tTdvect[100]; #define STRUCTCOPY(s, d) d = s + /* ** Declarations of useful functions */ @@ -1181,8 +1277,6 @@ extern void openxscript __P((ENVELOPE *)); extern void closexscript __P((ENVELOPE *)); extern char *shortenstring __P((const char *, int)); extern bool usershellok __P((char *, char *)); -extern void commaize __P((HDR *, char *, bool, MCI *, ENVELOPE *)); -extern char *hvalue __P((char *, HDR *)); extern char *defcharset __P((ENVELOPE *)); extern bool wordinclass __P((char *, int)); extern char *denlstring __P((char *, bool, bool)); @@ -1197,6 +1291,7 @@ extern void logsender __P((ENVELOPE *, char *)); extern void smtprset __P((MAILER *, MCI *, ENVELOPE *)); extern void smtpquit __P((MAILER *, MCI *, ENVELOPE *)); extern void setuserenv __P((const char *, const char *)); +extern char *getextenv __P((const char *)); extern void disconnect __P((int, ENVELOPE *)); extern void putxline __P((char *, MCI *, int)); extern void dumpfd __P((int, bool, bool)); @@ -1208,15 +1303,66 @@ extern void inittimeouts __P((char *)); extern void logdelivery __P((MAILER *, MCI *, const char *, ADDRESS *, time_t, ENVELOPE *)); extern void giveresponse __P((int, MAILER *, MCI *, ADDRESS *, time_t, ENVELOPE *)); extern void buildfname __P((char *, char *, char *, int)); +extern void mci_setstat __P((MCI *, char *, char *)); +extern char *smtptodsn __P((int)); +extern int rscheck __P((char *, char *, char *, ENVELOPE *e)); +extern void mime7to8 __P((MCI *, HDR *, ENVELOPE *)); +extern int mime8to7 __P((MCI *, HDR *, ENVELOPE *, char **, int)); +extern void xfclose __P((FILE *, char *, char *)); +extern int switch_map_find __P((char *, char *[], short [])); +extern void shorten_hostname __P((char [])); +extern int waitfor __P((pid_t)); +extern void proc_list_add __P((pid_t)); +extern void proc_list_drop __P((pid_t)); +extern void buffer_errors __P((void)); +extern void flush_errors __P((bool)); +extern void putline __P((char *, MCI *)); +extern void putxline __P((char *, MCI *, int)); +extern bool xtextok __P((char *)); +extern char *xtextify __P((char *, char *)); +extern char *xuntextify __P((char *)); +extern void cleanstrcpy __P((char *, char *, int)); +extern int getmxrr __P((char *, char **, bool, int *)); +extern int strtorwset __P((char *, char **, int)); +extern void printav __P((char **)); +extern void printopenfds __P((bool)); +extern int endmailer __P((MCI *, ENVELOPE *, char **)); +extern void fixcrlf __P((char *, bool)); +extern int dofork __P((void)); +extern void initsys __P((ENVELOPE *)); +extern void collect __P((FILE *, bool, bool, HDR **, ENVELOPE *)); +extern void stripquotes __P((char *)); +extern int include __P((char *, bool, ADDRESS *, ADDRESS **, int, ENVELOPE *)); +extern void unlockqueue __P((ENVELOPE *)); +extern void xunlink __P((char *)); +extern void runqueue __P((bool)); +extern int getla __P((void)); +extern void sendall __P((ENVELOPE *, int)); +extern void queueup __P((ENVELOPE *, bool)); +extern void checkfds __P((char *)); +extern int returntosender __P((char *, ADDRESS *, int, ENVELOPE *)); +extern void markstats __P((ENVELOPE *, ADDRESS *)); +extern void poststats __P((char *)); +extern char *arpadate __P((char *)); +extern int mailfile __P((char *, ADDRESS *, int, ENVELOPE *)); +extern void loseqfile __P((ENVELOPE *, char *)); +extern int prog_open __P((char **, int *, ENVELOPE *)); +extern bool getcanonname __P((char *, int, bool)); +extern bool validate_connection __P((SOCKADDR *, char *, ENVELOPE *)); +extern bool path_is_dir __P((char *, bool)); +extern pid_t dowork __P((char *, bool, bool, ENVELOPE *)); extern const char *errstring __P((int)); extern sigfunc_t setsignal __P((int, sigfunc_t)); +extern int releasesignal __P((int)); extern struct hostent *sm_gethostbyname __P((char *)); extern struct hostent *sm_gethostbyaddr __P((char *, int, int)); extern struct passwd *sm_getpwnam __P((char *)); extern struct passwd *sm_getpwuid __P((UID_T)); +extern struct passwd *finduser __P((char *, bool *)); #ifdef XDEBUG +extern void checkfdopen __P((int, char *)); extern void checkfd012 __P((char *)); #endif @@ -1227,12 +1373,14 @@ extern void syserr(const char *, ...); extern void usrerr(const char *, ...); extern void message(const char *, ...); extern void nmessage(const char *, ...); +extern void setproctitle(const char *fmt, ...); #else extern void auth_warning(); extern void syserr(); extern void usrerr(); extern void message(); extern void nmessage(); +extern void setproctitle(); #endif #if !HASSNPRINTF diff --git a/usr.sbin/sendmail/src/srvrsmtp.c b/usr.sbin/sendmail/src/srvrsmtp.c index 69a4fbe..dc582cc 100644 --- a/usr.sbin/sendmail/src/srvrsmtp.c +++ b/usr.sbin/sendmail/src/srvrsmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #ifdef SMTP -static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (with SMTP)"; +static char sccsid[] = "@(#)srvrsmtp.c 8.123 (Berkeley) 10/12/96 (with SMTP)"; #else -static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (without SMTP)"; +static char sccsid[] = "@(#)srvrsmtp.c 8.123 (Berkeley) 10/12/96 (without SMTP)"; #endif #endif /* not lint */ @@ -79,9 +79,11 @@ struct cmd # define CMDHELO 9 /* helo -- be polite */ # define CMDHELP 10 /* help -- give usage info */ # define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ +# define CMDETRN 12 /* etrn -- flush queue */ /* non-standard commands */ # define CMDONEX 16 /* onex -- sending one transaction only */ # define CMDVERB 17 /* verb -- go into verbose mode */ +# define CMDXUSR 18 /* xusr -- initial (user) submission */ /* use this to catch and log "door handle" attempts on your system */ # define CMDLOGBOGUS 23 /* bogus command that should be logged */ /* debugging-only commands, only enabled if SMTPDEBUG is defined */ @@ -90,27 +92,27 @@ struct cmd static struct cmd CmdTab[] = { - "mail", CMDMAIL, - "rcpt", CMDRCPT, - "data", CMDDATA, - "rset", CMDRSET, - "vrfy", CMDVRFY, - "expn", CMDEXPN, - "help", CMDHELP, - "noop", CMDNOOP, - "quit", CMDQUIT, - "helo", CMDHELO, - "ehlo", CMDEHLO, - "verb", CMDVERB, - "onex", CMDONEX, - /* - * remaining commands are here only - * to trap and log attempts to use them - */ - "showq", CMDDBGQSHOW, - "debug", CMDDBGDEBUG, - "wiz", CMDLOGBOGUS, - NULL, CMDERROR, + { "mail", CMDMAIL }, + { "rcpt", CMDRCPT }, + { "data", CMDDATA }, + { "rset", CMDRSET }, + { "vrfy", CMDVRFY }, + { "expn", CMDEXPN }, + { "help", CMDHELP }, + { "noop", CMDNOOP }, + { "quit", CMDQUIT }, + { "helo", CMDHELO }, + { "ehlo", CMDEHLO }, + { "etrn", CMDETRN }, + { "verb", CMDVERB }, + { "onex", CMDONEX }, + { "xusr", CMDXUSR }, + /* remaining commands are here only to trap and log attempts to use them */ + { "showq", CMDDBGQSHOW }, + { "debug", CMDDBGDEBUG }, + { "wiz", CMDLOGBOGUS }, + + { NULL, CMDERROR } }; bool OneXact = FALSE; /* one xaction only this run */ @@ -122,7 +124,8 @@ static char *skipword(); #define MAXBADCOMMANDS 25 /* maximum number of bad commands */ void -smtp(e) +smtp(nullserver, e) + bool nullserver; register ENVELOPE *volatile e; { register char *p; @@ -141,10 +144,15 @@ smtp(e) volatile int nrcpts = 0; /* number of RCPT commands */ bool doublequeue; volatile int badcommands = 0; /* count of bad commands */ + volatile int nverifies = 0; /* count of VRFY/EXPN commands */ + volatile int n_etrn = 0; /* count of ETRN commands */ char inp[MAXLINE]; char cmdbuf[MAXLINE]; extern ENVELOPE BlankEnvelope; extern void help __P((char *)); + extern void settime __P((ENVELOPE *)); + extern bool enoughdiskspace __P((long)); + extern int runinchild __P((char *, ENVELOPE *)); if (fileno(OutChannel) != fileno(stdout)) { @@ -253,6 +261,11 @@ smtp(e) if (e->e_xfp != NULL) fprintf(e->e_xfp, "<<< %s\n", inp); +#ifdef LOG + if (LogLevel >= 15) + syslog(LOG_INFO, "<-- %s", inp); +#endif + if (e->e_id == NULL) setproctitle("%s: %.80s", CurSmtpClient, inp); else @@ -282,7 +295,20 @@ smtp(e) /* reset errors */ errno = 0; - /* process command */ + /* + ** Process command. + ** + ** If we are running as a null server, return 550 + ** to everything. + */ + + if (nullserver && c->cmdcode != CMDQUIT) + { + message("550 Access denied"); + continue; + } + + /* non-null server */ switch (c->cmdcode) { case CMDHELO: /* hello -- introduce yourself */ @@ -299,7 +325,7 @@ smtp(e) } /* check for valid domain name (re 1123 5.2.5) */ - if (*p == '\0') + if (*p == '\0' && !AllowBogusHELO) { message("501 %s requires domain address", cmdbuf); @@ -325,11 +351,23 @@ smtp(e) } if (*q != '\0') { - message("501 Invalid domain name"); + if (!AllowBogusHELO) + message("501 Invalid domain name"); + else + message("250 %s Invalid domain name, accepting anyway", + MyHostName); break; } } + /* check for duplicate HELO/EHLO per RFC 1651 4.2 */ + if (gothello) + { + message("503 %s Duplicate HELO/EHLO", + MyHostName); + break; + } + sendinghost = newstr(p); gothello = TRUE; if (c->cmdcode != CMDEHLO) @@ -344,7 +382,10 @@ smtp(e) message("250-%s Hello %s, pleased to meet you", MyHostName, CurSmtpClient); if (!bitset(PRIV_NOEXPN, PrivacyFlags)) + { message("250-EXPN"); + message("250-VERB"); + } #if MIME8TO7 message("250-8BITMIME"); #endif @@ -356,8 +397,9 @@ smtp(e) if (SendMIMEErrors) message("250-DSN"); #endif - message("250-VERB"); message("250-ONEX"); + message("250-ETRN"); + message("250-XUSR"); message("250 HELP"); break; @@ -391,13 +433,17 @@ smtp(e) finis(); } + p = skipword(p, "from"); + if (p == NULL) + break; + /* fork a subprocess to process this command */ if (runinchild("SMTP-MAIL", e) > 0) break; if (!gothello) { auth_warning(e, - "Host %s didn't use HELO protocol", + "%s didn't use HELO protocol", CurSmtpClient); } #ifdef PICKY_HELO_CHECK @@ -420,12 +466,10 @@ smtp(e) setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); /* child -- go do the processing */ - p = skipword(p, "from"); - if (p == NULL) - break; if (setjmp(TopFrame) > 0) { /* this failed -- undo work */ + undo_subproc: if (InChild) { QuickAbort = FALSE; @@ -440,9 +484,12 @@ smtp(e) /* must parse sender first */ delimptr = NULL; setsender(p, e, &delimptr, FALSE); - p = delimptr; - if (p != NULL && *p != '\0') - *p++ = '\0'; + if (delimptr != NULL && *delimptr != '\0') + *delimptr++ = '\0'; + + /* do config file checking of the sender */ + if (rscheck("check_mail", p, NULL, e) != EX_OK) + goto undo_subproc; /* check for possible spoofing */ if (RealUid != 0 && OpMode == MD_SMTP && @@ -456,6 +503,7 @@ smtp(e) /* now parse ESMTP arguments */ e->e_msgsize = 0; + p = delimptr; while (p != NULL && *p != '\0') { char *kp; @@ -470,7 +518,7 @@ smtp(e) kp = p; /* skip to the value portion */ - while (isascii(*p) && isalnum(*p) || *p == '-') + while ((isascii(*p) && isalnum(*p)) || *p == '-') p++; if (*p == '=') { @@ -534,9 +582,15 @@ smtp(e) a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e); if (a == NULL) break; - p = delimptr; + if (delimptr != NULL && *delimptr != '\0') + *delimptr++ = '\0'; + + /* do config file checking of the recipient */ + if (rscheck("check_rcpt", p, NULL, e) != EX_OK) + break; /* now parse ESMTP arguments */ + p = delimptr; while (p != NULL && *p != '\0') { char *kp; @@ -551,7 +605,7 @@ smtp(e) kp = p; /* skip to the value portion */ - while (isascii(*p) && isalnum(*p) || *p == '-') + while ((isascii(*p) && isalnum(*p)) || *p == '-') p++; if (*p == '=') { @@ -582,7 +636,7 @@ smtp(e) break; /* no errors during parsing, but might be a duplicate */ - e->e_to = p; + e->e_to = a->q_paddr; if (!bitset(QBADADDR, a->q_flags)) { message("250 Recipient ok%s", @@ -698,7 +752,7 @@ smtp(e) /* clean up a bit */ gotmail = FALSE; - dropenvelope(e); + dropenvelope(e, TRUE); CurEnv = e = newenvelope(e, CurEnv); e->e_flags = BlankEnvelope.e_flags; break; @@ -714,12 +768,24 @@ smtp(e) /* clean up a bit */ gotmail = FALSE; - dropenvelope(e); + dropenvelope(e, TRUE); CurEnv = e = newenvelope(e, CurEnv); break; case CMDVRFY: /* vrfy -- verify address */ case CMDEXPN: /* expn -- expand address */ + if (++nverifies >= MAXBADCOMMANDS) + { +#ifdef LOG + if (nverifies == MAXBADCOMMANDS && + LogLevel > 5) + { + syslog(LOG_INFO, "%.100s: VRFY attack?", + CurSmtpClient); + } +#endif + sleep(1); + } vrfy = c->cmdcode == CMDVRFY; if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, PrivacyFlags)) @@ -778,20 +844,47 @@ smtp(e) } while (vrfyqueue != NULL) { - extern void printvrfyaddr __P((ADDRESS *, bool)); + extern void printvrfyaddr __P((ADDRESS *, bool, bool)); a = vrfyqueue; while ((a = a->q_next) != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) continue; if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) - printvrfyaddr(vrfyqueue, a == NULL); + printvrfyaddr(vrfyqueue, a == NULL, vrfy); vrfyqueue = vrfyqueue->q_next; } if (InChild) finis(); break; + case CMDETRN: /* etrn -- force queue flush */ + if (strlen(p) <= 0) + { + message("500 Parameter required"); + break; + } + + /* crude way to avoid denial-of-service attacks */ + if (n_etrn++ >= 3) + sleep(3); + id = p; + if (*id == '@') + id++; + else + *--id = '@'; +#ifdef LOG + if (LogLevel > 5) + syslog(LOG_INFO, "%.100s: ETRN %s", + CurSmtpClient, + shortenstring(id, 203)); +#endif + QueueLimitRecipient = id; + runqueue(TRUE); + QueueLimitRecipient = NULL; + message("250 Queuing for node %s started", p); + break; + case CMDHELP: /* help -- give user info */ help(p); break; @@ -831,6 +924,11 @@ doquit: message("250 Only one transaction"); break; + case CMDXUSR: /* initial (user) submission */ + UserSubmission = TRUE; + message("250 Initial submission"); + break; + # ifdef SMTPDEBUG case CMDDBGQSHOW: /* show queues */ printf("Send Queue="); @@ -1112,6 +1210,7 @@ rcpt_esmtp_args(a, kp, vp, e) ** Parameters: ** a -- the address to print ** last -- set if this is the last one. +** vrfy -- set if this is a VRFY command. ** ** Returns: ** none. @@ -1121,13 +1220,18 @@ rcpt_esmtp_args(a, kp, vp, e) */ void -printvrfyaddr(a, last) +printvrfyaddr(a, last, vrfy) register ADDRESS *a; bool last; + bool vrfy; { char fmtbuf[20]; - strcpy(fmtbuf, "250"); + if (vrfy && a->q_mailer != NULL && + !bitnset(M_VRFY250, a->q_mailer->m_flags)) + strcpy(fmtbuf, "252"); + else + strcpy(fmtbuf, "250"); fmtbuf[3] = last ? ' ' : '-'; if (a->q_fullname == NULL) diff --git a/usr.sbin/sendmail/src/udb.c b/usr.sbin/sendmail/src/udb.c index e9834eb..075f197 100644 --- a/usr.sbin/sendmail/src/udb.c +++ b/usr.sbin/sendmail/src/udb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #if USERDB -static char sccsid [] = "@(#)udb.c 8.33.1.2 (Berkeley) 9/16/96 (with USERDB)"; +static char sccsid [] = "@(#)udb.c 8.42 (Berkeley) 9/18/96 (with USERDB)"; #else -static char sccsid [] = "@(#)udb.c 8.33.1.2 (Berkeley) 9/16/96 (without USERDB)"; +static char sccsid [] = "@(#)udb.c 8.42 (Berkeley) 9/18/96 (without USERDB)"; #endif #endif @@ -119,6 +119,8 @@ struct option char *name; char *val; }; + +extern int _udbx_init __P((void)); /* ** UDBEXPAND -- look up user in database and expand ** @@ -159,7 +161,6 @@ udbexpand(a, sendq, aliaslevel, e) int keylen; int naddrs; char keybuf[MAXKEY]; - char buf[BUFSIZ]; if (tTd(28, 1)) printf("udbexpand(%s)\n", a->q_paddr); @@ -172,8 +173,6 @@ udbexpand(a, sendq, aliaslevel, e) /* on first call, locate the database */ if (!UdbInitialized) { - extern int _udbx_init(); - if (_udbx_init() == EX_TEMPFAIL) return EX_TEMPFAIL; } @@ -187,7 +186,7 @@ udbexpand(a, sendq, aliaslevel, e) return EX_OK; /* if name is too long, assume it won't match */ - if (strlen(a->q_user) > sizeof keybuf - 12) + if (strlen(a->q_user) > (SIZE_T) sizeof keybuf - 12) return EX_OK; /* if name begins with a colon, it indicates our metadata */ @@ -203,6 +202,16 @@ udbexpand(a, sendq, aliaslevel, e) for (up = UdbEnts; !breakout; up++) { char *user; + int usersize; + int userleft; + char userbuf[MEMCHUNKSIZE]; +#if defined(HESIOD) && defined(HES_GETMAILHOST) + char pobuf[MAXNAME]; +#endif + + user = userbuf; + usersize = sizeof userbuf; + userleft = sizeof userbuf - 1; /* ** Select action based on entry type. @@ -227,17 +236,18 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 2)) printf("udbexpand: no match on %s (%d)\n", keybuf, keylen); - continue; + break; } if (tTd(28, 80)) printf("udbexpand: match %.*s: %.*s\n", key.size, key.data, info.size, info.data); - naddrs = 0; a->q_flags &= ~QSELFREF; while (i == 0 && key.size == keylen && bcmp(key.data, keybuf, keylen) == 0) { + char *p; + if (bitset(EF_VRFYONLY, e->e_flags)) { a->q_flags |= QVERIFIED; @@ -245,24 +255,26 @@ udbexpand(a, sendq, aliaslevel, e) } breakout = TRUE; - if (info.size < sizeof buf) - user = buf; - else - user = xalloc(info.size + 1); + if (info.size >= userleft - 1) + { + char *nuser = xalloc(usersize + MEMCHUNKSIZE); + + bcopy(user, nuser, usersize); + if (user != userbuf) + free(user); + user = nuser; + usersize += MEMCHUNKSIZE; + userleft += MEMCHUNKSIZE; + } + p = &user[strlen(user)]; + if (p != user) + { + *p++ = ','; + userleft--; + } bcopy(info.data, user, info.size); user[info.size] = '\0'; - - message("expanded to %s", user); -#ifdef LOG - if (LogLevel >= 10) - syslog(LOG_INFO, "%s: expand %.100s => %s", - e->e_id, e->e_to, - shortenstring(user, 203)); -#endif - naddrs += sendtolist(user, a, sendq, aliaslevel + 1, e); - - if (user != buf) - free(user); + userleft -= info.size; /* get the next record */ i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT); @@ -270,8 +282,16 @@ udbexpand(a, sendq, aliaslevel, e) /* if nothing ever matched, try next database */ if (!breakout) - continue; + break; + message("expanded to %s", user); +#ifdef LOG + if (LogLevel >= 10) + syslog(LOG_INFO, "%s: expand %.100s => %s", + e->e_id, e->e_to, + shortenstring(user, 203)); +#endif + naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) { if (tTd(28, 5)) @@ -357,13 +377,24 @@ udbexpand(a, sendq, aliaslevel, e) if (tTd(28, 2)) printf("hes_getmailhost(%s): %d\n", a->q_user, hes_error()); - continue; + break; } + if (strlen(hp->po_name) + strlen(hp->po_host) > + sizeof pobuf - 2) + { + if (tTd(28, 2)) + printf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n", + a->q_user, + hp->po_name, + hp->po_host); + break; + } + info.data = pobuf; snprintf(pobuf, sizeof pobuf, "%s@%s", hp->po_name, hp->po_host); info.size = strlen(info.data); #else - continue; + break; #endif } if (tTd(28, 80)) @@ -378,9 +409,7 @@ udbexpand(a, sendq, aliaslevel, e) } breakout = TRUE; - if (info.size < sizeof buf) - user = buf; - else + if (info.size >= usersize) user = xalloc(info.size + 1); bcopy(info.data, user, info.size); user[info.size] = '\0'; @@ -394,9 +423,6 @@ udbexpand(a, sendq, aliaslevel, e) #endif naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e); - if (user != buf) - free(user); - if (naddrs > 0 && !bitset(QSELFREF, a->q_flags)) { if (tTd(28, 5)) @@ -428,17 +454,18 @@ udbexpand(a, sendq, aliaslevel, e) case UDB_REMOTE: /* not yet implemented */ - continue; + break; case UDB_FORWARD: if (bitset(EF_VRFYONLY, e->e_flags)) return EX_OK; i = strlen(up->udb_fwdhost) + strlen(a->q_user) + 1; - if (i < sizeof buf) - user = buf; - else - user = xalloc(i + 1); - (void) snprintf(user, i, "%s@%s", + if (i >= usersize) + { + usersize = i + 1; + user = xalloc(usersize); + } + (void) snprintf(user, usersize, "%s@%s", a->q_user, up->udb_fwdhost); message("expanded to %s", user); a->q_flags &= ~QSELFREF; @@ -452,19 +479,19 @@ udbexpand(a, sendq, aliaslevel, e) } a->q_flags |= QDONTSEND; } - if (user != buf) - free(user); breakout = TRUE; break; case UDB_EOLIST: breakout = TRUE; - continue; + break; default: /* unknown entry type */ - continue; + break; } + if (user != userbuf) + free(user); } return EX_OK; } @@ -798,6 +825,7 @@ _udbx_init() char *mxhosts[MAXMXHOSTS + 1]; # endif struct option opts[MAXUDBOPTS + 1]; + extern int _udb_parsespec __P((char *, struct option [], int)); while (*p == ' ' || *p == '\t' || *p == ',') p++; diff --git a/usr.sbin/sendmail/src/usersmtp.c b/usr.sbin/sendmail/src/usersmtp.c index edfe7be..aaae985 100644 --- a/usr.sbin/sendmail/src/usersmtp.c +++ b/usr.sbin/sendmail/src/usersmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #ifdef SMTP -static char sccsid[] = "@(#)usersmtp.c 8.65.1.2 (Berkeley) 9/16/96 (with SMTP)"; +static char sccsid[] = "@(#)usersmtp.c 8.72 (Berkeley) 9/15/96 (with SMTP)"; #else -static char sccsid[] = "@(#)usersmtp.c 8.65.1.2 (Berkeley) 9/16/96 (without SMTP)"; +static char sccsid[] = "@(#)usersmtp.c 8.72 (Berkeley) 9/15/96 (without SMTP)"; #endif #endif /* not lint */ @@ -64,6 +64,7 @@ int SmtpPid; /* pid of mailer */ bool SmtpNeedIntro; /* need "while talking" in transcript */ extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); +extern int reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)())); /* ** SMTPINIT -- initialize SMTP. ** @@ -83,7 +84,7 @@ extern void smtpmessage __P((char *f, MAILER *m, MCI *mci, ...)); void smtpinit(m, mci, e) - struct mailer *m; + MAILER *m; register MCI *mci; ENVELOPE *e; { @@ -327,7 +328,7 @@ helo_options(line, firstline, m, mci, e) int smtpmailfrom(m, mci, e) - struct mailer *m; + MAILER *m; MCI *mci; ENVELOPE *e; { @@ -383,14 +384,16 @@ smtpmailfrom(m, mci, e) else if (!bitset(MM_PASS8BIT, MimeMode)) { /* cannot just send a 8-bit version */ + extern char MsgBuf[]; + usrerr("%s does not support 8BITMIME", mci->mci_host); - mci->mci_status = "5.6.3"; + mci_setstat(mci, "5.6.3", MsgBuf); return EX_DATAERR; } if (bitset(MCIF_DSN, mci->mci_flags)) { - if (e->e_envid != NULL && strlen(e->e_envid) < (SIZE_T) l) + if (e->e_envid != NULL && strlen(e->e_envid) < (SIZE_T) (l - 7)) { strcat(optbuf, " ENVID="); strcat(optbuf, e->e_envid); @@ -454,6 +457,7 @@ smtpmailfrom(m, mci, e) } else if (REPLYTYPE(r) == 4) { + mci_setstat(mci, smtptodsn(r), SmtpReplyBuffer); return EX_TEMPFAIL; } else if (REPLYTYPE(r) == 2) @@ -463,24 +467,25 @@ smtpmailfrom(m, mci, e) else if (r == 501) { /* syntax error in arguments */ - mci->mci_status = "5.5.2"; + mci_setstat(mci, "5.5.2", SmtpReplyBuffer); return EX_DATAERR; } else if (r == 553) { /* mailbox name not allowed */ - mci->mci_status = "5.1.3"; + mci_setstat(mci, "5.1.3", SmtpReplyBuffer); return EX_DATAERR; } else if (r == 552) { /* exceeded storage allocation */ - mci->mci_status = "5.2.2"; + mci_setstat(mci, "5.2.2", SmtpReplyBuffer); return EX_UNAVAILABLE; } else if (REPLYTYPE(r) == 5) { /* unknown error */ + mci_setstat(mci, "5.0.0", SmtpReplyBuffer); return EX_UNAVAILABLE; } @@ -494,6 +499,7 @@ smtpmailfrom(m, mci, e) #endif /* protocol error -- close up */ + mci_setstat(mci, "5.5.1", SmtpReplyBuffer); smtpquit(m, mci, e); return EX_PROTOCOL; } @@ -523,7 +529,6 @@ smtprcpt(to, m, mci, e) register int r; int l; char optbuf[MAXLINE]; - extern char *smtptodsn(); strcpy(optbuf, ""); l = sizeof optbuf - 1; @@ -581,10 +586,25 @@ smtprcpt(to, m, mci, e) return EX_TEMPFAIL; else if (REPLYTYPE(r) == 2) return EX_OK; - else if (r == 550 || r == 551 || r == 553) + else if (r == 550) + { + to->q_status = "5.1.1"; return EX_NOUSER; + } + else if (r == 551) + { + to->q_status = "5.1.6"; + return EX_NOUSER; + } + else if (r == 553) + { + to->q_status = "5.1.3"; + return EX_NOUSER; + } else if (REPLYTYPE(r) == 5) + { return EX_UNAVAILABLE; + } #ifdef LOG if (LogLevel > 1) @@ -616,7 +636,7 @@ static void datatimeout(); int smtpdata(m, mci, e) - struct mailer *m; + MAILER *m; register MCI *mci; register ENVELOPE *e; { @@ -723,6 +743,7 @@ smtpdata(m, mci, e) return EX_TEMPFAIL; } mci->mci_state = MCIS_OPEN; + mci_setstat(mci, smtptodsn(r), SmtpReplyBuffer); e->e_statmsg = newstr(&SmtpReplyBuffer[4]); if (REPLYTYPE(r) == 4) return EX_TEMPFAIL; diff --git a/usr.sbin/sendmail/src/util.c b/usr.sbin/sendmail/src/util.c index 7abc671..2136d3c 100644 --- a/usr.sbin/sendmail/src/util.c +++ b/usr.sbin/sendmail/src/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -33,7 +33,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)util.c 8.84.1.4 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)util.c 8.105 (Berkeley) 10/12/96"; #endif /* not lint */ # include "sendmail.h" @@ -260,50 +260,71 @@ xputs(s) { register int c; register struct metamac *mp; + bool shiftout = FALSE; extern struct metamac MetaMacros[]; if (s == NULL) { - printf("<null>"); + printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off); return; } while ((c = (*s++ & 0377)) != '\0') { + if (shiftout) + { + printf("%s", TermEscape.te_rv_off); + shiftout = FALSE; + } if (!isascii(c)) { if (c == MATCHREPL) { - putchar('$'); - continue; + printf("%s$", TermEscape.te_rv_on); + shiftout = TRUE; + if (*s == '\0') + continue; + c = *s++ & 0377; + goto printchar; } if (c == MACROEXPAND) { - putchar('$'); + printf("%s$", TermEscape.te_rv_on); + shiftout = TRUE; if (strchr("=~&?", *s) != NULL) putchar(*s++); if (bitset(0200, *s)) printf("{%s}", macname(*s++ & 0377)); + else + printf("%c", *s++); continue; } for (mp = MetaMacros; mp->metaname != '\0'; mp++) { if ((mp->metaval & 0377) == c) { - printf("$%c", mp->metaname); + printf("%s$%c", + TermEscape.te_rv_on, + mp->metaname); + shiftout = TRUE; break; } } if (c == MATCHCLASS || c == MATCHNCLASS) { - if (!bitset(0200, *s)) - continue; - printf("{%s}", macname(*s++ & 0377)); + if (bitset(0200, *s)) + printf("{%s}", macname(*s++ & 0377)); + else + printf("%c", *s++); } if (mp->metaname != '\0') continue; - (void) putchar('\\'); + + /* unrecognized meta character */ + printf("%sM-", TermEscape.te_rv_on); + shiftout = TRUE; c &= 0177; } + printchar: if (isprint(c)) { putchar(c); @@ -324,15 +345,25 @@ xputs(s) case '\t': c = 't'; break; - - default: + } + if (!shiftout) + { + printf("%s", TermEscape.te_rv_on); + shiftout = TRUE; + } + if (isprint(c)) + { + (void) putchar('\\'); + (void) putchar(c); + } + else + { (void) putchar('^'); (void) putchar(c ^ 0100); - continue; } - (void) putchar('\\'); - (void) putchar(c); } + if (shiftout) + printf("%s", TermEscape.te_rv_off); (void) fflush(stdout); } /* @@ -397,27 +428,18 @@ buildfname(gecos, login, buf, buflen) if (*gecos == '*') gecos++; - /* find length of final string */ - l = 0; - for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) - { - if (*p == '&') - l += strlen(login); - else - l++; - } - if (l > buflen - 1) - { - /* not a good sign */ - snprintf(buf, buflen, "%s", gecos); - return; - } - - /* now fill in buf */ + /* copy gecos, interpolating & to be full name */ for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) { + if (bp >= &buf[buflen - 1]) + { + /* buffer overflow -- just use login name */ + snprintf(buf, buflen, "%s", login); + return; + } if (*p == '&') { + /* interpolate full name */ snprintf(bp, buflen - (bp - buf), "%s", login); *bp = toupper(*bp); bp += strlen(bp); @@ -470,8 +492,8 @@ buildfname(gecos, login, buf, buflen) int safefile(fn, uid, gid, uname, flags, mode, st) char *fn; - uid_t uid; - gid_t gid; + UID_T uid; + GID_T gid; char *uname; int flags; int mode; @@ -552,7 +574,7 @@ safefile(fn, uid, gid, uname, flags, mode, st) bitset(S_IXGRP, stbuf.st_mode)) continue; #ifndef NO_GROUP_SET - if (uname != NULL && + if (uname != NULL && !DontInitGroups && ((gr != NULL && gr->gr_gid == stbuf.st_gid) || (gr = getgrgid(stbuf.st_gid)) != NULL)) { @@ -651,7 +673,7 @@ safefile(fn, uid, gid, uname, flags, mode, st) if (st->st_gid == gid) ; #ifndef NO_GROUP_SET - else if (uname != NULL && + else if (uname != NULL && !DontInitGroups && ((gr != NULL && gr->gr_gid == st->st_gid) || (gr = getgrgid(st->st_gid)) != NULL)) { @@ -815,12 +837,12 @@ struct omodes char *farg; } OpenModes[] = { - O_ACCMODE, O_RDONLY, "r", - O_ACCMODE|O_APPEND, O_WRONLY, "w", - O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", - O_TRUNC, 0, "w+", - O_APPEND, O_APPEND, "a+", - 0, 0, "r+", + { O_ACCMODE, O_RDONLY, "r" }, + { O_ACCMODE|O_APPEND, O_WRONLY, "w" }, + { O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a" }, + { O_TRUNC, 0, "w+" }, + { O_APPEND, O_APPEND, "a+" }, + { 0, 0, "r+" }, }; FILE * @@ -1109,9 +1131,11 @@ sfgets(buf, siz, fp, timeout, during) if (setjmp(CtxReadTimeout) != 0) { # ifdef LOG - syslog(LOG_NOTICE, - "timeout waiting for input from %.100s during %s", - CurHostName? CurHostName: "local", during); + if (LogLevel > 1) + syslog(LOG_NOTICE, + "timeout waiting for input from %.100s during %s", + CurHostName ? CurHostName : "local", + during); # endif errno = 0; usrerr("451 timeout waiting for input during %s", @@ -1339,19 +1363,21 @@ atooct(s) int waitfor(pid) - int pid; + pid_t pid; { #ifdef WAITUNION union wait st; #else auto int st; #endif - int i; + pid_t i; do { errno = 0; i = wait(&st); + if (i > 0) + proc_list_drop(i); } while ((i >= 0 || errno == EINTR) && i != pid); if (i < 0) return -1; @@ -1470,7 +1496,7 @@ checkfd012(where) for (i = 0; i < 3; i++) { - if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) + if (fstat(i, &stbuf) < 0 && errno == EBADF) { /* oops.... */ int fd; @@ -1487,6 +1513,90 @@ checkfd012(where) #endif /* XDEBUG */ } /* +** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging +** +** Parameters: +** fd -- file descriptor to check. +** where -- tag to print on failure. +** +** Returns: +** none. +*/ + +void +checkfdopen(fd, where) + int fd; + char *where; +{ +#if XDEBUG + struct stat st; + + if (fstat(fd, &st) < 0 && errno == EBADF) + { + syserr("checkfdopen(%d): %s not open as expected!", fd, where); + printopenfds(TRUE); + } +#endif +} +/* +** CHECKFDS -- check for new or missing file descriptors +** +** Parameters: +** where -- tag for printing. If null, take a base line. +** +** Returns: +** none +** +** Side Effects: +** If where is set, shows changes since the last call. +*/ + +void +checkfds(where) + char *where; +{ + int maxfd; + register int fd; + bool printhdr = TRUE; + int save_errno = errno; + static BITMAP baseline; + extern int DtableSize; + + if (DtableSize > 256) + maxfd = 256; + else + maxfd = DtableSize; + if (where == NULL) + clrbitmap(baseline); + + for (fd = 0; fd < maxfd; fd++) + { + struct stat stbuf; + + if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) + { + if (!bitnset(fd, baseline)) + continue; + clrbitn(fd, baseline); + } + else if (!bitnset(fd, baseline)) + setbitn(fd, baseline); + else + continue; + + /* file state has changed */ + if (where == NULL) + continue; + if (printhdr) + { + syslog(LOG_DEBUG, "%s: changed fds:", where); + printhdr = FALSE; + } + dumpfd(fd, TRUE, TRUE); + } + errno = save_errno; +} +/* ** PRINTOPENFDS -- print the open file descriptors (for debugging) ** ** Parameters: @@ -1542,12 +1652,17 @@ dumpfd(fd, printclosed, logit) if (fstat(fd, &st) < 0) { - if (printclosed || errno != EBADF) + if (errno != EBADF) { snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)", errstring(errno)); goto printit; } + else if (printclosed) + { + snprintf(p, SPACELEFT(buf, p), "CLOSED"); + goto printit; + } return; } @@ -1812,8 +1927,10 @@ prog_open(argv, pfd, e) /* run as default user */ endpwent(); - setgid(DefGid); - setuid(DefUid); + if (setgid(DefGid) < 0) + syserr("prog_open: setgid(%ld) failed", (long) DefGid); + if (setuid(DefUid) < 0) + syserr("prog_open: setuid(%ld) failed", (long) DefUid); /* run in some directory */ if (ProgMailer != NULL) @@ -1856,6 +1973,7 @@ prog_open(argv, pfd, e) if (transienterror(saveerrno)) _exit(EX_OSERR); _exit(EX_CONFIG); + return -1; /* avoid compiler warning on IRIX */ } /* ** GET_COLUMN -- look up a Column in a line buffer @@ -1904,7 +2022,7 @@ get_column(line, col, delim, buf, buflen) if (col == 0 && delim == '\0') { - while (*begin && isspace(*begin)) + while (*begin != '\0' && isascii(*begin) && isspace(*begin)) begin++; } @@ -1915,14 +2033,14 @@ get_column(line, col, delim, buf, buflen) begin++; if (delim == '\0') { - while (*begin && isspace(*begin)) + while (*begin != '\0' && isascii(*begin) && isspace(*begin)) begin++; } } end = strpbrk(begin, delimbuf); if (end == NULL) - i = strlen(buf); + i = strlen(begin); else i = end - begin; if (i >= buflen) @@ -2022,3 +2140,112 @@ denlstring(s, strict, logattacks) return bp; } +/* +** PATH_IS_DIR -- check to see if file exists and is a directory. +** +** Parameters: +** pathname -- pathname to check for directory-ness. +** createflag -- if set, create directory if needed. +** +** Returns: +** TRUE -- if the indicated pathname is a directory +** FALSE -- otherwise +*/ + +int +path_is_dir(pathname, createflag) + char *pathname; + bool createflag; +{ + struct stat statbuf; + + if (stat(pathname, &statbuf) < 0) + { + if (errno != ENOENT || !createflag) + return FALSE; + if (mkdir(pathname, 0755) < 0) + return FALSE; + return TRUE; + } + if (!S_ISDIR(statbuf.st_mode)) + { + errno = ENOTDIR; + return FALSE; + } + return TRUE; +} +/* +** PROC_LIST_ADD -- add process id to list of our children +** +** Parameters: +** pid -- pid to add to list. +** +** Returns: +** none +*/ + +static pid_t *ProcListVec = NULL; +static int ProcListSize = 0; + +#define NO_PID ((pid_t) 0) +#ifndef PROC_LIST_SEG +# define PROC_LIST_SEG 32 /* number of pids to alloc at a time */ +#endif + +void +proc_list_add(pid) + pid_t pid; +{ + int i; + + for (i = 0; i < ProcListSize; i++) + { + if (ProcListVec[i] == NO_PID) + break; + } + if (i >= ProcListSize) + { + /* grow process list */ + pid_t *npv; + + npv = (pid_t *) xalloc(sizeof (pid_t) * (ProcListSize + PROC_LIST_SEG)); + if (ProcListSize > 0) + { + bcopy(ProcListVec, npv, ProcListSize * sizeof (pid_t)); + free(ProcListVec); + } + for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) + npv[i] = NO_PID; + i = ProcListSize; + ProcListSize += PROC_LIST_SEG; + ProcListVec = npv; + } + ProcListVec[i] = pid; + CurChildren++; +} +/* +** PROC_LIST_DROP -- drop pid from process list +** +** Parameters: +** pid -- pid to drop +** +** Returns: +** none. +*/ + +void +proc_list_drop(pid) + pid_t pid; +{ + int i; + + for (i = 0; i < ProcListSize; i++) + { + if (ProcListVec[i] == pid) + { + ProcListVec[i] = NO_PID; + CurChildren--; + break; + } + } +} |