+\f/*
+** RESETLIMITS -- reset system controlled resource limits
+**
+** This is to avoid denial-of-service attacks
+**
+** Parameters:
+** none
+**
+** Returns:
+** none
+*/
+
+#if HASSETRLIMIT
+# include <sys/resource.h>
+#endif
+
+void
+resetlimits()
+{
+#if HASSETRLIMIT
+ struct rlimit lim;
+
+ lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
+ (void) setrlimit(RLIMIT_CPU, &lim);
+ (void) setrlimit(RLIMIT_FSIZE, &lim);
+#else
+# if HASULIMIT
+ (void) ulimit(2, 0x3fffff);
+# endif
+#endif
+}
+\f/*
+** GETCFNAME -- return the name of the .cf file.
+**
+** Some systems (e.g., NeXT) determine this dynamically.
+*/
+
+char *
+getcfname()
+{
+
+ if (ConfFile != NULL)
+ return ConfFile;
+#if NETINFO
+ {
+ extern char *ni_propval();
+ char *cflocation;
+
+ cflocation = ni_propval("/locations", NULL, "sendmail",
+ "sendmail.cf", '\0');
+ if (cflocation != NULL)
+ return cflocation;
+ }
+#endif
+
+ return _PATH_SENDMAILCF;
+}
+\f/*
+** SETVENDOR -- process vendor code from V configuration line
+**
+** Parameters:
+** vendor -- string representation of vendor.
+**
+** Returns:
+** TRUE -- if ok.
+** FALSE -- if vendor code could not be processed.
+**
+** Side Effects:
+** It is reasonable to set mode flags here to tweak
+** processing in other parts of the code if necessary.
+** For example, if you are a vendor that uses $%y to
+** indicate YP lookups, you could enable that here.
+*/
+
+bool
+setvendor(vendor)
+ char *vendor;
+{
+ if (strcasecmp(vendor, "Berkeley") == 0)
+ {
+ VendorCode = VENDOR_BERKELEY;
+ return TRUE;
+ }
+
+ /* add vendor extensions here */
+
+#ifdef SUN_EXTENSIONS
+ if (strcasecmp(vendor, "Sun") == 0)
+ {
+ VendorCode = VENDOR_SUN;
+ return TRUE;
+ }
+#endif
+
+ return FALSE;
+}
+\f/*
+** VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults
+**
+** Vendor_pre_defaults is called before reading the configuration
+** file; vendor_post_defaults is called immediately after.
+**
+** Parameters:
+** e -- the global environment to initialize.
+**
+** Returns:
+** none.
+*/
+
+void
+vendor_pre_defaults(e)
+ ENVELOPE *e;
+{
+}
+
+
+void
+vendor_post_defaults(e)
+ ENVELOPE *e;
+{
+}
+\f/*
+** STRTOL -- convert string to long integer
+**
+** For systems that don't have it in the C library.
+**
+** This is taken verbatim from the 4.4-Lite C library.
+*/
+
+#ifdef NEEDSTRTOL
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+
+long
+strtol(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s = nptr;
+ register unsigned long acc;
+ register int c;
+ register unsigned long cutoff;
+ register int neg = 0, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long)base;
+ cutoff /= (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+
+#endif
+\f/*
+** STRSTR -- find first substring in string
+**
+** Parameters:
+** big -- the big (full) string.
+** little -- the little (sub) string.
+**
+** Returns:
+** A pointer to the first instance of little in big.
+** big if little is the null string.
+** NULL if little is not contained in big.
+*/
+
+#ifdef NEEDSTRSTR
+
+char *
+strstr(big, little)
+ char *big;
+ char *little;
+{
+ register char *p = big;
+ int l;
+
+ if (*little == '\0')
+ return big;
+ l = strlen(little);
+
+ while ((p = strchr(p, *little)) != NULL)
+ {
+ if (strncmp(p, little, l) == 0)
+ return p;
+ p++;
+ }
+ return NULL;
+}
+
+#endif
+\f/*
+** SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
+**
+** Some operating systems have wierd problems with the gethostbyXXX
+** routines. For example, Solaris versions at least through 2.3
+** don't properly deliver a canonical h_name field. This tries to
+** work around these problems.
+*/
+
+struct hostent *
+sm_gethostbyname(name)
+ char *name;
+{
+ struct hostent *h;
+#if defined(SOLARIS) && SOLARIS < 204 || defined(sony_news) && defined(__svr4)
+# if SOLARIS == 203
+ static struct hostent hp;
+ static char buf[1000];
+ extern struct hostent *_switch_gethostbyname_r();
+
+ if (tTd(61, 10))
+ printf("_switch_gethostbyname_r(%s)... ", name);
+ h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
+# else
+ extern struct hostent *__switch_gethostbyname();
+
+ if (tTd(61, 10))
+ printf("__switch_gethostbyname(%s)... ", name);
+ h = __switch_gethostbyname(name);
+# endif
+#else
+ int nmaps;
+ char *maptype[MAXMAPSTACK];
+ short mapreturn[MAXMAPACTIONS];
+ char hbuf[MAXNAME];
+
+ if (tTd(61, 10))
+ printf("gethostbyname(%s)... ", name);
+ h = gethostbyname(name);
+ if (h == NULL)
+ {
+ if (tTd(61, 10))
+ printf("failure\n");
+
+ nmaps = switch_map_find("hosts", maptype, mapreturn);
+ while (--nmaps >= 0)
+ if (strcmp(maptype[nmaps], "nis") == 0 ||
+ strcmp(maptype[nmaps], "files") == 0)
+ break;
+ if (nmaps >= 0)
+ {
+ /* try short name */
+ if (strlen(name) > sizeof hbuf - 1)
+ return NULL;
+ strcpy(hbuf, name);
+ shorten_hostname(hbuf);
+
+ /* if it hasn't been shortened, there's no point */
+ if (strcmp(hbuf, name) != 0)
+ {
+ if (tTd(61, 10))
+ printf("gethostbyname(%s)... ", hbuf);
+ h = gethostbyname(hbuf);
+ }
+ }
+ }
+#endif
+ if (tTd(61, 10))
+ {
+ if (h == NULL)
+ printf("failure\n");
+ else
+ printf("%s\n", h->h_name);
+ }
+ return h;
+}
+
+struct hostent *
+sm_gethostbyaddr(addr, len, type)
+ char *addr;
+ int len;
+ int type;
+{
+#if defined(SOLARIS) && SOLARIS < 204
+# if SOLARIS == 203
+ static struct hostent hp;
+ static char buf[1000];
+ extern struct hostent *_switch_gethostbyaddr_r();
+
+ return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno);
+# else
+ extern struct hostent *__switch_gethostbyaddr();
+
+ return __switch_gethostbyaddr(addr, len, type);
+# endif
+#else
+ return gethostbyaddr(addr, len, type);
+#endif
+}
+\f/*
+** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid
+*/
+
+struct passwd *
+sm_getpwnam(user)
+ char *user;
+{
+ return getpwnam(user);
+}
+
+struct passwd *
+sm_getpwuid(uid)
+ UID_T uid;
+{
+ return getpwuid(uid);
+}
+\f/*
+** LOAD_IF_NAMES -- load interface-specific names into $=w
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Loads $=w with the names of all the interfaces.
+*/
+
+#ifdef SIOCGIFCONF
+struct rtentry;
+struct mbuf;
+# include <arpa/inet.h>
+# include <sys/time.h>
+# include <net/if.h>
+#endif
+
+void
+load_if_names()
+{
+#ifdef SIOCGIFCONF
+ int s;
+ int i;
+ struct ifconf ifc;
+ char interfacebuf[1024];
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ return;
+
+ /* get the list of known IP address from the kernel */
+ ifc.ifc_buf = interfacebuf;
+ ifc.ifc_len = sizeof interfacebuf;
+ if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
+ {
+ if (tTd(0, 4))
+ printf("SIOGIFCONF failed: %s\n", errstring(errno));
+ close(s);
+ return;
+ }
+ close(s);
+
+ /* scan the list of IP address */
+ if (tTd(0, 40))
+ printf("scanning for interface specific names, ifc_len=%d\n",
+ ifc.ifc_len);
+
+ for (i = 0; i < ifc.ifc_len; )
+ {
+ struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i];
+ struct sockaddr *sa = &ifr->ifr_addr;
+ struct in_addr ia;
+ struct hostent *hp;
+ char ip_addr[256];
+ extern char *inet_ntoa();
+ extern struct hostent *gethostbyaddr();
+
+#ifdef BSD4_4_SOCKADDR
+ if (sa->sa_len > sizeof ifr->ifr_addr)
+ i += sizeof ifr->ifr_name + sa->sa_len;
+ else
+#endif
+ i += sizeof *ifr;
+
+ if (tTd(0, 20))
+ printf("%s\n", anynet_ntoa((SOCKADDR *) sa));
+
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+
+ /* extract IP address from the list*/
+ ia = (((struct sockaddr_in *) sa)->sin_addr);
+
+ /* save IP address in text from */
+ (void) sprintf(ip_addr, "[%s]",
+ inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
+ if (!wordinclass(ip_addr, 'w'))
+ {
+ setclass('w', ip_addr);
+ if (tTd(0, 4))
+ printf("\ta.k.a.: %s\n", ip_addr);
+ }
+
+ /* skip "loopback" interface "lo" */
+ if (strcmp("lo0", ifr->ifr_name) == 0)
+ continue;
+
+ /* lookup name with IP address */
+ hp = sm_gethostbyaddr((char *) &ia, sizeof(ia), AF_INET);
+ if (hp == NULL)
+ {
+ syslog(LOG_CRIT, "gethostbyaddr() failed for %s\n",
+ inet_ntoa(ia));
+ continue;
+ }
+
+ /* save its cname */
+ if (!wordinclass(hp->h_name, 'w'))
+ {
+ setclass('w', hp->h_name);
+ if (tTd(0, 4))
+ printf("\ta.k.a.: %s\n", hp->h_name);
+ }
+
+ /* save all it aliases name */
+ while (*hp->h_aliases)
+ {
+ if (!wordinclass(*hp->h_aliases, 'w'))
+ {
+ setclass('w', *hp->h_aliases);
+ if (tTd(0, 4))
+ printf("\ta.k.a.: %s\n", *hp->h_aliases);
+ }
+ hp->h_aliases++;
+ }
+ }
+#endif
+}
+\f/*
+** NI_PROPVAL -- netinfo property value lookup routine
+**
+** Parameters:
+** keydir -- the Netinfo directory name in which to search
+** for the key.
+** keyprop -- the name of the property in which to find the
+** property we are interested. Defaults to "name".
+** keyval -- the value for which we are really searching.
+** valprop -- the property name for the value in which we
+** are interested.
+** sepchar -- if non-nil, this can be multiple-valued, and
+** we should return a string separated by this
+** character.
+**
+** Returns:
+** NULL -- if:
+** 1. the directory is not found
+** 2. the property name is not found
+** 3. the property contains multiple values
+** 4. some error occured
+** else -- the location of the config file.
+**
+** Example:
+** To search for an alias value, use:
+** ni_propval("/aliases", "name", aliasname, "members", ',')
+**
+** Notes:
+** Caller should free the return value of ni_proval
+*/
+
+#if NETINFO
+
+# include <netinfo/ni.h>
+
+# define LOCAL_NETINFO_DOMAIN "."
+# define PARENT_NETINFO_DOMAIN ".."
+# define MAX_NI_LEVELS 256
+
+char *
+ni_propval(keydir, keyprop, keyval, valprop, sepchar)
+ char *keydir;
+ char *keyprop;
+ char *keyval;
+ char *valprop;
+ char sepchar;
+{
+ char *propval = NULL;
+ int i;
+ int j, alen;
+ void *ni = NULL;
+ void *lastni = NULL;
+ ni_status nis;
+ ni_id nid;
+ ni_namelist ninl;
+ register char *p;
+ char keybuf[1024];
+
+ /*
+ ** Create the full key from the two parts.
+ **
+ ** Note that directory can end with, e.g., "name=" to specify
+ ** an alternate search property.
+ */
+
+ i = strlen(keydir) + strlen(keyval) + 2;
+ if (keyprop != NULL)
+ i += strlen(keyprop) + 1;
+ if (i > sizeof keybuf)
+ return NULL;
+ strcpy(keybuf, keydir);
+ strcat(keybuf, "/");
+ if (keyprop != NULL)
+ {
+ strcat(keybuf, keyprop);
+ strcat(keybuf, "=");
+ }
+ strcat(keybuf, keyval);
+
+ /*
+ ** If the passed directory and property name are found
+ ** in one of netinfo domains we need to search (starting
+ ** from the local domain moving all the way back to the
+ ** root domain) set propval to the property's value
+ ** and return it.
+ */
+
+ for (i = 0; i < MAX_NI_LEVELS; ++i)
+ {
+ if (i == 0)
+ {
+ nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
+ }
+ else
+ {
+ if (lastni != NULL)
+ ni_free(lastni);
+ lastni = ni;
+ nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
+ }
+
+ /*
+ ** Don't bother if we didn't get a handle on a
+ ** proper domain. This is not necessarily an error.
+ ** We would get a positive ni_status if, for instance
+ ** we never found the directory or property and tried
+ ** to open the parent of the root domain!
+ */
+
+ if (nis != 0)
+ break;
+
+ /*
+ ** Find the path to the server information.
+ */
+
+ if (ni_pathsearch(ni, &nid, keybuf) != 0)
+ continue;
+
+ /*
+ ** Find associated value information.
+ */
+
+ if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
+ continue;
+
+ /*
+ ** See if we have an acceptable number of values.
+ */
+
+ if (ninl.ni_namelist_len <= 0)
+ continue;
+
+ if (sepchar == '\0' && ninl.ni_namelist_len > 1)
+ {
+ ni_namelist_free(&ninl);
+ continue;
+ }
+
+ /*
+ ** Calculate number of bytes needed and build result
+ */
+
+ alen = 1;
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ alen += strlen(ninl.ni_namelist_val[j]) + 1;
+ propval = p = xalloc(alen);
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ {
+ strcpy(p, ninl.ni_namelist_val[j]);
+ p += strlen(p);
+ *p++ = sepchar;
+ }
+ *--p = '\0';
+
+ ni_namelist_free(&ninl);
+ }
+
+ /*
+ ** Clean up.
+ */
+
+ if (ni != NULL)
+ ni_free(ni);
+ if (lastni != NULL && ni != lastni)
+ ni_free(lastni);
+
+ return propval;
+}
+
+#endif /* NETINFO */
+\f/*
+** HARD_SYSLOG -- call syslog repeatedly until it works
+**
+** Needed on HP-UX, which apparently doesn't guarantee that
+** syslog succeeds during interrupt handlers.
+*/
+
+#ifdef __hpux
+
+# define MAXSYSLOGTRIES 100
+# undef syslog
+
+# ifdef __STDC__
+void
+hard_syslog(int pri, char *msg, ...)
+# else
+hard_syslog(pri, msg, va_alist)
+ int pri;
+ char *msg;
+ va_dcl
+# endif
+{
+ int i;
+ char buf[SYSLOG_BUFSIZE * 2];
+ VA_LOCAL_DECL;
+
+ VA_START(msg);
+ vsprintf(buf, msg, ap);
+ VA_END;
+
+ for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; )
+ continue;
+}
+
+#endif
+\f/*
+** LOCAL_HOSTNAME_LENGTH
+**
+** This is required to get sendmail to compile against BIND 4.9.x
+** on Ultrix.
+*/
+
+#if defined(ultrix) && NAMED_BIND
+
+# include <resolv.h>
+# if __RES >= 19931104
+
+int
+local_hostname_length(hostname)
+ char *hostname;
+{
+ int len_host, len_domain;
+
+ if (!*_res.defdname)
+ res_init();
+ len_host = strlen(hostname);
+ len_domain = strlen(_res.defdname);
+ if (len_host > len_domain &&
+ (strcasecmp(hostname + len_host - len_domain,_res.defdname) == 0) &&
+ hostname[len_host - len_domain - 1] == '.')
+ return len_host - len_domain - 1;
+ else
+ return 0;
+}
+
+# endif
+#endif
+\f/*
+** Compile-Time options
+*/
+
+char *CompileOptions[] =
+{
+#if HESIOD
+ "HESIOD",
+#endif
+#ifdef LOG
+ "LOG",
+#endif
+#if MATCHGECOS
+ "MATCHGECOS",
+#endif
+#if NAMED_BIND
+ "NAMED_BIND",
+#endif
+#if NDBM
+ "NDBM",
+#endif
+#if NETINET
+ "NETINET",
+#endif
+#if NETINFO
+ "NETINFO",
+#endif
+#if NETISO
+ "NETISO",
+#endif
+#if NETNS
+ "NETNS",
+#endif
+#if NETUNIX
+ "NETUNIX",
+#endif
+#if NETX25
+ "NETX25",
+#endif
+#if NEWDB
+ "NEWDB",
+#endif
+#if NIS
+ "NIS",
+#endif
+#if NISPLUS
+ "NISPLUS",
+#endif
+#if SCANF
+ "SCANF",
+#endif
+#if SUID_ROOT_FILES_OK
+ "SUID_ROOT_FILES_OK",
+#endif
+#if USERDB
+ "USERDB",
+#endif
+#if XDEBUG
+ "XDEBUG",
+#endif
+#if XLA
+ "XLA",
+#endif
+ NULL
+};
+
+
+/*
+** OS compile options.
+*/
+
+char *OsCompileOptions[] =
+{
+#if HASFLOCK
+ "HASFLOCK",
+#endif
+#if HASGETUSERSHELL
+ "HASGETUSERSHELL",
+#endif
+#if HASINITGROUPS
+ "HASINITGROUPS",
+#endif
+#if HASLSTAT
+ "HASLSTAT",
+#endif
+#if HASSETREUID
+ "HASSETREUID",
+#endif
+#if HASSETSID
+ "HASSETSID",
+#endif
+#if HASSETVBUF
+ "HASSETVBUF",
+#endif
+#if HASUNAME
+ "HASUNAME",
+#endif
+#if IDENTPROTO
+ "IDENTPROTO",
+#endif
+#if IP_SRCROUTE
+ "IP_SRCROUTE",
+#endif
+#if SYS5SETPGRP
+ "SYS5SETPGRP",
+#endif
+#if SYSTEM5
+ "SYSTEM5",
+#endif
+#if USESETEUID
+ "USESETEUID",
+#endif
+ NULL
+};