summaryrefslogtreecommitdiff
path: root/usr.sbin/sendmail/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/sendmail/src/util.c')
-rw-r--r--usr.sbin/sendmail/src/util.c393
1 files changed, 338 insertions, 55 deletions
diff --git a/usr.sbin/sendmail/src/util.c b/usr.sbin/sendmail/src/util.c
index 7abc67176cb49..c3eb822744b3a 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.109 (Berkeley) 11/16/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 *
@@ -990,6 +1012,15 @@ putxline(l, mci, pxflags)
if (TrafficLogFile != NULL)
(void) putc('.', TrafficLogFile);
}
+ else if (l[0] == 'F' && slop == 0 &&
+ bitset(PXLF_MAPFROM, pxflags) &&
+ strncmp(l, "From ", 5) == 0 &&
+ bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
+ {
+ (void) putc('>', mci->mci_out);
+ if (TrafficLogFile != NULL)
+ (void) putc('>', TrafficLogFile);
+ }
if (TrafficLogFile != NULL)
fprintf(TrafficLogFile, "%.*s\n", p - l, l);
for ( ; l < p; ++l)
@@ -1109,9 +1140,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 +1372,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 +1505,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 +1522,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 +1661,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 +1936,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 +1982,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 +2031,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 +2042,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 +2149,159 @@ 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;
+ extern void proc_list_probe __P((void));
+
+ for (i = 0; i < ProcListSize; i++)
+ {
+ if (ProcListVec[i] == NO_PID)
+ break;
+ }
+ if (i >= ProcListSize)
+ {
+ /* probe the existing vector to avoid growing infinitely */
+ proc_list_probe();
+
+ /* now scan again */
+ 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;
+ break;
+ }
+ }
+ if (CurChildren > 0)
+ CurChildren--;
+}
+ /*
+** PROC_LIST_PROBE -- probe processes in the list to see if they still exist
+**
+** Parameters:
+** none
+**
+** Returns:
+** none
+*/
+
+void
+proc_list_probe()
+{
+ int i;
+
+ for (i = 0; i < ProcListSize; i++)
+ {
+ if (ProcListVec[i] == NO_PID)
+ continue;
+ if (kill(ProcListVec[i], 0) < 0)
+ {
+#ifdef LOG
+ if (LogLevel > 3)
+ syslog(LOG_DEBUG, "proc_list_probe: lost pid %d",
+ ProcListVec[i]);
+#endif
+ ProcListVec[i] = NO_PID;
+ CurChildren--;
+ }
+ }
+ if (CurChildren < 0)
+ CurChildren = 0;
+}