aboutsummaryrefslogtreecommitdiff
path: root/contrib/sendmail/libsmutil
diff options
context:
space:
mode:
authorGregory Neil Shapiro <gshapiro@FreeBSD.org>2000-08-12 21:55:49 +0000
committerGregory Neil Shapiro <gshapiro@FreeBSD.org>2000-08-12 21:55:49 +0000
commit06f25ae9f1d6020a600a10f713046203d1a82570 (patch)
tree6d207932926718f38869bd08959330c09f4f3e0d /contrib/sendmail/libsmutil
parentb518ca7de5820956700c15009494373b46ec0dbd (diff)
downloadsrc-06f25ae9f1d6020a600a10f713046203d1a82570.tar.gz
src-06f25ae9f1d6020a600a10f713046203d1a82570.zip
Import of sendmail version 8.11.0 into vendor branch SENDMAIL with
release tag v8_11_0. Obtained from: ftp://ftp.sendmail.org/pub/sendmail/
Notes
Notes: svn path=/vendor/sendmail/dist/; revision=64562
Diffstat (limited to 'contrib/sendmail/libsmutil')
-rwxr-xr-xcontrib/sendmail/libsmutil/Build13
-rw-r--r--contrib/sendmail/libsmutil/Makefile17
-rw-r--r--contrib/sendmail/libsmutil/Makefile.m413
-rw-r--r--contrib/sendmail/libsmutil/debug.c40
-rw-r--r--contrib/sendmail/libsmutil/errstring.c206
-rw-r--r--contrib/sendmail/libsmutil/lockfile.c83
-rw-r--r--contrib/sendmail/libsmutil/safefile.c949
-rw-r--r--contrib/sendmail/libsmutil/snprintf.c430
-rw-r--r--contrib/sendmail/libsmutil/strl.c91
9 files changed, 1842 insertions, 0 deletions
diff --git a/contrib/sendmail/libsmutil/Build b/contrib/sendmail/libsmutil/Build
new file mode 100755
index 000000000000..014c45cc9442
--- /dev/null
+++ b/contrib/sendmail/libsmutil/Build
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
+# All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+# $Id: Build,v 8.2.2.1 2000/04/10 06:41:07 gshapiro Exp $
+
+exec sh ../devtools/bin/Build $*
diff --git a/contrib/sendmail/libsmutil/Makefile b/contrib/sendmail/libsmutil/Makefile
new file mode 100644
index 000000000000..2de323192e3b
--- /dev/null
+++ b/contrib/sendmail/libsmutil/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 8.2 1999/09/23 22:36:32 ca Exp $
+
+SHELL= /bin/sh
+BUILD= ./Build
+OPTIONS= $(CONFIG) $(FLAGS)
+
+all: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+clean: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+install: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+
+fresh: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) -c
+
+FRC:
diff --git a/contrib/sendmail/libsmutil/Makefile.m4 b/contrib/sendmail/libsmutil/Makefile.m4
new file mode 100644
index 000000000000..93a344c48ce0
--- /dev/null
+++ b/contrib/sendmail/libsmutil/Makefile.m4
@@ -0,0 +1,13 @@
+include(confBUILDTOOLSDIR`/M4/switch.m4')
+
+# sendmail dir
+SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail')
+PREPENDDEF(`confENVDEF', `confMAPDEF')
+PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ')
+
+bldPRODUCT_START(`library', `libsmutil')
+define(`bldSOURCES', `debug.c errstring.c lockfile.c safefile.c snprintf.c strl.c ')
+APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL')
+bldPRODUCT_END
+
+bldFINISH
diff --git a/contrib/sendmail/libsmutil/debug.c b/contrib/sendmail/libsmutil/debug.c
new file mode 100644
index 000000000000..bc32b66b1c6e
--- /dev/null
+++ b/contrib/sendmail/libsmutil/debug.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#ifndef lint
+static char id[] = "@(#)$Id: debug.c,v 8.2 1999/07/26 04:04:09 gshapiro Exp $";
+#endif /* ! lint */
+
+#include <sendmail.h>
+
+u_char tTdvect[100]; /* trace vector */
+
+#if _FFR_DPRINTF_
+void
+/*VARARGS1*/
+#ifdef __STDC__
+dprintf(const char *fmt, ...)
+#else /* __STDC__ */
+dprintf(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif /* __STDC__ */
+{
+ VA_LOCAL_DECL;
+
+ (void) vfprintf(stdout, fmt, ap);
+}
+
+int
+dflush()
+{
+ return fflush(stdout);
+}
+#endif /* _FFR_DPRINTF_ */
diff --git a/contrib/sendmail/libsmutil/errstring.c b/contrib/sendmail/libsmutil/errstring.c
new file mode 100644
index 000000000000..c851532ec404
--- /dev/null
+++ b/contrib/sendmail/libsmutil/errstring.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#ifndef lint
+static char id[] = "@(#)$Id: errstring.c,v 8.8.4.1 2000/05/26 18:16:28 geir Exp $";
+#endif /* ! lint */
+
+#include <sendmail.h>
+
+/*
+** ERRSTRING -- return string description of error code
+**
+** Parameters:
+** errnum -- the error number to translate
+**
+** Returns:
+** A string description of errnum.
+**
+** Side Effects:
+** none.
+*/
+
+const char *
+errstring(errnum)
+ int errnum;
+{
+#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
+
+ /*
+ ** Handle special network error codes.
+ **
+ ** These are 4.2/4.3bsd specific; they should be in daemon.c.
+ */
+
+ switch (errnum)
+ {
+ case EPERM:
+ /* SunOS gives "Not owner" -- this is the POSIX message */
+ return "Operation not permitted";
+
+ /*
+ ** Error messages used internally in sendmail.
+ */
+
+ case E_SM_OPENTIMEOUT:
+ return "Timeout on file open";
+
+ case E_SM_NOSLINK:
+ return "Symbolic links not allowed";
+
+ case E_SM_NOHLINK:
+ return "Hard links not allowed";
+
+ case E_SM_REGONLY:
+ return "Regular files only";
+
+ case E_SM_ISEXEC:
+ return "Executable files not allowed";
+
+ case E_SM_WWDIR:
+ return "World writable directory";
+
+ case E_SM_GWDIR:
+ return "Group writable directory";
+
+ case E_SM_FILECHANGE:
+ return "File changed after open";
+
+ case E_SM_WWFILE:
+ return "World writable file";
+
+ case E_SM_GWFILE:
+ return "Group writable file";
+
+ case E_SM_GRFILE:
+ return "Group readable file";
+
+ case E_SM_WRFILE:
+ return "World readable file";
+
+ /*
+ ** DNS error messages.
+ */
+
+#if NAMED_BIND
+ case HOST_NOT_FOUND + E_DNSBASE:
+ return "Name server: host not found";
+
+ case TRY_AGAIN + E_DNSBASE:
+ return "Name server: host name lookup failure";
+
+ case NO_RECOVERY + E_DNSBASE:
+ return "Name server: non-recoverable error";
+
+ case NO_DATA + E_DNSBASE:
+ return "Name server: no data known";
+#endif /* NAMED_BIND */
+
+ /*
+ ** libsmdb error messages.
+ */
+
+ case SMDBE_MALLOC:
+ return "Memory allocation failed";
+
+ case SMDBE_GDBM_IS_BAD:
+ return "GDBM is not supported";
+
+ case SMDBE_UNSUPPORTED:
+ return "Unsupported action";
+
+ case SMDBE_DUPLICATE:
+ return "Key already exists";
+
+ case SMDBE_BAD_OPEN:
+ return "Database open failed";
+
+ case SMDBE_NOT_FOUND:
+ return "Key not found";
+
+ case SMDBE_UNKNOWN_DB_TYPE:
+ return "Unknown database type";
+
+ case SMDBE_UNSUPPORTED_DB_TYPE:
+ return "Support for database type not compiled into this program";
+
+ case SMDBE_INCOMPLETE:
+ return "DB sync did not finish";
+
+ case SMDBE_KEY_EMPTY:
+ return "Key is empty";
+
+ case SMDBE_KEY_EXIST:
+ return "Key already exists";
+
+ case SMDBE_LOCK_DEADLOCK:
+ return "Locker killed to resolve deadlock";
+
+ case SMDBE_LOCK_NOT_GRANTED:
+ return "Lock unavailable";
+
+ case SMDBE_LOCK_NOT_HELD:
+ return "Lock not held by locker";
+
+ case SMDBE_RUN_RECOVERY:
+ return "Database panic, run recovery";
+
+ case SMDBE_IO_ERROR:
+ return "I/O error";
+
+ case SMDBE_READ_ONLY:
+ return "Database opened read-only";
+
+ case SMDBE_DB_NAME_TOO_LONG:
+ return "Name too long";
+
+ case SMDBE_INVALID_PARAMETER:
+ return "Invalid parameter";
+
+ case SMDBE_ONLY_SUPPORTS_ONE_CURSOR:
+ return "Only one cursor allowed";
+
+ case SMDBE_NOT_A_VALID_CURSOR:
+ return "Invalid cursor";
+
+ case SMDBE_OLD_VERSION:
+ return "Berkeley DB file is an old version, recreate it";
+ }
+
+ /*
+ ** LDAP error messages.
+ */
+
+#ifdef LDAPMAP
+ if (errnum >= E_LDAPBASE)
+ return ldap_err2string(errnum - E_LDAPBASE);
+#endif /* LDAPMAP */
+
+#if HASSTRERROR
+ return strerror(errnum);
+#else /* HASSTRERROR */
+ if (errnum > 0 && errnum < sys_nerr)
+ return sys_errlist[errnum];
+ else
+ {
+ static char buf[MAXLINE];
+
+ (void) snprintf(buf, sizeof buf, "Error %d", errnum);
+ return buf;
+ }
+#endif /* HASSTRERROR */
+}
+
diff --git a/contrib/sendmail/libsmutil/lockfile.c b/contrib/sendmail/libsmutil/lockfile.c
new file mode 100644
index 000000000000..78fbc20cd159
--- /dev/null
+++ b/contrib/sendmail/libsmutil/lockfile.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#ifndef lint
+static char id[] = "@(#)$Id: lockfile.c,v 8.3 1999/08/31 15:38:27 ca Exp $";
+#endif /* ! lint */
+
+#include <sendmail.h>
+
+ /*
+** LOCKFILE -- lock a file using flock or (shudder) fcntl locking
+**
+** Parameters:
+** fd -- the file descriptor of the file.
+** filename -- the file name (for error messages). [unused]
+** ext -- the filename extension. [unused]
+** type -- type of the lock. Bits can be:
+** LOCK_EX -- exclusive lock.
+** LOCK_NB -- non-blocking.
+**
+** Returns:
+** TRUE if the lock was acquired.
+** FALSE otherwise.
+*/
+
+bool
+lockfile(fd, filename, ext, type)
+ int fd;
+ char *filename;
+ char *ext;
+ int type;
+{
+#if !HASFLOCK
+ int action;
+ struct flock lfd;
+ extern int errno;
+
+ memset(&lfd, '\0', sizeof lfd);
+ if (bitset(LOCK_UN, type))
+ lfd.l_type = F_UNLCK;
+ else if (bitset(LOCK_EX, type))
+ lfd.l_type = F_WRLCK;
+ else
+ lfd.l_type = F_RDLCK;
+ if (bitset(LOCK_NB, type))
+ action = F_SETLK;
+ else
+ action = F_SETLKW;
+
+ if (fcntl(fd, action, &lfd) >= 0)
+ return TRUE;
+
+ /*
+ ** On SunOS, if you are testing using -oQ/tmp/mqueue or
+ ** -oA/tmp/aliases or anything like that, and /tmp is mounted
+ ** as type "tmp" (that is, served from swap space), the
+ ** previous fcntl will fail with "Invalid argument" errors.
+ ** Since this is fairly common during testing, we will assume
+ ** that this indicates that the lock is successfully grabbed.
+ */
+
+ if (errno == EINVAL)
+ return TRUE;
+
+#else /* !HASFLOCK */
+
+ if (flock(fd, type) >= 0)
+ return TRUE;
+
+#endif /* !HASFLOCK */
+
+ return FALSE;
+}
diff --git a/contrib/sendmail/libsmutil/safefile.c b/contrib/sendmail/libsmutil/safefile.c
new file mode 100644
index 000000000000..cbb88dfa83ba
--- /dev/null
+++ b/contrib/sendmail/libsmutil/safefile.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#ifndef lint
+static char id[] = "@(#)$Id: safefile.c,v 8.81.4.5 2000/07/17 22:33:37 ca Exp $";
+#endif /* ! lint */
+
+#include <sendmail.h>
+
+
+ /*
+** SAFEFILE -- return 0 if a file exists and is safe for a user.
+**
+** Parameters:
+** fn -- filename to check.
+** uid -- user id to compare against.
+** gid -- group id to compare against.
+** user -- user name to compare against (used for group
+** sets).
+** flags -- modifiers:
+** SFF_MUSTOWN -- "uid" must own this file.
+** SFF_NOSLINK -- file cannot be a symbolic link.
+** mode -- mode bits that must match.
+** st -- if set, points to a stat structure that will
+** get the stat info for the file.
+**
+** Returns:
+** 0 if fn exists, is owned by uid, and matches mode.
+** An errno otherwise. The actual errno is cleared.
+**
+** Side Effects:
+** none.
+*/
+
+int
+safefile(fn, uid, gid, user, flags, mode, st)
+ char *fn;
+ UID_T uid;
+ GID_T gid;
+ char *user;
+ long flags;
+ int mode;
+ struct stat *st;
+{
+ register char *p;
+ register struct group *gr = NULL;
+ int file_errno = 0;
+ bool checkpath;
+ struct stat stbuf;
+ struct stat fstbuf;
+ char fbuf[MAXPATHLEN + 1];
+
+ if (tTd(44, 4))
+ dprintf("safefile(%s, uid=%d, gid=%d, flags=%lx, mode=%o):\n",
+ fn, (int) uid, (int) gid, flags, mode);
+ errno = 0;
+ if (st == NULL)
+ st = &fstbuf;
+ if (strlcpy(fbuf, fn, sizeof fbuf) >= sizeof fbuf)
+ {
+ if (tTd(44, 4))
+ dprintf("\tpathname too long\n");
+ return ENAMETOOLONG;
+ }
+ fn = fbuf;
+
+ /* ignore SFF_SAFEDIRPATH if we are debugging */
+ if (RealUid != 0 && RunAsUid == RealUid)
+ flags &= ~SFF_SAFEDIRPATH;
+
+ /* first check to see if the file exists at all */
+# if HASLSTAT
+ if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st)
+ : stat(fn, st)) < 0)
+# else /* HASLSTAT */
+ if (stat(fn, st) < 0)
+# endif /* HASLSTAT */
+ {
+ file_errno = errno;
+ }
+ else if (bitset(SFF_SETUIDOK, flags) &&
+ !bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode) &&
+ S_ISREG(st->st_mode))
+ {
+ /*
+ ** If final file is setuid, run as the owner of that
+ ** file. Gotta be careful not to reveal anything too
+ ** soon here!
+ */
+
+# ifdef SUID_ROOT_FILES_OK
+ if (bitset(S_ISUID, st->st_mode))
+# else /* SUID_ROOT_FILES_OK */
+ if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0 &&
+ st->st_uid != TrustedUid)
+# endif /* SUID_ROOT_FILES_OK */
+ {
+ uid = st->st_uid;
+ user = NULL;
+ }
+# ifdef SUID_ROOT_FILES_OK
+ if (bitset(S_ISGID, st->st_mode))
+# else /* SUID_ROOT_FILES_OK */
+ if (bitset(S_ISGID, st->st_mode) && st->st_gid != 0)
+# endif /* SUID_ROOT_FILES_OK */
+ gid = st->st_gid;
+ }
+
+ checkpath = !bitset(SFF_NOPATHCHECK, flags) ||
+ (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags));
+ if (bitset(SFF_NOWLINK, flags) && !bitset(SFF_SAFEDIRPATH, flags))
+ {
+ int ret;
+
+ /* check the directory */
+ p = strrchr(fn, '/');
+ if (p == NULL)
+ {
+ ret = safedirpath(".", uid, gid, user,
+ flags|SFF_SAFEDIRPATH, 0, 0);
+ }
+ else
+ {
+ *p = '\0';
+ ret = safedirpath(fn, uid, gid, user,
+ flags|SFF_SAFEDIRPATH, 0, 0);
+ *p = '/';
+ }
+ if (ret == 0)
+ {
+ /* directory is safe */
+ checkpath = FALSE;
+ }
+ else
+ {
+# if HASLSTAT
+ /* Need lstat() information if called stat() before */
+ if (!bitset(SFF_NOSLINK, flags) && lstat(fn, st) < 0)
+ {
+ ret = errno;
+ if (tTd(44, 4))
+ dprintf("\t%s\n", errstring(ret));
+ return ret;
+ }
+# endif /* HASLSTAT */
+ /* directory is writable: disallow links */
+ flags |= SFF_NOLINK;
+ }
+ }
+
+ if (checkpath)
+ {
+ int ret;
+
+ p = strrchr(fn, '/');
+ if (p == NULL)
+ {
+ ret = safedirpath(".", uid, gid, user, flags, 0, 0);
+ }
+ else
+ {
+ *p = '\0';
+ ret = safedirpath(fn, uid, gid, user, flags, 0, 0);
+ *p = '/';
+ }
+ if (ret != 0)
+ return ret;
+ }
+
+ /*
+ ** If the target file doesn't exist, check the directory to
+ ** ensure that it is writable by this user.
+ */
+
+ if (file_errno != 0)
+ {
+ int ret = file_errno;
+ char *dir = fn;
+
+ if (tTd(44, 4))
+ dprintf("\t%s\n", errstring(ret));
+
+ errno = 0;
+ if (!bitset(SFF_CREAT, flags) || file_errno != ENOENT)
+ return ret;
+
+ /* check to see if legal to create the file */
+ p = strrchr(dir, '/');
+ if (p == NULL)
+ dir = ".";
+ else if (p == dir)
+ dir = "/";
+ else
+ *p = '\0';
+ if (stat(dir, &stbuf) >= 0)
+ {
+ int md = S_IWRITE|S_IEXEC;
+
+ if (stbuf.st_uid == uid)
+ /* EMPTY */
+ ;
+ else if (uid == 0 && stbuf.st_uid == TrustedUid)
+ /* EMPTY */
+ ;
+ else
+ {
+ md >>= 3;
+ if (stbuf.st_gid == gid)
+ /* EMPTY */
+ ;
+# ifndef NO_GROUP_SET
+ else if (user != NULL && !DontInitGroups &&
+ ((gr != NULL &&
+ gr->gr_gid == stbuf.st_gid) ||
+ (gr = getgrgid(stbuf.st_gid)) != NULL))
+ {
+ register char **gp;
+
+ for (gp = gr->gr_mem; *gp != NULL; gp++)
+ if (strcmp(*gp, user) == 0)
+ break;
+ if (*gp == NULL)
+ md >>= 3;
+ }
+# endif /* ! NO_GROUP_SET */
+ else
+ md >>= 3;
+ }
+ if ((stbuf.st_mode & md) != md)
+ errno = EACCES;
+ }
+ ret = errno;
+ if (tTd(44, 4))
+ dprintf("\t[final dir %s uid %d mode %lo] %s\n",
+ dir, (int) stbuf.st_uid, (u_long) stbuf.st_mode,
+ errstring(ret));
+ if (p != NULL)
+ *p = '/';
+ st->st_mode = ST_MODE_NOFILE;
+ return ret;
+ }
+
+# ifdef S_ISLNK
+ if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[slink mode %lo]\tE_SM_NOSLINK\n",
+ (u_long) st->st_mode);
+ return E_SM_NOSLINK;
+ }
+# endif /* S_ISLNK */
+ if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[non-reg mode %lo]\tE_SM_REGONLY\n",
+ (u_long) st->st_mode);
+ return E_SM_REGONLY;
+ }
+ if (bitset(SFF_NOGWFILES, flags) &&
+ bitset(S_IWGRP, st->st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[write bits %lo]\tE_SM_GWFILE\n",
+ (u_long) st->st_mode);
+ return E_SM_GWFILE;
+ }
+ if (bitset(SFF_NOWWFILES, flags) &&
+ bitset(S_IWOTH, st->st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[write bits %lo]\tE_SM_WWFILE\n",
+ (u_long) st->st_mode);
+ return E_SM_WWFILE;
+ }
+ if (bitset(SFF_NOGRFILES, flags) && bitset(S_IRGRP, st->st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[read bits %lo]\tE_SM_GRFILE\n",
+ (u_long) st->st_mode);
+ return E_SM_GRFILE;
+ }
+ if (bitset(SFF_NOWRFILES, flags) && bitset(S_IROTH, st->st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[read bits %lo]\tE_SM_WRFILE\n",
+ (u_long) st->st_mode);
+ return E_SM_WRFILE;
+ }
+ if (!bitset(SFF_EXECOK, flags) &&
+ bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) &&
+ bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[exec bits %lo]\tE_SM_ISEXEC]\n",
+ (u_long) st->st_mode);
+ return E_SM_ISEXEC;
+ }
+ if (bitset(SFF_NOHLINK, flags) && st->st_nlink != 1)
+ {
+ if (tTd(44, 4))
+ dprintf("\t[link count %d]\tE_SM_NOHLINK\n",
+ (int) st->st_nlink);
+ return E_SM_NOHLINK;
+ }
+
+ if (uid == 0 && bitset(SFF_OPENASROOT, flags))
+ /* EMPTY */
+ ;
+ else if (uid == 0 && !bitset(SFF_ROOTOK, flags))
+ mode >>= 6;
+ else if (st->st_uid == uid)
+ /* EMPTY */
+ ;
+ else if (uid == 0 && st->st_uid == TrustedUid)
+ /* EMPTY */
+ ;
+ else
+ {
+ mode >>= 3;
+ if (st->st_gid == gid)
+ /* EMPTY */
+ ;
+# ifndef NO_GROUP_SET
+ else if (user != NULL && !DontInitGroups &&
+ ((gr != NULL && gr->gr_gid == st->st_gid) ||
+ (gr = getgrgid(st->st_gid)) != NULL))
+ {
+ register char **gp;
+
+ for (gp = gr->gr_mem; *gp != NULL; gp++)
+ if (strcmp(*gp, user) == 0)
+ break;
+ if (*gp == NULL)
+ mode >>= 3;
+ }
+# endif /* ! NO_GROUP_SET */
+ else
+ mode >>= 3;
+ }
+ if (tTd(44, 4))
+ dprintf("\t[uid %d, nlink %d, stat %lo, mode %lo] ",
+ (int) st->st_uid, (int) st->st_nlink,
+ (u_long) st->st_mode, (u_long) mode);
+ if ((st->st_uid == uid || st->st_uid == 0 ||
+ st->st_uid == TrustedUid ||
+ !bitset(SFF_MUSTOWN, flags)) &&
+ (st->st_mode & mode) == mode)
+ {
+ if (tTd(44, 4))
+ dprintf("\tOK\n");
+ return 0;
+ }
+ if (tTd(44, 4))
+ dprintf("\tEACCES\n");
+ return EACCES;
+}
+ /*
+** SAFEDIRPATH -- check to make sure a path to a directory is safe
+**
+** Safe means not writable and owned by the right folks.
+**
+** Parameters:
+** fn -- filename to check.
+** uid -- user id to compare against.
+** gid -- group id to compare against.
+** user -- user name to compare against (used for group
+** sets).
+** flags -- modifiers:
+** SFF_ROOTOK -- ok to use root permissions to open.
+** SFF_SAFEDIRPATH -- writable directories are considered
+** to be fatal errors.
+** level -- symlink recursive level.
+** offset -- offset into fn to start checking from.
+**
+** Returns:
+** 0 -- if the directory path is "safe".
+** else -- an error number associated with the path.
+*/
+
+int
+safedirpath(fn, uid, gid, user, flags, level, offset)
+ char *fn;
+ UID_T uid;
+ GID_T gid;
+ char *user;
+ long flags;
+ int level;
+ int offset;
+{
+ int ret = 0;
+ int mode = S_IWOTH;
+ char save = '\0';
+ char *saveptr = NULL;
+ char *p, *enddir;
+ register struct group *gr = NULL;
+ char s[MAXLINKPATHLEN + 1];
+ struct stat stbuf;
+
+ /* make sure we aren't in a symlink loop */
+ if (level > MAXSYMLINKS)
+ return ELOOP;
+
+ /* special case root directory */
+ if (*fn == '\0')
+ fn = "/";
+
+ if (tTd(44, 4))
+ dprintf("safedirpath(%s, uid=%ld, gid=%ld, flags=%lx, level=%d, offset=%d):\n",
+ fn, (long) uid, (long) gid, flags, level, offset);
+
+ if (!bitnset(DBS_GROUPWRITABLEDIRPATHSAFE, DontBlameSendmail))
+ mode |= S_IWGRP;
+
+ /* Make a modifiable copy of the filename */
+ if (strlcpy(s, fn, sizeof s) >= sizeof s)
+ return EINVAL;
+
+ p = s + offset;
+ while (p != NULL)
+ {
+ /* put back character */
+ if (saveptr != NULL)
+ {
+ *saveptr = save;
+ saveptr = NULL;
+ p++;
+ }
+
+ if (*p == '\0')
+ break;
+
+ p = strchr(p, '/');
+
+ /* Special case for root directory */
+ if (p == s)
+ {
+ save = *(p + 1);
+ saveptr = p + 1;
+ *(p + 1) = '\0';
+ }
+ else if (p != NULL)
+ {
+ save = *p;
+ saveptr = p;
+ *p = '\0';
+ }
+
+ /* Heuristic: . and .. have already been checked */
+ enddir = strrchr(s, '/');
+ if (enddir != NULL &&
+ (strcmp(enddir, "/..") == 0 ||
+ strcmp(enddir, "/.") == 0))
+ continue;
+
+ if (tTd(44, 20))
+ dprintf("\t[dir %s]\n", s);
+
+# if HASLSTAT
+ ret = lstat(s, &stbuf);
+# else /* HASLSTAT */
+ ret = stat(s, &stbuf);
+# endif /* HASLSTAT */
+ if (ret < 0)
+ {
+ ret = errno;
+ break;
+ }
+
+# ifdef S_ISLNK
+ /* Follow symlinks */
+ if (S_ISLNK(stbuf.st_mode))
+ {
+ char *target;
+ char buf[MAXPATHLEN + 1];
+
+ memset(buf, '\0', sizeof buf);
+ if (readlink(s, buf, sizeof buf) < 0)
+ {
+ ret = errno;
+ break;
+ }
+
+ offset = 0;
+ if (*buf == '/')
+ {
+ target = buf;
+
+ /* If path is the same, avoid rechecks */
+ while (s[offset] == buf[offset] &&
+ s[offset] != '\0')
+ offset++;
+
+ if (s[offset] == '\0' && buf[offset] == '\0')
+ {
+ /* strings match, symlink loop */
+ return ELOOP;
+ }
+
+ /* back off from the mismatch */
+ if (offset > 0)
+ offset--;
+
+ /* Make sure we are at a directory break */
+ if (offset > 0 &&
+ s[offset] != '/' &&
+ s[offset] != '\0')
+ {
+ while (buf[offset] != '/' &&
+ offset > 0)
+ offset--;
+ }
+ if (offset > 0 &&
+ s[offset] == '/' &&
+ buf[offset] == '/')
+ {
+ /* Include the trailing slash */
+ offset++;
+ }
+ }
+ else
+ {
+ char *sptr;
+ char fullbuf[MAXLINKPATHLEN + 1];
+
+ sptr = strrchr(s, '/');
+ if (sptr != NULL)
+ {
+ *sptr = '\0';
+ offset = sptr + 1 - s;
+ if ((strlen(s) + 1 +
+ strlen(buf) + 1) > sizeof fullbuf)
+ {
+ ret = EINVAL;
+ break;
+ }
+ snprintf(fullbuf, sizeof fullbuf,
+ "%s/%s", s, buf);
+ *sptr = '/';
+ }
+ else
+ {
+ if (strlen(buf) + 1 > sizeof fullbuf)
+ {
+ ret = EINVAL;
+ break;
+ }
+ (void) strlcpy(fullbuf, buf,
+ sizeof fullbuf);
+ }
+ target = fullbuf;
+ }
+ ret = safedirpath(target, uid, gid, user, flags,
+ level + 1, offset);
+ if (ret != 0)
+ break;
+
+ /* Don't check permissions on the link file itself */
+ continue;
+ }
+#endif /* S_ISLNK */
+
+ if ((uid == 0 || bitset(SFF_SAFEDIRPATH, flags)) &&
+#ifdef S_ISVTX
+ !(bitnset(DBS_TRUSTSTICKYBIT, DontBlameSendmail) &&
+ bitset(S_ISVTX, stbuf.st_mode)) &&
+#endif /* S_ISVTX */
+ bitset(mode, stbuf.st_mode))
+ {
+ if (tTd(44, 4))
+ dprintf("\t[dir %s] mode %lo ",
+ s, (u_long) stbuf.st_mode);
+ if (bitset(SFF_SAFEDIRPATH, flags))
+ {
+ if (bitset(S_IWOTH, stbuf.st_mode))
+ ret = E_SM_WWDIR;
+ else
+ ret = E_SM_GWDIR;
+ if (tTd(44, 4))
+ dprintf("FATAL\n");
+ break;
+ }
+ if (tTd(44, 4))
+ dprintf("WARNING\n");
+ if (Verbose > 1)
+ message("051 WARNING: %s writable directory %s",
+ bitset(S_IWOTH, stbuf.st_mode)
+ ? "World"
+ : "Group",
+ s);
+ }
+ if (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags))
+ {
+ if (bitset(S_IXOTH, stbuf.st_mode))
+ continue;
+ ret = EACCES;
+ break;
+ }
+
+ /*
+ ** Let OS determine access to file if we are not
+ ** running as a privileged user. This allows ACLs
+ ** to work. Also, if opening as root, assume we can
+ ** scan the directory.
+ */
+ if (geteuid() != 0 || bitset(SFF_OPENASROOT, flags))
+ continue;
+
+ if (stbuf.st_uid == uid &&
+ bitset(S_IXUSR, stbuf.st_mode))
+ continue;
+ if (stbuf.st_gid == gid &&
+ bitset(S_IXGRP, stbuf.st_mode))
+ continue;
+# ifndef NO_GROUP_SET
+ if (user != NULL && !DontInitGroups &&
+ ((gr != NULL && gr->gr_gid == stbuf.st_gid) ||
+ (gr = getgrgid(stbuf.st_gid)) != NULL))
+ {
+ register char **gp;
+
+ for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++)
+ if (strcmp(*gp, user) == 0)
+ break;
+ if (gp != NULL && *gp != NULL &&
+ bitset(S_IXGRP, stbuf.st_mode))
+ continue;
+ }
+# endif /* ! NO_GROUP_SET */
+ if (!bitset(S_IXOTH, stbuf.st_mode))
+ {
+ ret = EACCES;
+ break;
+ }
+ }
+ if (tTd(44, 4))
+ dprintf("\t[dir %s] %s\n", fn,
+ ret == 0 ? "OK" : errstring(ret));
+ return ret;
+}
+ /*
+** SAFEOPEN -- do a file open with extra checking
+**
+** Parameters:
+** fn -- the file name to open.
+** omode -- the open-style mode flags.
+** cmode -- the create-style mode flags.
+** sff -- safefile flags.
+**
+** Returns:
+** Same as open.
+*/
+
+#ifndef O_ACCMODE
+# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
+#endif /* ! O_ACCMODE */
+
+int
+safeopen(fn, omode, cmode, sff)
+ char *fn;
+ int omode;
+ int cmode;
+ long sff;
+{
+ int rval;
+ int fd;
+ int smode;
+ struct stat stb;
+
+ if (tTd(44, 10))
+ printf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n",
+ fn, omode, cmode, sff);
+
+ if (bitset(O_CREAT, omode))
+ sff |= SFF_CREAT;
+ omode &= ~O_CREAT;
+ smode = 0;
+ switch (omode & O_ACCMODE)
+ {
+ case O_RDONLY:
+ smode = S_IREAD;
+ break;
+
+ case O_WRONLY:
+ smode = S_IWRITE;
+ break;
+
+ case O_RDWR:
+ smode = S_IREAD|S_IWRITE;
+ break;
+
+ default:
+ smode = 0;
+ break;
+ }
+ if (bitset(SFF_OPENASROOT, sff))
+ rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName,
+ sff, smode, &stb);
+ else
+ rval = safefile(fn, RealUid, RealGid, RealUserName,
+ sff, smode, &stb);
+ if (rval != 0)
+ {
+ errno = rval;
+ return -1;
+ }
+ if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff))
+ omode |= O_CREAT | (bitset(SFF_NOTEXCL, sff) ? 0 : O_EXCL);
+ else if (bitset(SFF_CREAT, sff) && bitset(O_EXCL, omode))
+ {
+ /* The file exists so an exclusive create would fail */
+ errno = EEXIST;
+ return -1;
+ }
+
+ fd = dfopen(fn, omode, cmode, sff);
+ if (fd < 0)
+ return fd;
+ if (filechanged(fn, fd, &stb))
+ {
+ syserr("554 5.3.0 cannot open: file %s changed after open", fn);
+ (void) close(fd);
+ errno = E_SM_FILECHANGE;
+ return -1;
+ }
+ return fd;
+}
+ /*
+** SAFEFOPEN -- do a file open with extra checking
+**
+** Parameters:
+** fn -- the file name to open.
+** omode -- the open-style mode flags.
+** cmode -- the create-style mode flags.
+** sff -- safefile flags.
+**
+** Returns:
+** Same as fopen.
+*/
+
+FILE *
+safefopen(fn, omode, cmode, sff)
+ char *fn;
+ int omode;
+ int cmode;
+ long sff;
+{
+ int fd;
+ int save_errno;
+ FILE *fp;
+ char *fmode;
+
+ switch (omode & O_ACCMODE)
+ {
+ case O_RDONLY:
+ fmode = "r";
+ break;
+
+ case O_WRONLY:
+ if (bitset(O_APPEND, omode))
+ fmode = "a";
+ else
+ fmode = "w";
+ break;
+
+ case O_RDWR:
+ if (bitset(O_TRUNC, omode))
+ fmode = "w+";
+ else if (bitset(O_APPEND, omode))
+ fmode = "a+";
+ else
+ fmode = "r+";
+ break;
+
+ default:
+ syserr("554 5.3.5 safefopen: unknown omode %o", omode);
+ fmode = "x";
+ }
+ fd = safeopen(fn, omode, cmode, sff);
+ if (fd < 0)
+ {
+ save_errno = errno;
+ if (tTd(44, 10))
+ dprintf("safefopen: safeopen failed: %s\n",
+ errstring(errno));
+ errno = save_errno;
+ return NULL;
+ }
+ fp = fdopen(fd, fmode);
+ if (fp != NULL)
+ return fp;
+
+ save_errno = errno;
+ if (tTd(44, 10))
+ {
+ dprintf("safefopen: fdopen(%s, %s) failed: omode=%x, sff=%lx, err=%s\n",
+ fn, fmode, omode, sff, errstring(errno));
+ }
+ (void) close(fd);
+ errno = save_errno;
+ return NULL;
+}
+ /*
+** FILECHANGED -- check to see if file changed after being opened
+**
+** Parameters:
+** fn -- pathname of file to check.
+** fd -- file descriptor to check.
+** stb -- stat structure from before open.
+**
+** Returns:
+** TRUE -- if a problem was detected.
+** FALSE -- if this file is still the same.
+*/
+
+bool
+filechanged(fn, fd, stb)
+ char *fn;
+ int fd;
+ struct stat *stb;
+{
+ struct stat sta;
+
+ if (stb->st_mode == ST_MODE_NOFILE)
+ {
+# if HASLSTAT && BOGUS_O_EXCL
+ /* only necessary if exclusive open follows symbolic links */
+ if (lstat(fn, stb) < 0 || stb->st_nlink != 1)
+ return TRUE;
+# else /* HASLSTAT && BOGUS_O_EXCL */
+ return FALSE;
+# endif /* HASLSTAT && BOGUS_O_EXCL */
+ }
+ if (fstat(fd, &sta) < 0)
+ return TRUE;
+
+ if (sta.st_nlink != stb->st_nlink ||
+ sta.st_dev != stb->st_dev ||
+ sta.st_ino != stb->st_ino ||
+# if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */
+ sta.st_gen != stb->st_gen ||
+# endif /* HAS_ST_GEN && 0 */
+ sta.st_uid != stb->st_uid ||
+ sta.st_gid != stb->st_gid)
+ {
+ if (tTd(44, 8))
+ {
+ dprintf("File changed after opening:\n");
+ dprintf(" nlink = %ld/%ld\n",
+ (long) stb->st_nlink, (long) sta.st_nlink);
+ dprintf(" dev = %ld/%ld\n",
+ (long) stb->st_dev, (long) sta.st_dev);
+ if (sizeof sta.st_ino > sizeof (long))
+ {
+ dprintf(" ino = %s/",
+ quad_to_string(stb->st_ino));
+ dprintf("%s\n",
+ quad_to_string(sta.st_ino));
+ }
+ else
+ dprintf(" ino = %lu/%lu\n",
+ (unsigned long) stb->st_ino,
+ (unsigned long) sta.st_ino);
+# if HAS_ST_GEN
+ dprintf(" gen = %ld/%ld\n",
+ (long) stb->st_gen, (long) sta.st_gen);
+# endif /* HAS_ST_GEN */
+ dprintf(" uid = %ld/%ld\n",
+ (long) stb->st_uid, (long) sta.st_uid);
+ dprintf(" gid = %ld/%ld\n",
+ (long) stb->st_gid, (long) sta.st_gid);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+ /*
+** DFOPEN -- determined file open
+**
+** This routine has the semantics of open, except that it will
+** keep trying a few times to make this happen. The idea is that
+** on very loaded systems, we may run out of resources (inodes,
+** whatever), so this tries to get around it.
+*/
+
+int
+dfopen(filename, omode, cmode, sff)
+ char *filename;
+ int omode;
+ int cmode;
+ long sff;
+{
+ register int tries;
+ int fd = -1;
+ struct stat st;
+
+ for (tries = 0; tries < 10; tries++)
+ {
+ (void) sleep((unsigned) (10 * tries));
+ errno = 0;
+ fd = open(filename, omode, cmode);
+ if (fd >= 0)
+ break;
+ switch (errno)
+ {
+ case ENFILE: /* system file table full */
+ case EINTR: /* interrupted syscall */
+#ifdef ETXTBSY
+ case ETXTBSY: /* Apollo: net file locked */
+#endif /* ETXTBSY */
+ continue;
+ }
+ break;
+ }
+ if (!bitset(SFF_NOLOCK, sff) &&
+ fd >= 0 &&
+ fstat(fd, &st) >= 0 &&
+ S_ISREG(st.st_mode))
+ {
+ int locktype;
+
+ /* lock the file to avoid accidental conflicts */
+ if ((omode & O_ACCMODE) != O_RDONLY)
+ locktype = LOCK_EX;
+ else
+ locktype = LOCK_SH;
+ if (!lockfile(fd, filename, NULL, locktype))
+ {
+ int save_errno = errno;
+
+ (void) close(fd);
+ fd = -1;
+ errno = save_errno;
+ }
+ else
+ errno = 0;
+ }
+ return fd;
+}
diff --git a/contrib/sendmail/libsmutil/snprintf.c b/contrib/sendmail/libsmutil/snprintf.c
new file mode 100644
index 000000000000..297fbe83567a
--- /dev/null
+++ b/contrib/sendmail/libsmutil/snprintf.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#ifndef lint
+static char id[] = "@(#)$Id: snprintf.c,v 8.27.16.1 2000/07/15 17:35:18 gshapiro Exp $";
+#endif /* ! lint */
+
+#include <sendmail.h>
+
+ /*
+** SNPRINTF, VSNPRINT -- counted versions of printf
+**
+** These versions have been grabbed off the net. They have been
+** cleaned up to compile properly and support for .precision and
+** %lx has been added.
+*/
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (sm_dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ **************************************************************/
+
+/*static char _id[] = "$OrigId: snprintf.c,v 1.2 1995/10/09 11:19:47 roberto Exp $";*/
+void sm_dopr();
+char *DoprEnd;
+int SnprfOverflow;
+
+#if !HASSNPRINTF && !SNPRINTF_IS_BROKEN
+# define sm_snprintf snprintf
+# ifndef luna2
+# define sm_vsnprintf vsnprintf
+extern int vsnprintf __P((char *, size_t, const char *, va_list));
+# endif /* ! luna2 */
+#endif /* !HASSNPRINTF && !SNPRINTF_IS_BROKEN */
+
+/* VARARGS3 */
+int
+# ifdef __STDC__
+sm_snprintf(char *str, size_t count, const char *fmt, ...)
+# else /* __STDC__ */
+sm_snprintf(str, count, fmt, va_alist)
+ char *str;
+ size_t count;
+ const char *fmt;
+ va_dcl
+# endif /* __STDC__ */
+{
+ int len;
+ VA_LOCAL_DECL
+
+ VA_START(fmt);
+ len = sm_vsnprintf(str, count, fmt, ap);
+ VA_END;
+ return len;
+}
+
+int
+sm_vsnprintf(str, count, fmt, args)
+ char *str;
+ size_t count;
+ const char *fmt;
+ va_list args;
+{
+ str[0] = 0;
+ DoprEnd = str + count - 1;
+ SnprfOverflow = 0;
+ sm_dopr( str, fmt, args );
+ if (count > 0)
+ DoprEnd[0] = 0;
+ if (SnprfOverflow && tTd(57, 2))
+ dprintf("\nvsnprintf overflow, len = %ld, str = %s",
+ (long) count, shortenstring(str, MAXSHORTSTR));
+ return strlen(str);
+}
+
+/*
+ * sm_dopr(): poor man's version of doprintf
+ */
+
+void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth));
+void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad));
+void dostr __P(( char * , int ));
+char *output;
+void dopr_outch __P(( int c ));
+int SyslogErrno;
+
+void
+sm_dopr( buffer, format, args )
+ char *buffer;
+ const char *format;
+ va_list args;
+{
+ int ch;
+ long value;
+ int longflag = 0;
+ int pointflag = 0;
+ int maxwidth = 0;
+ char *strvalue;
+ int ljust;
+ int len;
+ int zpad;
+#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
+
+
+ output = buffer;
+ while( (ch = *format++) != '\0' ){
+ switch( ch ){
+ case '%':
+ ljust = len = zpad = maxwidth = 0;
+ longflag = pointflag = 0;
+ nextch:
+ ch = *format++;
+ switch( ch ){
+ case 0:
+ dostr( "**end of format**" , 0);
+ return;
+ case '-': ljust = 1; goto nextch;
+ case '0': /* set zero padding if len not set */
+ if(len==0 && !pointflag) zpad = '0';
+ /* FALLTHROUGH */
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ if (pointflag)
+ maxwidth = maxwidth*10 + ch - '0';
+ else
+ len = len*10 + ch - '0';
+ goto nextch;
+ case '*':
+ if (pointflag)
+ maxwidth = va_arg( args, int );
+ else
+ len = va_arg( args, int );
+ goto nextch;
+ case '.': pointflag = 1; goto nextch;
+ case 'l': longflag = 1; goto nextch;
+ case 'u': case 'U':
+ /*fmtnum(value,base,dosign,ljust,len,zpad) */
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 10,0, ljust, len, zpad ); break;
+ case 'o': case 'O':
+ /*fmtnum(value,base,dosign,ljust,len,zpad) */
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 8,0, ljust, len, zpad ); break;
+ case 'd': case 'D':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 10,1, ljust, len, zpad ); break;
+ case 'x':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value, 16,0, ljust, len, zpad ); break;
+ case 'X':
+ if( longflag ){
+ value = va_arg( args, long );
+ } else {
+ value = va_arg( args, int );
+ }
+ fmtnum( value,-16,0, ljust, len, zpad ); break;
+ case 's':
+ strvalue = va_arg( args, char *);
+ 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 );
+ dopr_outch( ch ); break;
+ case 'm':
+#if HASSTRERROR
+ dostr(strerror(SyslogErrno), 0);
+#else /* HASSTRERROR */
+ if (SyslogErrno < 0 || SyslogErrno >= sys_nerr)
+ {
+ dostr("Error ", 0);
+ fmtnum(SyslogErrno, 10, 0, 0, 0, 0);
+ }
+ else
+ dostr((char *)sys_errlist[SyslogErrno], 0);
+#endif /* HASSTRERROR */
+ break;
+
+ case '%': dopr_outch( ch ); continue;
+ default:
+ dostr( "???????" , 0);
+ }
+ break;
+ default:
+ dopr_outch( ch );
+ break;
+ }
+ }
+ *output = 0;
+}
+
+void
+fmtstr( value, ljust, len, zpad, maxwidth )
+ char *value;
+ int ljust, len, zpad, maxwidth;
+{
+ int padlen, strleng; /* amount to pad */
+
+ if( value == 0 ){
+ value = "<NULL>";
+ }
+ for( strleng = 0; value[strleng]; ++ strleng ); /* strlen */
+ if (strleng > maxwidth && maxwidth)
+ strleng = maxwidth;
+ padlen = len - strleng;
+ if( padlen < 0 ) padlen = 0;
+ if( ljust ) padlen = -padlen;
+ while( padlen > 0 ) {
+ dopr_outch( ' ' );
+ --padlen;
+ }
+ dostr( value, maxwidth );
+ while( padlen < 0 ) {
+ dopr_outch( ' ' );
+ ++padlen;
+ }
+}
+
+void
+fmtnum( value, base, dosign, ljust, len, zpad )
+ long value;
+ int base, dosign, ljust, len, zpad;
+{
+ int signvalue = 0;
+ unsigned long uvalue;
+ char convert[20];
+ int place = 0;
+ int padlen = 0; /* amount to pad */
+ int caps = 0;
+
+ /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
+ value, base, dosign, ljust, len, zpad )); */
+ uvalue = value;
+ if( dosign ){
+ if( value < 0 ) {
+ signvalue = '-';
+ uvalue = -value;
+ }
+ }
+ if( base < 0 ){
+ caps = 1;
+ base = -base;
+ }
+ do{
+ convert[place++] =
+ (caps? "0123456789ABCDEF":"0123456789abcdef")
+ [uvalue % (unsigned)base ];
+ uvalue = (uvalue / (unsigned)base );
+ }while(uvalue);
+ convert[place] = 0;
+ padlen = len - place;
+ if( padlen < 0 ) padlen = 0;
+ if( ljust ) padlen = -padlen;
+ /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
+ convert,place,signvalue,padlen)); */
+ if( zpad && padlen > 0 ){
+ if( signvalue ){
+ dopr_outch( signvalue );
+ --padlen;
+ signvalue = 0;
+ }
+ while( padlen > 0 ){
+ dopr_outch( zpad );
+ --padlen;
+ }
+ }
+ while( padlen > 0 ) {
+ dopr_outch( ' ' );
+ --padlen;
+ }
+ if( signvalue ) dopr_outch( signvalue );
+ while( place > 0 ) dopr_outch( convert[--place] );
+ while( padlen < 0 ){
+ dopr_outch( ' ' );
+ ++padlen;
+ }
+}
+
+void
+dostr( str , cut)
+ char *str;
+ int cut;
+{
+ if (cut) {
+ while(*str && cut-- > 0) dopr_outch(*str++);
+ } else {
+ while(*str) dopr_outch(*str++);
+ }
+}
+
+void
+dopr_outch( c )
+ int c;
+{
+#if 0
+ if( iscntrl(c) && c != '\n' && c != '\t' ){
+ c = '@' + (c & 0x1F);
+ if( DoprEnd == 0 || output < DoprEnd )
+ *output++ = '^';
+ }
+#endif /* 0 */
+ if( DoprEnd == 0 || output < DoprEnd )
+ *output++ = c;
+ else
+ SnprfOverflow++;
+}
+
+ /*
+** QUAD_TO_STRING -- Convert a quad type to a string.
+**
+** Convert a quad type to a string. This must be done
+** separately as %lld/%qd are not supported by snprint()
+** and adding support would slow down systems which only
+** emulate the data type.
+**
+** Parameters:
+** value -- number to convert to a string.
+**
+** Returns:
+** pointer to a string.
+*/
+
+char *
+quad_to_string(value)
+ QUAD_T value;
+{
+ char *formatstr;
+ static char buf[64];
+
+ /*
+ ** Use sprintf() instead of snprintf() since snprintf()
+ ** does not support %qu or %llu. The buffer is large enough
+ ** to hold the string so there is no danger of buffer
+ ** overflow.
+ */
+
+#if NEED_PERCENTQ
+ formatstr = "%qu";
+#else /* NEED_PERCENTQ */
+ formatstr = "%llu";
+#endif /* NEED_PERCENTQ */
+ sprintf(buf, formatstr, value);
+ return buf;
+}
+ /*
+** SHORTENSTRING -- return short version of a string
+**
+** If the string is already short, just return it. If it is too
+** long, return the head and tail of the string.
+**
+** Parameters:
+** s -- the string to shorten.
+** m -- the max length of the string (strlen()).
+**
+** Returns:
+** Either s or a short version of s.
+*/
+
+char *
+shortenstring(s, m)
+ register const char *s;
+ int m;
+{
+ int l;
+ static char buf[MAXSHORTSTR + 1];
+
+ l = strlen(s);
+ if (l < m)
+ return (char *) s;
+ if (m > MAXSHORTSTR)
+ m = MAXSHORTSTR;
+ else if (m < 10)
+ {
+ if (m < 5)
+ {
+ (void) strlcpy(buf, s, m + 1);
+ return buf;
+ }
+ (void) strlcpy(buf, s, m - 2);
+ (void) strlcat(buf, "...", sizeof buf);
+ return buf;
+ }
+ m = (m - 3) / 2;
+ (void) strlcpy(buf, s, m + 1);
+ (void) strlcat(buf, "...", sizeof buf);
+ (void) strlcat(buf, s + l - m, sizeof buf);
+ return buf;
+}
diff --git a/contrib/sendmail/libsmutil/strl.c b/contrib/sendmail/libsmutil/strl.c
new file mode 100644
index 000000000000..b0a7662b90ef
--- /dev/null
+++ b/contrib/sendmail/libsmutil/strl.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#ifndef lint
+static char id[] = "@(#)$Id: strl.c,v 8.5.14.1 2000/05/12 20:46:17 ca Exp $";
+#endif /* ! lint */
+
+#include <sendmail.h>
+
+#if !HASSTRL
+ /*
+** strlcpy -- copy string obeying length and '\0' terminate it
+**
+** terminates with '\0' if len > 0
+**
+** Parameters:
+** dst -- "destination" string.
+** src -- "from" string.
+** len -- length of space available in "destination" string.
+**
+** Returns:
+** total length of the string tried to create (=strlen(src))
+** if this is greater than len then an overflow would have
+** occurred.
+*/
+
+size_t
+strlcpy(dst, src, len)
+ register char *dst;
+ register const char *src;
+ size_t len;
+{
+ register size_t i;
+
+ if (len-- <= 0)
+ return strlen(src);
+ for (i = 0; i < len && (dst[i] = src[i]) != 0; i++)
+ continue;
+ dst[i] = '\0';
+ if (src[i] == '\0')
+ return i;
+ else
+ return i + strlen(src + i);
+}
+ /*
+** strlcat -- catenate strings obeying length and '\0' terminate it
+**
+** strlcat will append at most len - strlen(dst) - 1 chars.
+** terminates with '\0' if len > 0
+**
+** Parameters:
+** dst -- "destination" string.
+** src -- "from" string.
+** len -- max. length of "destination" string.
+**
+** Returns:
+** total length of the string tried to create
+** (= initial length of dst + length of src)
+** if this is greater than len then an overflow would have
+** occurred.
+*/
+
+size_t
+strlcat(dst, src, len)
+ register char *dst;
+ register const char *src;
+ size_t len;
+{
+ register size_t i, j, o;
+
+ o = strlen(dst);
+ if (len < o + 1)
+ return o + strlen(src);
+ len -= o + 1;
+ for (i = 0, j = o; i < len && (dst[j] = src[i]) != 0; i++, j++)
+ continue;
+ dst[j] = '\0';
+ if (src[i] == '\0')
+ return j;
+ else
+ return j + strlen(src + i);
+}
+
+#endif /* !HASSTRL */