home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)util.c 5.20 (Berkeley) 3/8/91";
- #endif /* not lint */
-
- # include <stdio.h>
- # include <sys/types.h>
- # include <sys/stat.h>
- # include <sysexits.h>
- # include <errno.h>
- # include "sendmail.h"
-
- /*
- ** STRIPQUOTES -- Strip quotes & quote bits from a string.
- **
- ** Runs through a string and strips off unquoted quote
- ** characters and quote bits. This is done in place.
- **
- ** Parameters:
- ** s -- the string to strip.
- ** qf -- if set, remove actual `` " '' characters
- ** as well as the quote bits.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** none.
- **
- ** Called By:
- ** deliver
- */
-
- stripquotes(s, qf)
- char *s;
- bool qf;
- {
- register char *p;
- register char *q;
- register char c;
-
- if (s == NULL)
- return;
-
- for (p = q = s; (c = *p++) != '\0'; )
- {
- if (c != '"' || !qf)
- *q++ = c & 0177;
- }
- *q = '\0';
- }
- /*
- ** QSTRLEN -- give me the string length assuming 0200 bits add a char
- **
- ** Parameters:
- ** s -- the string to measure.
- **
- ** Reurns:
- ** The length of s, including space for backslash escapes.
- **
- ** Side Effects:
- ** none.
- */
-
- qstrlen(s)
- register char *s;
- {
- register int l = 0;
- register char c;
-
- while ((c = *s++) != '\0')
- {
- if (bitset(0200, c))
- l++;
- l++;
- }
- return (l);
- }
- /*
- ** CAPITALIZE -- return a copy of a string, properly capitalized.
- **
- ** Parameters:
- ** s -- the string to capitalize.
- **
- ** Returns:
- ** a pointer to a properly capitalized string.
- **
- ** Side Effects:
- ** none.
- */
-
- char *
- capitalize(s)
- register char *s;
- {
- static char buf[50];
- register char *p;
-
- p = buf;
-
- for (;;)
- {
- while (!isalpha(*s) && *s != '\0')
- *p++ = *s++;
- if (*s == '\0')
- break;
- *p++ = toupper(*s);
- s++;
- while (isalpha(*s))
- *p++ = *s++;
- }
-
- *p = '\0';
- return (buf);
- }
- /*
- ** XALLOC -- Allocate memory and bitch wildly on failure.
- **
- ** THIS IS A CLUDGE. This should be made to give a proper
- ** error -- but after all, what can we do?
- **
- ** Parameters:
- ** sz -- size of area to allocate.
- **
- ** Returns:
- ** pointer to data region.
- **
- ** Side Effects:
- ** Memory is allocated.
- */
-
- char *
- xalloc(sz)
- register int sz;
- {
- register char *p;
- extern char *malloc();
-
- p = malloc((unsigned) sz);
- if (p == NULL)
- {
- syserr("Out of memory!!");
- abort();
- /* exit(EX_UNAVAILABLE); */
- }
- return (p);
- }
- /*
- ** COPYPLIST -- copy list of pointers.
- **
- ** This routine is the equivalent of newstr for lists of
- ** pointers.
- **
- ** Parameters:
- ** list -- list of pointers to copy.
- ** Must be NULL terminated.
- ** copycont -- if TRUE, copy the contents of the vector
- ** (which must be a string) also.
- **
- ** Returns:
- ** a copy of 'list'.
- **
- ** Side Effects:
- ** none.
- */
-
- char **
- copyplist(list, copycont)
- char **list;
- bool copycont;
- {
- register char **vp;
- register char **newvp;
-
- for (vp = list; *vp != NULL; vp++)
- continue;
-
- vp++;
-
- newvp = (char **) xalloc((int) (vp - list) * sizeof *vp);
- bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp);
-
- if (copycont)
- {
- for (vp = newvp; *vp != NULL; vp++)
- *vp = newstr(*vp);
- }
-
- return (newvp);
- }
- /*
- ** PRINTAV -- print argument vector.
- **
- ** Parameters:
- ** av -- argument vector.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** prints av.
- */
-
- printav(av)
- register char **av;
- {
- while (*av != NULL)
- {
- if (tTd(0, 44))
- printf("\n\t%08x=", *av);
- else
- (void) putchar(' ');
- xputs(*av++);
- }
- (void) putchar('\n');
- }
- /*
- ** LOWER -- turn letter into lower case.
- **
- ** Parameters:
- ** c -- character to turn into lower case.
- **
- ** Returns:
- ** c, in lower case.
- **
- ** Side Effects:
- ** none.
- */
-
- char
- lower(c)
- register char c;
- {
- return(isascii(c) && isupper(c) ? tolower(c) : c);
- }
- /*
- ** XPUTS -- put string doing control escapes.
- **
- ** Parameters:
- ** s -- string to put.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** output to stdout
- */
-
- xputs(s)
- register char *s;
- {
- register char c;
-
- if (s == NULL)
- {
- printf("<null>");
- return;
- }
- (void) putchar('"');
- while ((c = *s++) != '\0')
- {
- if (!isascii(c))
- {
- (void) putchar('\\');
- c &= 0177;
- }
- if (c < 040 || c >= 0177)
- {
- (void) putchar('^');
- c ^= 0100;
- }
- (void) putchar(c);
- }
- (void) putchar('"');
- (void) fflush(stdout);
- }
- /*
- ** MAKELOWER -- Translate a line into lower case
- **
- ** Parameters:
- ** p -- the string to translate. If NULL, return is
- ** immediate.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** String pointed to by p is translated to lower case.
- **
- ** Called By:
- ** parse
- */
-
- makelower(p)
- register char *p;
- {
- register char c;
-
- if (p == NULL)
- return;
- for (; (c = *p) != '\0'; p++)
- if (isascii(c) && isupper(c))
- *p = tolower(c);
- }
- /*
- ** BUILDFNAME -- build full name from gecos style entry.
- **
- ** This routine interprets the strange entry that would appear
- ** in the GECOS field of the password file.
- **
- ** Parameters:
- ** p -- name to build.
- ** login -- the login name of this user (for &).
- ** buf -- place to put the result.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** none.
- */
-
- buildfname(p, login, buf)
- register char *p;
- char *login;
- char *buf;
- {
- register char *bp = buf;
-
- if (*p == '*')
- p++;
- while (*p != '\0' && *p != ',' && *p != ';' && *p != '%')
- {
- if (*p == '&')
- {
- (void) strcpy(bp, login);
- *bp = toupper(*bp);
- while (*bp != '\0')
- bp++;
- p++;
- }
- else
- *bp++ = *p++;
- }
- *bp = '\0';
- }
- /*
- ** SAFEFILE -- return true if a file exists and is safe for a user.
- **
- ** Parameters:
- ** fn -- filename to check.
- ** uid -- uid to compare against.
- ** mode -- mode bits that must match.
- **
- ** Returns:
- ** TRUE if fn exists, is owned by uid, and matches mode.
- ** FALSE otherwise.
- **
- ** Side Effects:
- ** none.
- */
-
- bool
- safefile(fn, uid, mode)
- char *fn;
- int uid;
- int mode;
- {
- struct stat stbuf;
-
- if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid &&
- (stbuf.st_mode & mode) == mode)
- return (TRUE);
- errno = 0;
- return (FALSE);
- }
- /*
- ** FIXCRLF -- fix <CR><LF> in line.
- **
- ** Looks for the <CR><LF> combination and turns it into the
- ** UNIX canonical <NL> character. It only takes one line,
- ** i.e., it is assumed that the first <NL> found is the end
- ** of the line.
- **
- ** Parameters:
- ** line -- the line to fix.
- ** stripnl -- if true, strip the newline also.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** line is changed in place.
- */
-
- fixcrlf(line, stripnl)
- char *line;
- bool stripnl;
- {
- register char *p;
-
- p = index(line, '\n');
- if (p == NULL)
- return;
- if (p > line && p[-1] == '\r')
- p--;
- if (!stripnl)
- *p++ = '\n';
- *p = '\0';
- }
- /*
- ** DFOPEN -- determined file open
- **
- ** This routine has the semantics of fopen, 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.
- */
-
- FILE *
- dfopen(filename, mode)
- char *filename;
- char *mode;
- {
- register int tries;
- register FILE *fp;
-
- for (tries = 0; tries < 10; tries++)
- {
- sleep((unsigned) (10 * tries));
- errno = 0;
- fp = fopen(filename, mode);
- if (fp != NULL)
- break;
- if (errno != ENFILE && errno != EINTR)
- break;
- }
- errno = 0;
- return (fp);
- }
- /*
- ** PUTLINE -- put a line like fputs obeying SMTP conventions
- **
- ** This routine always guarantees outputing a newline (or CRLF,
- ** as appropriate) at the end of the string.
- **
- ** Parameters:
- ** l -- line to put.
- ** fp -- file to put it onto.
- ** m -- the mailer used to control output.
- **
- ** Returns:
- ** none
- **
- ** Side Effects:
- ** output of l to fp.
- */
-
- # define SMTPLINELIM 990 /* maximum line length */
-
- putline(l, fp, m)
- register char *l;
- FILE *fp;
- MAILER *m;
- {
- register char *p;
- register char svchar;
-
- /* strip out 0200 bits -- these can look like TELNET protocol */
- if (bitnset(M_LIMITS, m->m_flags))
- {
- for (p = l; svchar = *p; ++p)
- if (svchar & 0200)
- *p = svchar &~ 0200;
- }
-
- do
- {
- /* find the end of the line */
- p = index(l, '\n');
- if (p == NULL)
- p = &l[strlen(l)];
-
- /* check for line overflow */
- while ((p - l) > SMTPLINELIM && bitnset(M_LIMITS, m->m_flags))
- {
- register char *q = &l[SMTPLINELIM - 1];
-
- svchar = *q;
- *q = '\0';
- if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
- (void) putc('.', fp);
- fputs(l, fp);
- (void) putc('!', fp);
- fputs(m->m_eol, fp);
- *q = svchar;
- l = q;
- }
-
- /* output last part */
- if (l[0] == '.' && bitnset(M_XDOT, m->m_flags))
- (void) putc('.', fp);
- for ( ; l < p; ++l)
- (void) putc(*l, fp);
- fputs(m->m_eol, fp);
- if (*l == '\n')
- ++l;
- } while (l[0] != '\0');
- }
- /*
- ** XUNLINK -- unlink a file, doing logging as appropriate.
- **
- ** Parameters:
- ** f -- name of file to unlink.
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** f is unlinked.
- */
-
- xunlink(f)
- char *f;
- {
- register int i;
-
- # ifdef LOG
- if (LogLevel > 20)
- syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f);
- # endif LOG
-
- i = unlink(f);
- # ifdef LOG
- if (i < 0 && LogLevel > 21)
- syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno);
- # endif LOG
- }
- /*
- ** SFGETS -- "safe" fgets -- times out and ignores random interrupts.
- **
- ** Parameters:
- ** buf -- place to put the input line.
- ** siz -- size of buf.
- ** fp -- file to read from.
- **
- ** Returns:
- ** NULL on error (including timeout). This will also leave
- ** buf containing a null string.
- ** buf otherwise.
- **
- ** Side Effects:
- ** none.
- */
-
- static jmp_buf CtxReadTimeout;
-
- char *
- sfgets(buf, siz, fp)
- char *buf;
- int siz;
- FILE *fp;
- {
- register EVENT *ev = NULL;
- register char *p;
- static int readtimeout();
-
- /* set the timeout */
- if (ReadTimeout != 0)
- {
- if (setjmp(CtxReadTimeout) != 0)
- {
- # ifdef LOG
- syslog(LOG_NOTICE,
- "timeout waiting for input from %s\n",
- RealHostName? RealHostName: "local");
- # endif
- errno = 0;
- usrerr("451 timeout waiting for input");
- buf[0] = '\0';
- return (NULL);
- }
- ev = setevent((time_t) ReadTimeout, readtimeout, 0);
- }
-
- /* try to read */
- p = NULL;
- while (p == NULL && !feof(fp) && !ferror(fp))
- {
- errno = 0;
- p = fgets(buf, siz, fp);
- if (errno == EINTR)
- clearerr(fp);
- }
-
- /* clear the event if it has not sprung */
- clrevent(ev);
-
- /* clean up the books and exit */
- LineNumber++;
- if (p == NULL)
- {
- buf[0] = '\0';
- return (NULL);
- }
- for (p = buf; *p != '\0'; p++)
- *p &= ~0200;
- return (buf);
- }
-
- static
- readtimeout()
- {
- longjmp(CtxReadTimeout, 1);
- }
- /*
- ** FGETFOLDED -- like fgets, but know about folded lines.
- **
- ** Parameters:
- ** buf -- place to put result.
- ** n -- bytes available.
- ** f -- file to read from.
- **
- ** Returns:
- ** buf on success, NULL on error or EOF.
- **
- ** Side Effects:
- ** buf gets lines from f, with continuation lines (lines
- ** with leading white space) appended. CRLF's are mapped
- ** into single newlines. Any trailing NL is stripped.
- */
-
- char *
- fgetfolded(buf, n, f)
- char *buf;
- register int n;
- FILE *f;
- {
- register char *p = buf;
- register int i;
-
- n--;
- while ((i = getc(f)) != EOF)
- {
- if (i == '\r')
- {
- i = getc(f);
- if (i != '\n')
- {
- if (i != EOF)
- (void) ungetc(i, f);
- i = '\r';
- }
- }
- if (--n > 0)
- *p++ = i;
- if (i == '\n')
- {
- LineNumber++;
- i = getc(f);
- if (i != EOF)
- (void) ungetc(i, f);
- if (i != ' ' && i != '\t')
- {
- *--p = '\0';
- return (buf);
- }
- }
- }
- return (NULL);
- }
- /*
- ** CURTIME -- return current time.
- **
- ** Parameters:
- ** none.
- **
- ** Returns:
- ** the current time.
- **
- ** Side Effects:
- ** none.
- */
-
- time_t
- curtime()
- {
- auto time_t t;
-
- (void) time(&t);
- return (t);
- }
- /*
- ** ATOBOOL -- convert a string representation to boolean.
- **
- ** Defaults to "TRUE"
- **
- ** Parameters:
- ** s -- string to convert. Takes "tTyY" as true,
- ** others as false.
- **
- ** Returns:
- ** A boolean representation of the string.
- **
- ** Side Effects:
- ** none.
- */
-
- bool
- atobool(s)
- register char *s;
- {
- if (*s == '\0' || index("tTyY", *s) != NULL)
- return (TRUE);
- return (FALSE);
- }
- /*
- ** ATOOCT -- convert a string representation to octal.
- **
- ** Parameters:
- ** s -- string to convert.
- **
- ** Returns:
- ** An integer representing the string interpreted as an
- ** octal number.
- **
- ** Side Effects:
- ** none.
- */
-
- atooct(s)
- register char *s;
- {
- register int i = 0;
-
- while (*s >= '0' && *s <= '7')
- i = (i << 3) | (*s++ - '0');
- return (i);
- }
- /*
- ** WAITFOR -- wait for a particular process id.
- **
- ** Parameters:
- ** pid -- process id to wait for.
- **
- ** Returns:
- ** status of pid.
- ** -1 if pid never shows up.
- **
- ** Side Effects:
- ** none.
- */
-
- waitfor(pid)
- int pid;
- {
- auto int st;
- int i;
-
- do
- {
- errno = 0;
- i = wait(&st);
- } while ((i >= 0 || errno == EINTR) && i != pid);
- if (i < 0)
- st = -1;
- return (st);
- }
- /*
- ** BITINTERSECT -- tell if two bitmaps intersect
- **
- ** Parameters:
- ** a, b -- the bitmaps in question
- **
- ** Returns:
- ** TRUE if they have a non-null intersection
- ** FALSE otherwise
- **
- ** Side Effects:
- ** none.
- */
-
- bool
- bitintersect(a, b)
- BITMAP a;
- BITMAP b;
- {
- int i;
-
- for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
- if ((a[i] & b[i]) != 0)
- return (TRUE);
- return (FALSE);
- }
- /*
- ** BITZEROP -- tell if a bitmap is all zero
- **
- ** Parameters:
- ** map -- the bit map to check
- **
- ** Returns:
- ** TRUE if map is all zero.
- ** FALSE if there are any bits set in map.
- **
- ** Side Effects:
- ** none.
- */
-
- bool
- bitzerop(map)
- BITMAP map;
- {
- int i;
-
- for (i = BITMAPBYTES / sizeof (int); --i >= 0; )
- if (map[i] != 0)
- return (FALSE);
- return (TRUE);
- }
-