util.c revision 43730
138032Speter/* 238032Speter * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 438032Speter * Copyright (c) 1988, 1993 538032Speter * The Regents of the University of California. All rights reserved. 638032Speter * 738032Speter * By using this file, you agree to the terms and conditions set 838032Speter * forth in the LICENSE file which can be found at the top level of 938032Speter * the sendmail distribution. 1038032Speter * 1138032Speter */ 1238032Speter 1338032Speter#ifndef lint 1443730Speterstatic char sccsid[] = "@(#)util.c 8.168 (Berkeley) 1/21/1999"; 1538032Speter#endif /* not lint */ 1638032Speter 1738032Speter# include "sendmail.h" 1838032Speter# include <sysexits.h> 1938032Speter/* 2038032Speter** STRIPQUOTES -- Strip quotes & quote bits from a string. 2138032Speter** 2238032Speter** Runs through a string and strips off unquoted quote 2338032Speter** characters and quote bits. This is done in place. 2438032Speter** 2538032Speter** Parameters: 2638032Speter** s -- the string to strip. 2738032Speter** 2838032Speter** Returns: 2938032Speter** none. 3038032Speter** 3138032Speter** Side Effects: 3238032Speter** none. 3338032Speter** 3438032Speter** Called By: 3538032Speter** deliver 3638032Speter*/ 3738032Speter 3838032Spetervoid 3938032Speterstripquotes(s) 4038032Speter char *s; 4138032Speter{ 4238032Speter register char *p; 4338032Speter register char *q; 4438032Speter register char c; 4538032Speter 4638032Speter if (s == NULL) 4738032Speter return; 4838032Speter 4938032Speter p = q = s; 5038032Speter do 5138032Speter { 5238032Speter c = *p++; 5338032Speter if (c == '\\') 5438032Speter c = *p++; 5538032Speter else if (c == '"') 5638032Speter continue; 5738032Speter *q++ = c; 5838032Speter } while (c != '\0'); 5938032Speter} 6038032Speter/* 6138032Speter** ADDQUOTES -- Adds quotes & quote bits to a string. 6238032Speter** 6338032Speter** Runs through a string and adds characters and quote bits. 6438032Speter** 6538032Speter** Parameters: 6638032Speter** s -- the string to modify. 6738032Speter** 6838032Speter** Returns: 6938032Speter** pointer to quoted string. 7038032Speter** 7138032Speter** Side Effects: 7238032Speter** none. 7338032Speter** 7438032Speter*/ 7538032Speter 7638032Speterchar * 7738032Speteraddquotes(s) 7838032Speter char *s; 7938032Speter{ 8038032Speter int len = 0; 8138032Speter char c; 8238032Speter char *p = s, *q, *r; 8338032Speter 8438032Speter if (s == NULL) 8538032Speter return NULL; 8638032Speter 8738032Speter /* Find length of quoted string */ 8838032Speter while ((c = *p++) != '\0') 8938032Speter { 9038032Speter len++; 9138032Speter if (c == '\\' || c == '"') 9238032Speter len++; 9338032Speter } 9438032Speter 9538032Speter q = r = xalloc(len + 3); 9638032Speter p = s; 9738032Speter 9838032Speter /* add leading quote */ 9938032Speter *q++ = '"'; 10038032Speter while ((c = *p++) != '\0') 10138032Speter { 10238032Speter /* quote \ or " */ 10338032Speter if (c == '\\' || c == '"') 10438032Speter *q++ = '\\'; 10538032Speter *q++ = c; 10638032Speter } 10738032Speter *q++ = '"'; 10838032Speter *q = '\0'; 10938032Speter return r; 11038032Speter} 11138032Speter/* 11238032Speter** RFC822_STRING -- Checks string for proper RFC822 string quoting. 11338032Speter** 11438032Speter** Runs through a string and verifies RFC822 special characters 11538032Speter** are only found inside comments, quoted strings, or backslash 11638032Speter** escaped. Also verified balanced quotes and parenthesis. 11738032Speter** 11838032Speter** Parameters: 11938032Speter** s -- the string to modify. 12038032Speter** 12138032Speter** Returns: 12238032Speter** TRUE -- if the string is RFC822 compliant. 12338032Speter** FALSE -- if the string is not RFC822 compliant. 12438032Speter** 12538032Speter** Side Effects: 12638032Speter** none. 12738032Speter** 12838032Speter*/ 12938032Speter 13038032Speterbool 13138032Speterrfc822_string(s) 13238032Speter char *s; 13338032Speter{ 13438032Speter bool quoted = FALSE; 13538032Speter int commentlev = 0; 13638032Speter char *c = s; 13738032Speter 13838032Speter if (s == NULL) 13938032Speter return FALSE; 14038032Speter 14138032Speter while (*c != '\0') 14238032Speter { 14338032Speter /* escaped character */ 14438032Speter if (*c == '\\') 14538032Speter { 14638032Speter c++; 14738032Speter if (*c == '\0') 14838032Speter return FALSE; 14938032Speter } 15038032Speter else if (commentlev == 0 && *c == '"') 15138032Speter quoted = !quoted; 15238032Speter else if (!quoted) 15338032Speter { 15438032Speter if (*c == ')') 15538032Speter { 15638032Speter /* unbalanced ')' */ 15738032Speter if (commentlev == 0) 15838032Speter return FALSE; 15938032Speter else 16038032Speter commentlev--; 16138032Speter } 16238032Speter else if (*c == '(') 16338032Speter commentlev++; 16438032Speter else if (commentlev == 0 && 16538032Speter strchr(MustQuoteChars, *c) != NULL) 16638032Speter return FALSE; 16738032Speter } 16838032Speter c++; 16938032Speter } 17038032Speter /* unbalanced '"' or '(' */ 17138032Speter if (quoted || commentlev != 0) 17238032Speter return FALSE; 17338032Speter else 17438032Speter return TRUE; 17538032Speter} 17638032Speter/* 17742575Speter** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string 17842575Speter** 17942575Speter** Arbitratily shorten (in place) an RFC822 string and rebalance 18042575Speter** comments and quotes. 18142575Speter** 18242575Speter** Parameters: 18342575Speter** string -- the string to shorten 18442575Speter** length -- the maximum size, 0 if no maximum 18542575Speter** 18642575Speter** Returns: 18742575Speter** TRUE if string is changed, FALSE otherwise 18842575Speter** 18942575Speter** Side Effects: 19042575Speter** Changes string in place, possibly resulting 19142575Speter** in a shorter string. 19242575Speter*/ 19342575Speter 19442575Speterbool 19542575Spetershorten_rfc822_string(string, length) 19642575Speter char *string; 19742575Speter size_t length; 19842575Speter{ 19942575Speter bool backslash = FALSE; 20042575Speter bool modified = FALSE; 20142575Speter bool quoted = FALSE; 20242575Speter size_t slen; 20342575Speter int parencount = 0; 20442575Speter char *ptr = string; 20542575Speter 20642575Speter /* 20742575Speter ** If have to rebalance an already short enough string, 20842575Speter ** need to do it within allocated space. 20942575Speter */ 21042575Speter slen = strlen(string); 21142575Speter if (length == 0 || slen < length) 21242575Speter length = slen; 21342575Speter 21442575Speter while (*ptr != '\0') 21542575Speter { 21642575Speter if (backslash) 21742575Speter { 21842575Speter backslash = FALSE; 21942575Speter goto increment; 22042575Speter } 22142575Speter 22242575Speter if (*ptr == '\\') 22342575Speter backslash = TRUE; 22442575Speter else if (*ptr == '(') 22542575Speter { 22642575Speter if (!quoted) 22742575Speter parencount++; 22842575Speter } 22942575Speter else if (*ptr == ')') 23042575Speter { 23142575Speter if (--parencount < 0) 23242575Speter parencount = 0; 23342575Speter } 23442575Speter 23542575Speter /* Inside a comment, quotes don't matter */ 23642575Speter if (parencount <= 0 && *ptr == '"') 23742575Speter quoted = !quoted; 23842575Speter 23942575Speterincrement: 24042575Speter /* Check for sufficient space for next character */ 24142575Speter if (length - (ptr - string) <= ((backslash ? 1 : 0) + 24242575Speter parencount + 24342575Speter (quoted ? 1 : 0))) 24442575Speter { 24542575Speter /* Not enough, backtrack */ 24642575Speter if (*ptr == '\\') 24742575Speter backslash = FALSE; 24842575Speter else if (*ptr == '(' && !quoted) 24942575Speter parencount--; 25042575Speter else if (*ptr == '"' && parencount == 0) 25142575Speter quoted = FALSE; 25242575Speter break; 25342575Speter } 25442575Speter ptr++; 25542575Speter } 25642575Speter 25742575Speter /* Rebalance */ 25842575Speter while (parencount-- > 0) 25942575Speter { 26042575Speter if (*ptr != ')') 26142575Speter { 26242575Speter modified = TRUE; 26342575Speter *ptr = ')'; 26442575Speter } 26542575Speter ptr++; 26642575Speter } 26742575Speter if (quoted) 26842575Speter { 26942575Speter if (*ptr != '"') 27042575Speter { 27142575Speter modified = TRUE; 27242575Speter *ptr = '"'; 27342575Speter } 27442575Speter ptr++; 27542575Speter } 27642575Speter if (*ptr != '\0') 27742575Speter { 27842575Speter modified = TRUE; 27942575Speter *ptr = '\0'; 28042575Speter } 28142575Speter return modified; 28242575Speter} 28342575Speter/* 28442575Speter** FIND_CHARACTER -- find an unquoted character in an RFC822 string 28542575Speter** 28642575Speter** Find an unquoted, non-commented character in an RFC822 28742575Speter** string and return a pointer to its location in the 28842575Speter** string. 28942575Speter** 29042575Speter** Parameters: 29142575Speter** string -- the string to search 29242575Speter** character -- the character to find 29342575Speter** 29442575Speter** Returns: 29542575Speter** pointer to the character, or 29642575Speter** a pointer to the end of the line if character is not found 29742575Speter*/ 29842575Speter 29942575Speterchar * 30042575Speterfind_character(string, character) 30142575Speter char *string; 30242575Speter char character; 30342575Speter{ 30442575Speter bool backslash = FALSE; 30542575Speter bool quoted = FALSE; 30642575Speter int parencount = 0; 30742575Speter 30842575Speter while (string != NULL && *string != '\0') 30942575Speter { 31042575Speter if (backslash) 31142575Speter { 31242575Speter backslash = FALSE; 31342575Speter if (!quoted && character == '\\' && *string == '\\') 31442575Speter break; 31542575Speter string++; 31642575Speter continue; 31742575Speter } 31842575Speter switch (*string) 31942575Speter { 32042575Speter case '\\': 32142575Speter backslash = TRUE; 32242575Speter break; 32342575Speter 32442575Speter case '(': 32542575Speter if (!quoted) 32642575Speter parencount++; 32742575Speter break; 32842575Speter 32942575Speter case ')': 33042575Speter if (--parencount < 0) 33142575Speter parencount = 0; 33242575Speter break; 33342575Speter } 33442575Speter 33542575Speter /* Inside a comment, nothing matters */ 33642575Speter if (parencount > 0) 33742575Speter { 33842575Speter string++; 33942575Speter continue; 34042575Speter } 34142575Speter 34242575Speter if (*string == '"') 34342575Speter quoted = !quoted; 34442575Speter else if (*string == character && !quoted) 34542575Speter break; 34642575Speter string++; 34742575Speter } 34842575Speter 34942575Speter /* Return pointer to the character */ 35042575Speter return string; 35142575Speter} 35242575Speter/* 35338032Speter** XALLOC -- Allocate memory and bitch wildly on failure. 35438032Speter** 35538032Speter** THIS IS A CLUDGE. This should be made to give a proper 35638032Speter** error -- but after all, what can we do? 35738032Speter** 35838032Speter** Parameters: 35938032Speter** sz -- size of area to allocate. 36038032Speter** 36138032Speter** Returns: 36238032Speter** pointer to data region. 36338032Speter** 36438032Speter** Side Effects: 36538032Speter** Memory is allocated. 36638032Speter*/ 36738032Speter 36838032Speterchar * 36938032Speterxalloc(sz) 37038032Speter register int sz; 37138032Speter{ 37238032Speter register char *p; 37338032Speter 37438032Speter /* some systems can't handle size zero mallocs */ 37538032Speter if (sz <= 0) 37638032Speter sz = 1; 37738032Speter 37838032Speter p = malloc((unsigned) sz); 37938032Speter if (p == NULL) 38038032Speter { 38138032Speter syserr("!Out of memory!!"); 38238032Speter /* exit(EX_UNAVAILABLE); */ 38338032Speter } 38438032Speter return (p); 38538032Speter} 38638032Speter/* 38738032Speter** COPYPLIST -- copy list of pointers. 38838032Speter** 38938032Speter** This routine is the equivalent of newstr for lists of 39038032Speter** pointers. 39138032Speter** 39238032Speter** Parameters: 39338032Speter** list -- list of pointers to copy. 39438032Speter** Must be NULL terminated. 39538032Speter** copycont -- if TRUE, copy the contents of the vector 39638032Speter** (which must be a string) also. 39738032Speter** 39838032Speter** Returns: 39938032Speter** a copy of 'list'. 40038032Speter** 40138032Speter** Side Effects: 40238032Speter** none. 40338032Speter*/ 40438032Speter 40538032Speterchar ** 40638032Spetercopyplist(list, copycont) 40738032Speter char **list; 40838032Speter bool copycont; 40938032Speter{ 41038032Speter register char **vp; 41138032Speter register char **newvp; 41238032Speter 41338032Speter for (vp = list; *vp != NULL; vp++) 41438032Speter continue; 41538032Speter 41638032Speter vp++; 41738032Speter 41838032Speter newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 41938032Speter bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 42038032Speter 42138032Speter if (copycont) 42238032Speter { 42338032Speter for (vp = newvp; *vp != NULL; vp++) 42438032Speter *vp = newstr(*vp); 42538032Speter } 42638032Speter 42738032Speter return (newvp); 42838032Speter} 42938032Speter/* 43038032Speter** COPYQUEUE -- copy address queue. 43138032Speter** 43238032Speter** This routine is the equivalent of newstr for address queues 43338032Speter** addresses marked with QDONTSEND aren't copied 43438032Speter** 43538032Speter** Parameters: 43638032Speter** addr -- list of address structures to copy. 43738032Speter** 43838032Speter** Returns: 43938032Speter** a copy of 'addr'. 44038032Speter** 44138032Speter** Side Effects: 44238032Speter** none. 44338032Speter*/ 44438032Speter 44538032SpeterADDRESS * 44638032Spetercopyqueue(addr) 44738032Speter ADDRESS *addr; 44838032Speter{ 44938032Speter register ADDRESS *newaddr; 45038032Speter ADDRESS *ret; 45138032Speter register ADDRESS **tail = &ret; 45238032Speter 45338032Speter while (addr != NULL) 45438032Speter { 45538032Speter if (!bitset(QDONTSEND, addr->q_flags)) 45638032Speter { 45738032Speter newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 45838032Speter STRUCTCOPY(*addr, *newaddr); 45938032Speter *tail = newaddr; 46038032Speter tail = &newaddr->q_next; 46138032Speter } 46238032Speter addr = addr->q_next; 46338032Speter } 46438032Speter *tail = NULL; 46538032Speter 46638032Speter return ret; 46738032Speter} 46838032Speter/* 46938032Speter** PRINTAV -- print argument vector. 47038032Speter** 47138032Speter** Parameters: 47238032Speter** av -- argument vector. 47338032Speter** 47438032Speter** Returns: 47538032Speter** none. 47638032Speter** 47738032Speter** Side Effects: 47838032Speter** prints av. 47938032Speter*/ 48038032Speter 48138032Spetervoid 48238032Speterprintav(av) 48338032Speter register char **av; 48438032Speter{ 48538032Speter while (*av != NULL) 48638032Speter { 48738032Speter if (tTd(0, 44)) 48838032Speter printf("\n\t%08lx=", (u_long) *av); 48938032Speter else 49038032Speter (void) putchar(' '); 49138032Speter xputs(*av++); 49238032Speter } 49338032Speter (void) putchar('\n'); 49438032Speter} 49538032Speter/* 49638032Speter** LOWER -- turn letter into lower case. 49738032Speter** 49838032Speter** Parameters: 49938032Speter** c -- character to turn into lower case. 50038032Speter** 50138032Speter** Returns: 50238032Speter** c, in lower case. 50338032Speter** 50438032Speter** Side Effects: 50538032Speter** none. 50638032Speter*/ 50738032Speter 50838032Speterchar 50938032Speterlower(c) 51038032Speter register char c; 51138032Speter{ 51238032Speter return((isascii(c) && isupper(c)) ? tolower(c) : c); 51338032Speter} 51438032Speter/* 51538032Speter** XPUTS -- put string doing control escapes. 51638032Speter** 51738032Speter** Parameters: 51838032Speter** s -- string to put. 51938032Speter** 52038032Speter** Returns: 52138032Speter** none. 52238032Speter** 52338032Speter** Side Effects: 52438032Speter** output to stdout 52538032Speter*/ 52638032Speter 52738032Spetervoid 52838032Speterxputs(s) 52938032Speter register const char *s; 53038032Speter{ 53138032Speter register int c; 53238032Speter register struct metamac *mp; 53338032Speter bool shiftout = FALSE; 53438032Speter extern struct metamac MetaMacros[]; 53538032Speter 53638032Speter if (s == NULL) 53738032Speter { 53838032Speter printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off); 53938032Speter return; 54038032Speter } 54138032Speter while ((c = (*s++ & 0377)) != '\0') 54238032Speter { 54338032Speter if (shiftout) 54438032Speter { 54538032Speter printf("%s", TermEscape.te_rv_off); 54638032Speter shiftout = FALSE; 54738032Speter } 54838032Speter if (!isascii(c)) 54938032Speter { 55038032Speter if (c == MATCHREPL) 55138032Speter { 55238032Speter printf("%s$", TermEscape.te_rv_on); 55338032Speter shiftout = TRUE; 55438032Speter if (*s == '\0') 55538032Speter continue; 55638032Speter c = *s++ & 0377; 55738032Speter goto printchar; 55838032Speter } 55938032Speter if (c == MACROEXPAND || c == MACRODEXPAND) 56038032Speter { 56138032Speter printf("%s$", TermEscape.te_rv_on); 56238032Speter if (c == MACRODEXPAND) 56338032Speter putchar('&'); 56438032Speter shiftout = TRUE; 56538032Speter if (*s == '\0') 56638032Speter continue; 56738032Speter if (strchr("=~&?", *s) != NULL) 56838032Speter putchar(*s++); 56938032Speter if (bitset(0200, *s)) 57038032Speter printf("{%s}", macname(*s++ & 0377)); 57138032Speter else 57238032Speter printf("%c", *s++); 57338032Speter continue; 57438032Speter } 57538032Speter for (mp = MetaMacros; mp->metaname != '\0'; mp++) 57638032Speter { 57738032Speter if ((mp->metaval & 0377) == c) 57838032Speter { 57938032Speter printf("%s$%c", 58038032Speter TermEscape.te_rv_on, 58138032Speter mp->metaname); 58238032Speter shiftout = TRUE; 58338032Speter break; 58438032Speter } 58538032Speter } 58638032Speter if (c == MATCHCLASS || c == MATCHNCLASS) 58738032Speter { 58838032Speter if (bitset(0200, *s)) 58938032Speter printf("{%s}", macname(*s++ & 0377)); 59038032Speter else if (*s != '\0') 59138032Speter printf("%c", *s++); 59238032Speter } 59338032Speter if (mp->metaname != '\0') 59438032Speter continue; 59538032Speter 59638032Speter /* unrecognized meta character */ 59738032Speter printf("%sM-", TermEscape.te_rv_on); 59838032Speter shiftout = TRUE; 59938032Speter c &= 0177; 60038032Speter } 60138032Speter printchar: 60238032Speter if (isprint(c)) 60338032Speter { 60438032Speter putchar(c); 60538032Speter continue; 60638032Speter } 60738032Speter 60838032Speter /* wasn't a meta-macro -- find another way to print it */ 60938032Speter switch (c) 61038032Speter { 61138032Speter case '\n': 61238032Speter c = 'n'; 61338032Speter break; 61438032Speter 61538032Speter case '\r': 61638032Speter c = 'r'; 61738032Speter break; 61838032Speter 61938032Speter case '\t': 62038032Speter c = 't'; 62138032Speter break; 62238032Speter } 62338032Speter if (!shiftout) 62438032Speter { 62538032Speter printf("%s", TermEscape.te_rv_on); 62638032Speter shiftout = TRUE; 62738032Speter } 62838032Speter if (isprint(c)) 62938032Speter { 63038032Speter (void) putchar('\\'); 63138032Speter (void) putchar(c); 63238032Speter } 63338032Speter else 63438032Speter { 63538032Speter (void) putchar('^'); 63638032Speter (void) putchar(c ^ 0100); 63738032Speter } 63838032Speter } 63938032Speter if (shiftout) 64038032Speter printf("%s", TermEscape.te_rv_off); 64138032Speter (void) fflush(stdout); 64238032Speter} 64338032Speter/* 64438032Speter** MAKELOWER -- Translate a line into lower case 64538032Speter** 64638032Speter** Parameters: 64738032Speter** p -- the string to translate. If NULL, return is 64838032Speter** immediate. 64938032Speter** 65038032Speter** Returns: 65138032Speter** none. 65238032Speter** 65338032Speter** Side Effects: 65438032Speter** String pointed to by p is translated to lower case. 65538032Speter** 65638032Speter** Called By: 65738032Speter** parse 65838032Speter*/ 65938032Speter 66038032Spetervoid 66138032Spetermakelower(p) 66238032Speter register char *p; 66338032Speter{ 66438032Speter register char c; 66538032Speter 66638032Speter if (p == NULL) 66738032Speter return; 66838032Speter for (; (c = *p) != '\0'; p++) 66938032Speter if (isascii(c) && isupper(c)) 67038032Speter *p = tolower(c); 67138032Speter} 67238032Speter/* 67338032Speter** BUILDFNAME -- build full name from gecos style entry. 67438032Speter** 67538032Speter** This routine interprets the strange entry that would appear 67638032Speter** in the GECOS field of the password file. 67738032Speter** 67838032Speter** Parameters: 67938032Speter** p -- name to build. 68038032Speter** login -- the login name of this user (for &). 68138032Speter** buf -- place to put the result. 68238032Speter** buflen -- length of buf. 68338032Speter** 68438032Speter** Returns: 68538032Speter** none. 68638032Speter** 68738032Speter** Side Effects: 68838032Speter** none. 68938032Speter*/ 69038032Speter 69138032Spetervoid 69238032Speterbuildfname(gecos, login, buf, buflen) 69338032Speter register char *gecos; 69438032Speter char *login; 69538032Speter char *buf; 69638032Speter int buflen; 69738032Speter{ 69838032Speter register char *p; 69938032Speter register char *bp = buf; 70038032Speter 70138032Speter if (*gecos == '*') 70238032Speter gecos++; 70338032Speter 70438032Speter /* copy gecos, interpolating & to be full name */ 70538032Speter for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 70638032Speter { 70738032Speter if (bp >= &buf[buflen - 1]) 70838032Speter { 70938032Speter /* buffer overflow -- just use login name */ 71038032Speter snprintf(buf, buflen, "%s", login); 71138032Speter return; 71238032Speter } 71338032Speter if (*p == '&') 71438032Speter { 71538032Speter /* interpolate full name */ 71638032Speter snprintf(bp, buflen - (bp - buf), "%s", login); 71738032Speter *bp = toupper(*bp); 71838032Speter bp += strlen(bp); 71938032Speter } 72038032Speter else 72138032Speter *bp++ = *p; 72238032Speter } 72338032Speter *bp = '\0'; 72438032Speter} 72538032Speter/* 72638032Speter** FIXCRLF -- fix <CR><LF> in line. 72738032Speter** 72838032Speter** Looks for the <CR><LF> combination and turns it into the 72938032Speter** UNIX canonical <NL> character. It only takes one line, 73038032Speter** i.e., it is assumed that the first <NL> found is the end 73138032Speter** of the line. 73238032Speter** 73338032Speter** Parameters: 73438032Speter** line -- the line to fix. 73538032Speter** stripnl -- if true, strip the newline also. 73638032Speter** 73738032Speter** Returns: 73838032Speter** none. 73938032Speter** 74038032Speter** Side Effects: 74138032Speter** line is changed in place. 74238032Speter*/ 74338032Speter 74438032Spetervoid 74538032Speterfixcrlf(line, stripnl) 74638032Speter char *line; 74738032Speter bool stripnl; 74838032Speter{ 74938032Speter register char *p; 75038032Speter 75138032Speter p = strchr(line, '\n'); 75238032Speter if (p == NULL) 75338032Speter return; 75438032Speter if (p > line && p[-1] == '\r') 75538032Speter p--; 75638032Speter if (!stripnl) 75738032Speter *p++ = '\n'; 75838032Speter *p = '\0'; 75938032Speter} 76038032Speter/* 76138032Speter** PUTLINE -- put a line like fputs obeying SMTP conventions 76238032Speter** 76338032Speter** This routine always guarantees outputing a newline (or CRLF, 76438032Speter** as appropriate) at the end of the string. 76538032Speter** 76638032Speter** Parameters: 76738032Speter** l -- line to put. 76838032Speter** mci -- the mailer connection information. 76938032Speter** 77038032Speter** Returns: 77138032Speter** none 77238032Speter** 77338032Speter** Side Effects: 77438032Speter** output of l to fp. 77538032Speter*/ 77638032Speter 77738032Spetervoid 77838032Speterputline(l, mci) 77938032Speter register char *l; 78038032Speter register MCI *mci; 78138032Speter{ 78238032Speter putxline(l, strlen(l), mci, PXLF_MAPFROM); 78338032Speter} 78438032Speter/* 78538032Speter** PUTXLINE -- putline with flags bits. 78638032Speter** 78738032Speter** This routine always guarantees outputing a newline (or CRLF, 78838032Speter** as appropriate) at the end of the string. 78938032Speter** 79038032Speter** Parameters: 79138032Speter** l -- line to put. 79238032Speter** len -- the length of the line. 79338032Speter** mci -- the mailer connection information. 79438032Speter** pxflags -- flag bits: 79538032Speter** PXLF_MAPFROM -- map From_ to >From_. 79638032Speter** PXLF_STRIP8BIT -- strip 8th bit. 79738032Speter** PXLF_HEADER -- map bare newline in header to newline space. 79838032Speter** 79938032Speter** Returns: 80038032Speter** none 80138032Speter** 80238032Speter** Side Effects: 80338032Speter** output of l to fp. 80438032Speter*/ 80538032Speter 80638032Spetervoid 80738032Speterputxline(l, len, mci, pxflags) 80838032Speter register char *l; 80938032Speter size_t len; 81038032Speter register MCI *mci; 81138032Speter int pxflags; 81238032Speter{ 81338032Speter register char *p, *end; 81438032Speter int slop = 0; 81538032Speter size_t eol_len = strlen(mci->mci_mailer->m_eol); 81638032Speter 81738032Speter /* strip out 0200 bits -- these can look like TELNET protocol */ 81838032Speter if (bitset(MCIF_7BIT, mci->mci_flags) || 81938032Speter bitset(PXLF_STRIP8BIT, pxflags)) 82038032Speter { 82138032Speter register char svchar; 82238032Speter 82338032Speter for (p = l; (svchar = *p) != '\0'; ++p) 82438032Speter if (bitset(0200, svchar)) 82538032Speter *p = svchar &~ 0200; 82638032Speter } 82738032Speter 82838032Speter end = l + len; 82938032Speter do 83038032Speter { 83138032Speter /* find the end of the line */ 83238032Speter p = memchr(l, '\n', end - l); 83338032Speter if (p == NULL) 83438032Speter p = end; 83538032Speter 83638032Speter if (TrafficLogFile != NULL) 83738032Speter fprintf(TrafficLogFile, "%05d >>> ", (int) getpid()); 83838032Speter 83938032Speter /* check for line overflow */ 84038032Speter while (mci->mci_mailer->m_linelimit > 0 && 84138032Speter (p - l + slop) > mci->mci_mailer->m_linelimit) 84238032Speter { 84338032Speter char *l_base = l; 84438032Speter register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 84538032Speter 84638032Speter if (l[0] == '.' && slop == 0 && 84738032Speter bitnset(M_XDOT, mci->mci_mailer->m_flags)) 84838032Speter { 84938032Speter (void) putc('.', mci->mci_out); 85038032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 85138032Speter mci->mci_contentlen++; 85238032Speter if (TrafficLogFile != NULL) 85338032Speter (void) putc('.', TrafficLogFile); 85438032Speter } 85538032Speter else if (l[0] == 'F' && slop == 0 && 85638032Speter bitset(PXLF_MAPFROM, pxflags) && 85738032Speter strncmp(l, "From ", 5) == 0 && 85838032Speter bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 85938032Speter { 86038032Speter (void) putc('>', mci->mci_out); 86138032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 86238032Speter mci->mci_contentlen++; 86338032Speter if (TrafficLogFile != NULL) 86438032Speter (void) putc('>', TrafficLogFile); 86538032Speter } 86638032Speter while (l < q) 86738032Speter { 86838032Speter (void) putc(*l++, mci->mci_out); 86938032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 87038032Speter mci->mci_contentlen++; 87138032Speter } 87238032Speter (void) putc('!', mci->mci_out); 87338032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 87438032Speter mci->mci_contentlen++; 87538032Speter fputs(mci->mci_mailer->m_eol, mci->mci_out); 87638032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 87738032Speter mci->mci_contentlen += eol_len; 87838032Speter (void) putc(' ', mci->mci_out); 87938032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 88038032Speter mci->mci_contentlen++; 88138032Speter if (TrafficLogFile != NULL) 88238032Speter { 88338032Speter for (l = l_base; l < q; l++) 88438032Speter (void) putc(*l, TrafficLogFile); 88538032Speter fprintf(TrafficLogFile, "!\n%05d >>> ", 88638032Speter (int) getpid()); 88738032Speter } 88838032Speter slop = 1; 88938032Speter } 89038032Speter 89138032Speter /* output last part */ 89238032Speter if (l[0] == '.' && slop == 0 && 89338032Speter bitnset(M_XDOT, mci->mci_mailer->m_flags)) 89438032Speter { 89538032Speter (void) putc('.', mci->mci_out); 89638032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 89738032Speter mci->mci_contentlen++; 89838032Speter if (TrafficLogFile != NULL) 89938032Speter (void) putc('.', TrafficLogFile); 90038032Speter } 90138032Speter else if (l[0] == 'F' && slop == 0 && 90238032Speter bitset(PXLF_MAPFROM, pxflags) && 90338032Speter strncmp(l, "From ", 5) == 0 && 90438032Speter bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 90538032Speter { 90638032Speter (void) putc('>', mci->mci_out); 90738032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 90838032Speter mci->mci_contentlen++; 90938032Speter if (TrafficLogFile != NULL) 91038032Speter (void) putc('>', TrafficLogFile); 91138032Speter } 91238032Speter for ( ; l < p; ++l) 91338032Speter { 91438032Speter if (TrafficLogFile != NULL) 91538032Speter (void) putc(*l, TrafficLogFile); 91638032Speter (void) putc(*l, mci->mci_out); 91738032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 91838032Speter mci->mci_contentlen++; 91938032Speter } 92038032Speter if (TrafficLogFile != NULL) 92138032Speter (void) putc('\n', TrafficLogFile); 92238032Speter fputs(mci->mci_mailer->m_eol, mci->mci_out); 92338032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 92438032Speter mci->mci_contentlen += eol_len; 92538032Speter if (l < end && *l == '\n') 92638032Speter { 92738032Speter if (*++l != ' ' && *l != '\t' && *l != '\0' && 92838032Speter bitset(PXLF_HEADER, pxflags)) 92938032Speter { 93038032Speter (void) putc(' ', mci->mci_out); 93138032Speter if (!bitset(MCIF_INHEADER, mci->mci_flags)) 93238032Speter mci->mci_contentlen++; 93338032Speter if (TrafficLogFile != NULL) 93438032Speter (void) putc(' ', TrafficLogFile); 93538032Speter } 93638032Speter } 93738032Speter } while (l < end); 93838032Speter} 93938032Speter/* 94038032Speter** XUNLINK -- unlink a file, doing logging as appropriate. 94138032Speter** 94238032Speter** Parameters: 94338032Speter** f -- name of file to unlink. 94438032Speter** 94538032Speter** Returns: 94638032Speter** none. 94738032Speter** 94838032Speter** Side Effects: 94938032Speter** f is unlinked. 95038032Speter*/ 95138032Speter 95238032Spetervoid 95338032Speterxunlink(f) 95438032Speter char *f; 95538032Speter{ 95638032Speter register int i; 95738032Speter 95838032Speter if (LogLevel > 98) 95938032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 96038032Speter "unlink %s", 96138032Speter f); 96238032Speter 96338032Speter i = unlink(f); 96438032Speter if (i < 0 && LogLevel > 97) 96538032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 96638032Speter "%s: unlink-fail %d", 96738032Speter f, errno); 96838032Speter} 96938032Speter/* 97038032Speter** XFCLOSE -- close a file, doing logging as appropriate. 97138032Speter** 97238032Speter** Parameters: 97338032Speter** fp -- file pointer for the file to close 97438032Speter** a, b -- miscellaneous crud to print for debugging 97538032Speter** 97638032Speter** Returns: 97738032Speter** none. 97838032Speter** 97938032Speter** Side Effects: 98038032Speter** fp is closed. 98138032Speter*/ 98238032Speter 98338032Spetervoid 98438032Speterxfclose(fp, a, b) 98538032Speter FILE *fp; 98638032Speter char *a, *b; 98738032Speter{ 98838032Speter if (tTd(53, 99)) 98938032Speter printf("xfclose(%lx) %s %s\n", (u_long) fp, a, b); 99038032Speter#if XDEBUG 99138032Speter if (fileno(fp) == 1) 99238032Speter syserr("xfclose(%s %s): fd = 1", a, b); 99338032Speter#endif 99438032Speter if (fclose(fp) < 0 && tTd(53, 99)) 99538032Speter printf("xfclose FAILURE: %s\n", errstring(errno)); 99638032Speter} 99738032Speter/* 99838032Speter** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 99938032Speter** 100038032Speter** Parameters: 100138032Speter** buf -- place to put the input line. 100238032Speter** siz -- size of buf. 100338032Speter** fp -- file to read from. 100438032Speter** timeout -- the timeout before error occurs. 100538032Speter** during -- what we are trying to read (for error messages). 100638032Speter** 100738032Speter** Returns: 100838032Speter** NULL on error (including timeout). This will also leave 100938032Speter** buf containing a null string. 101038032Speter** buf otherwise. 101138032Speter** 101238032Speter** Side Effects: 101338032Speter** none. 101438032Speter*/ 101538032Speter 101638032Speterstatic jmp_buf CtxReadTimeout; 101738032Speterstatic void readtimeout __P((time_t)); 101838032Speter 101938032Speterchar * 102038032Spetersfgets(buf, siz, fp, timeout, during) 102138032Speter char *buf; 102238032Speter int siz; 102338032Speter FILE *fp; 102438032Speter time_t timeout; 102538032Speter char *during; 102638032Speter{ 102738032Speter register EVENT *ev = NULL; 102838032Speter register char *p; 102943730Speter int save_errno; 103038032Speter 103138032Speter if (fp == NULL) 103238032Speter { 103338032Speter buf[0] = '\0'; 103438032Speter return NULL; 103538032Speter } 103638032Speter 103738032Speter /* set the timeout */ 103838032Speter if (timeout != 0) 103938032Speter { 104038032Speter if (setjmp(CtxReadTimeout) != 0) 104138032Speter { 104238032Speter if (LogLevel > 1) 104338032Speter sm_syslog(LOG_NOTICE, CurEnv->e_id, 104438032Speter "timeout waiting for input from %.100s during %s", 104538032Speter CurHostName ? CurHostName : "local", 104638032Speter during); 104738032Speter buf[0] = '\0'; 104838032Speter#if XDEBUG 104938032Speter checkfd012(during); 105038032Speter#endif 105138032Speter if (TrafficLogFile != NULL) 105238032Speter fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n", 105338032Speter (int) getpid()); 105443730Speter errno = 0; 105538032Speter return (NULL); 105638032Speter } 105738032Speter ev = setevent(timeout, readtimeout, 0); 105838032Speter } 105938032Speter 106038032Speter /* try to read */ 106138032Speter p = NULL; 106243730Speter errno = 0; 106338032Speter while (!feof(fp) && !ferror(fp)) 106438032Speter { 106538032Speter errno = 0; 106638032Speter p = fgets(buf, siz, fp); 106738032Speter if (p != NULL || errno != EINTR) 106838032Speter break; 106938032Speter clearerr(fp); 107038032Speter } 107143730Speter save_errno = errno; 107238032Speter 107338032Speter /* clear the event if it has not sprung */ 107438032Speter clrevent(ev); 107538032Speter 107638032Speter /* clean up the books and exit */ 107738032Speter LineNumber++; 107838032Speter if (p == NULL) 107938032Speter { 108038032Speter buf[0] = '\0'; 108138032Speter if (TrafficLogFile != NULL) 108238032Speter fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid()); 108343730Speter errno = save_errno; 108438032Speter return (NULL); 108538032Speter } 108638032Speter if (TrafficLogFile != NULL) 108738032Speter fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf); 108838032Speter if (SevenBitInput) 108938032Speter { 109038032Speter for (p = buf; *p != '\0'; p++) 109138032Speter *p &= ~0200; 109238032Speter } 109338032Speter else if (!HasEightBits) 109438032Speter { 109538032Speter for (p = buf; *p != '\0'; p++) 109638032Speter { 109738032Speter if (bitset(0200, *p)) 109838032Speter { 109938032Speter HasEightBits = TRUE; 110038032Speter break; 110138032Speter } 110238032Speter } 110338032Speter } 110438032Speter return (buf); 110538032Speter} 110638032Speter 110738032Speter/* ARGSUSED */ 110838032Speterstatic void 110938032Speterreadtimeout(timeout) 111038032Speter time_t timeout; 111138032Speter{ 111238032Speter longjmp(CtxReadTimeout, 1); 111338032Speter} 111438032Speter/* 111538032Speter** FGETFOLDED -- like fgets, but know about folded lines. 111638032Speter** 111738032Speter** Parameters: 111838032Speter** buf -- place to put result. 111938032Speter** n -- bytes available. 112038032Speter** f -- file to read from. 112138032Speter** 112238032Speter** Returns: 112338032Speter** input line(s) on success, NULL on error or EOF. 112438032Speter** This will normally be buf -- unless the line is too 112538032Speter** long, when it will be xalloc()ed. 112638032Speter** 112738032Speter** Side Effects: 112838032Speter** buf gets lines from f, with continuation lines (lines 112938032Speter** with leading white space) appended. CRLF's are mapped 113038032Speter** into single newlines. Any trailing NL is stripped. 113138032Speter*/ 113238032Speter 113338032Speterchar * 113438032Speterfgetfolded(buf, n, f) 113538032Speter char *buf; 113638032Speter register int n; 113738032Speter FILE *f; 113838032Speter{ 113938032Speter register char *p = buf; 114038032Speter char *bp = buf; 114138032Speter register int i; 114238032Speter 114338032Speter n--; 114438032Speter while ((i = getc(f)) != EOF) 114538032Speter { 114638032Speter if (i == '\r') 114738032Speter { 114838032Speter i = getc(f); 114938032Speter if (i != '\n') 115038032Speter { 115138032Speter if (i != EOF) 115238032Speter (void) ungetc(i, f); 115338032Speter i = '\r'; 115438032Speter } 115538032Speter } 115638032Speter if (--n <= 0) 115738032Speter { 115838032Speter /* allocate new space */ 115938032Speter char *nbp; 116038032Speter int nn; 116138032Speter 116238032Speter nn = (p - bp); 116338032Speter if (nn < MEMCHUNKSIZE) 116438032Speter nn *= 2; 116538032Speter else 116638032Speter nn += MEMCHUNKSIZE; 116738032Speter nbp = xalloc(nn); 116838032Speter bcopy(bp, nbp, p - bp); 116938032Speter p = &nbp[p - bp]; 117038032Speter if (bp != buf) 117138032Speter free(bp); 117238032Speter bp = nbp; 117338032Speter n = nn - (p - bp); 117438032Speter } 117538032Speter *p++ = i; 117638032Speter if (i == '\n') 117738032Speter { 117838032Speter LineNumber++; 117938032Speter i = getc(f); 118038032Speter if (i != EOF) 118138032Speter (void) ungetc(i, f); 118238032Speter if (i != ' ' && i != '\t') 118338032Speter break; 118438032Speter } 118538032Speter } 118638032Speter if (p == bp) 118738032Speter return (NULL); 118838032Speter if (p[-1] == '\n') 118938032Speter p--; 119038032Speter *p = '\0'; 119138032Speter return (bp); 119238032Speter} 119338032Speter/* 119438032Speter** CURTIME -- return current time. 119538032Speter** 119638032Speter** Parameters: 119738032Speter** none. 119838032Speter** 119938032Speter** Returns: 120038032Speter** the current time. 120138032Speter** 120238032Speter** Side Effects: 120338032Speter** none. 120438032Speter*/ 120538032Speter 120638032Spetertime_t 120738032Spetercurtime() 120838032Speter{ 120938032Speter auto time_t t; 121038032Speter 121138032Speter (void) time(&t); 121238032Speter return (t); 121338032Speter} 121438032Speter/* 121538032Speter** ATOBOOL -- convert a string representation to boolean. 121638032Speter** 121738032Speter** Defaults to "TRUE" 121838032Speter** 121938032Speter** Parameters: 122038032Speter** s -- string to convert. Takes "tTyY" as true, 122138032Speter** others as false. 122238032Speter** 122338032Speter** Returns: 122438032Speter** A boolean representation of the string. 122538032Speter** 122638032Speter** Side Effects: 122738032Speter** none. 122838032Speter*/ 122938032Speter 123038032Speterbool 123138032Speteratobool(s) 123238032Speter register char *s; 123338032Speter{ 123438032Speter if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 123538032Speter return (TRUE); 123638032Speter return (FALSE); 123738032Speter} 123838032Speter/* 123938032Speter** ATOOCT -- convert a string representation to octal. 124038032Speter** 124138032Speter** Parameters: 124238032Speter** s -- string to convert. 124338032Speter** 124438032Speter** Returns: 124538032Speter** An integer representing the string interpreted as an 124638032Speter** octal number. 124738032Speter** 124838032Speter** Side Effects: 124938032Speter** none. 125038032Speter*/ 125138032Speter 125238032Speterint 125338032Speteratooct(s) 125438032Speter register char *s; 125538032Speter{ 125638032Speter register int i = 0; 125738032Speter 125838032Speter while (*s >= '0' && *s <= '7') 125938032Speter i = (i << 3) | (*s++ - '0'); 126038032Speter return (i); 126138032Speter} 126238032Speter/* 126338032Speter** BITINTERSECT -- tell if two bitmaps intersect 126438032Speter** 126538032Speter** Parameters: 126638032Speter** a, b -- the bitmaps in question 126738032Speter** 126838032Speter** Returns: 126938032Speter** TRUE if they have a non-null intersection 127038032Speter** FALSE otherwise 127138032Speter** 127238032Speter** Side Effects: 127338032Speter** none. 127438032Speter*/ 127538032Speter 127638032Speterbool 127738032Speterbitintersect(a, b) 127838032Speter BITMAP a; 127938032Speter BITMAP b; 128038032Speter{ 128138032Speter int i; 128238032Speter 128338032Speter for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 128438032Speter if ((a[i] & b[i]) != 0) 128538032Speter return (TRUE); 128638032Speter return (FALSE); 128738032Speter} 128838032Speter/* 128938032Speter** BITZEROP -- tell if a bitmap is all zero 129038032Speter** 129138032Speter** Parameters: 129238032Speter** map -- the bit map to check 129338032Speter** 129438032Speter** Returns: 129538032Speter** TRUE if map is all zero. 129638032Speter** FALSE if there are any bits set in map. 129738032Speter** 129838032Speter** Side Effects: 129938032Speter** none. 130038032Speter*/ 130138032Speter 130238032Speterbool 130338032Speterbitzerop(map) 130438032Speter BITMAP map; 130538032Speter{ 130638032Speter int i; 130738032Speter 130838032Speter for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 130938032Speter if (map[i] != 0) 131038032Speter return (FALSE); 131138032Speter return (TRUE); 131238032Speter} 131338032Speter/* 131438032Speter** STRCONTAINEDIN -- tell if one string is contained in another 131538032Speter** 131638032Speter** Parameters: 131738032Speter** a -- possible substring. 131838032Speter** b -- possible superstring. 131938032Speter** 132038032Speter** Returns: 132138032Speter** TRUE if a is contained in b. 132238032Speter** FALSE otherwise. 132338032Speter*/ 132438032Speter 132538032Speterbool 132638032Speterstrcontainedin(a, b) 132738032Speter register char *a; 132838032Speter register char *b; 132938032Speter{ 133038032Speter int la; 133138032Speter int lb; 133238032Speter int c; 133338032Speter 133438032Speter la = strlen(a); 133538032Speter lb = strlen(b); 133638032Speter c = *a; 133738032Speter if (isascii(c) && isupper(c)) 133838032Speter c = tolower(c); 133938032Speter for (; lb-- >= la; b++) 134038032Speter { 134138032Speter if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) 134238032Speter continue; 134338032Speter if (strncasecmp(a, b, la) == 0) 134438032Speter return TRUE; 134538032Speter } 134638032Speter return FALSE; 134738032Speter} 134838032Speter/* 134938032Speter** CHECKFD012 -- check low numbered file descriptors 135038032Speter** 135138032Speter** File descriptors 0, 1, and 2 should be open at all times. 135238032Speter** This routine verifies that, and fixes it if not true. 135338032Speter** 135438032Speter** Parameters: 135538032Speter** where -- a tag printed if the assertion failed 135638032Speter** 135738032Speter** Returns: 135838032Speter** none 135938032Speter*/ 136038032Speter 136138032Spetervoid 136238032Spetercheckfd012(where) 136338032Speter char *where; 136438032Speter{ 136538032Speter#if XDEBUG 136638032Speter register int i; 136738032Speter 136838032Speter for (i = 0; i < 3; i++) 136938032Speter fill_fd(i, where); 137038032Speter#endif /* XDEBUG */ 137138032Speter} 137238032Speter/* 137338032Speter** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging 137438032Speter** 137538032Speter** Parameters: 137638032Speter** fd -- file descriptor to check. 137738032Speter** where -- tag to print on failure. 137838032Speter** 137938032Speter** Returns: 138038032Speter** none. 138138032Speter*/ 138238032Speter 138338032Spetervoid 138438032Spetercheckfdopen(fd, where) 138538032Speter int fd; 138638032Speter char *where; 138738032Speter{ 138838032Speter#if XDEBUG 138938032Speter struct stat st; 139038032Speter 139138032Speter if (fstat(fd, &st) < 0 && errno == EBADF) 139238032Speter { 139338032Speter syserr("checkfdopen(%d): %s not open as expected!", fd, where); 139438032Speter printopenfds(TRUE); 139538032Speter } 139638032Speter#endif 139738032Speter} 139838032Speter/* 139938032Speter** CHECKFDS -- check for new or missing file descriptors 140038032Speter** 140138032Speter** Parameters: 140238032Speter** where -- tag for printing. If null, take a base line. 140338032Speter** 140438032Speter** Returns: 140538032Speter** none 140638032Speter** 140738032Speter** Side Effects: 140838032Speter** If where is set, shows changes since the last call. 140938032Speter*/ 141038032Speter 141138032Spetervoid 141238032Spetercheckfds(where) 141338032Speter char *where; 141438032Speter{ 141538032Speter int maxfd; 141638032Speter register int fd; 141738032Speter bool printhdr = TRUE; 141838032Speter int save_errno = errno; 141938032Speter static BITMAP baseline; 142038032Speter extern int DtableSize; 142138032Speter 142238032Speter if (DtableSize > 256) 142338032Speter maxfd = 256; 142438032Speter else 142538032Speter maxfd = DtableSize; 142638032Speter if (where == NULL) 142738032Speter clrbitmap(baseline); 142838032Speter 142938032Speter for (fd = 0; fd < maxfd; fd++) 143038032Speter { 143138032Speter struct stat stbuf; 143238032Speter 143338032Speter if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) 143438032Speter { 143538032Speter if (!bitnset(fd, baseline)) 143638032Speter continue; 143738032Speter clrbitn(fd, baseline); 143838032Speter } 143938032Speter else if (!bitnset(fd, baseline)) 144038032Speter setbitn(fd, baseline); 144138032Speter else 144238032Speter continue; 144338032Speter 144438032Speter /* file state has changed */ 144538032Speter if (where == NULL) 144638032Speter continue; 144738032Speter if (printhdr) 144838032Speter { 144938032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 145038032Speter "%s: changed fds:", 145138032Speter where); 145238032Speter printhdr = FALSE; 145338032Speter } 145438032Speter dumpfd(fd, TRUE, TRUE); 145538032Speter } 145638032Speter errno = save_errno; 145738032Speter} 145838032Speter/* 145938032Speter** PRINTOPENFDS -- print the open file descriptors (for debugging) 146038032Speter** 146138032Speter** Parameters: 146238032Speter** logit -- if set, send output to syslog; otherwise 146338032Speter** print for debugging. 146438032Speter** 146538032Speter** Returns: 146638032Speter** none. 146738032Speter*/ 146838032Speter 146938032Speter#include <arpa/inet.h> 147038032Speter 147138032Spetervoid 147238032Speterprintopenfds(logit) 147338032Speter bool logit; 147438032Speter{ 147538032Speter register int fd; 147638032Speter extern int DtableSize; 147738032Speter 147838032Speter for (fd = 0; fd < DtableSize; fd++) 147938032Speter dumpfd(fd, FALSE, logit); 148038032Speter} 148138032Speter/* 148238032Speter** DUMPFD -- dump a file descriptor 148338032Speter** 148438032Speter** Parameters: 148538032Speter** fd -- the file descriptor to dump. 148638032Speter** printclosed -- if set, print a notification even if 148738032Speter** it is closed; otherwise print nothing. 148838032Speter** logit -- if set, send output to syslog instead of stdout. 148938032Speter*/ 149038032Speter 149138032Spetervoid 149238032Speterdumpfd(fd, printclosed, logit) 149338032Speter int fd; 149438032Speter bool printclosed; 149538032Speter bool logit; 149638032Speter{ 149738032Speter register char *p; 149838032Speter char *hp; 149938032Speter#ifdef S_IFSOCK 150038032Speter SOCKADDR sa; 150138032Speter#endif 150238032Speter auto SOCKADDR_LEN_T slen; 150338032Speter int i; 150438032Speter#if STAT64 > 0 150538032Speter struct stat64 st; 150638032Speter#else 150738032Speter struct stat st; 150838032Speter#endif 150938032Speter char buf[200]; 151038032Speter 151138032Speter p = buf; 151238032Speter snprintf(p, SPACELEFT(buf, p), "%3d: ", fd); 151338032Speter p += strlen(p); 151438032Speter 151538032Speter if ( 151638032Speter#if STAT64 > 0 151738032Speter fstat64(fd, &st) 151838032Speter#else 151938032Speter fstat(fd, &st) 152038032Speter#endif 152138032Speter < 0) 152238032Speter { 152338032Speter if (errno != EBADF) 152438032Speter { 152538032Speter snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)", 152638032Speter errstring(errno)); 152738032Speter goto printit; 152838032Speter } 152938032Speter else if (printclosed) 153038032Speter { 153138032Speter snprintf(p, SPACELEFT(buf, p), "CLOSED"); 153238032Speter goto printit; 153338032Speter } 153438032Speter return; 153538032Speter } 153638032Speter 153738032Speter i = fcntl(fd, F_GETFL, NULL); 153838032Speter if (i != -1) 153938032Speter { 154038032Speter snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i); 154138032Speter p += strlen(p); 154238032Speter } 154338032Speter 154438032Speter snprintf(p, SPACELEFT(buf, p), "mode=%o: ", st.st_mode); 154538032Speter p += strlen(p); 154638032Speter switch (st.st_mode & S_IFMT) 154738032Speter { 154838032Speter#ifdef S_IFSOCK 154938032Speter case S_IFSOCK: 155038032Speter snprintf(p, SPACELEFT(buf, p), "SOCK "); 155138032Speter p += strlen(p); 155238032Speter slen = sizeof sa; 155338032Speter if (getsockname(fd, &sa.sa, &slen) < 0) 155438032Speter snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno)); 155538032Speter else 155638032Speter { 155738032Speter hp = hostnamebyanyaddr(&sa); 155838032Speter if (sa.sa.sa_family == AF_INET) 155938032Speter snprintf(p, SPACELEFT(buf, p), "%s/%d", 156038032Speter hp, ntohs(sa.sin.sin_port)); 156138032Speter else 156238032Speter snprintf(p, SPACELEFT(buf, p), "%s", hp); 156338032Speter } 156438032Speter p += strlen(p); 156538032Speter snprintf(p, SPACELEFT(buf, p), "->"); 156638032Speter p += strlen(p); 156738032Speter slen = sizeof sa; 156838032Speter if (getpeername(fd, &sa.sa, &slen) < 0) 156938032Speter snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno)); 157038032Speter else 157138032Speter { 157238032Speter hp = hostnamebyanyaddr(&sa); 157338032Speter if (sa.sa.sa_family == AF_INET) 157438032Speter snprintf(p, SPACELEFT(buf, p), "%s/%d", 157538032Speter hp, ntohs(sa.sin.sin_port)); 157638032Speter else 157738032Speter snprintf(p, SPACELEFT(buf, p), "%s", hp); 157838032Speter } 157938032Speter break; 158038032Speter#endif 158138032Speter 158238032Speter case S_IFCHR: 158338032Speter snprintf(p, SPACELEFT(buf, p), "CHR: "); 158438032Speter p += strlen(p); 158538032Speter goto defprint; 158638032Speter 158738032Speter case S_IFBLK: 158838032Speter snprintf(p, SPACELEFT(buf, p), "BLK: "); 158938032Speter p += strlen(p); 159038032Speter goto defprint; 159138032Speter 159238032Speter#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 159338032Speter case S_IFIFO: 159438032Speter snprintf(p, SPACELEFT(buf, p), "FIFO: "); 159538032Speter p += strlen(p); 159638032Speter goto defprint; 159738032Speter#endif 159838032Speter 159938032Speter#ifdef S_IFDIR 160038032Speter case S_IFDIR: 160138032Speter snprintf(p, SPACELEFT(buf, p), "DIR: "); 160238032Speter p += strlen(p); 160338032Speter goto defprint; 160438032Speter#endif 160538032Speter 160638032Speter#ifdef S_IFLNK 160738032Speter case S_IFLNK: 160838032Speter snprintf(p, SPACELEFT(buf, p), "LNK: "); 160938032Speter p += strlen(p); 161038032Speter goto defprint; 161138032Speter#endif 161238032Speter 161338032Speter default: 161438032Speterdefprint: 161538032Speter if (sizeof st.st_ino > sizeof (long)) 161638032Speter snprintf(p, SPACELEFT(buf, p), 161738032Speter "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ", 161838032Speter major(st.st_dev), minor(st.st_dev), 161938032Speter quad_to_string(st.st_ino), 162038032Speter st.st_nlink, st.st_uid, st.st_gid); 162138032Speter else 162238032Speter snprintf(p, SPACELEFT(buf, p), 162338032Speter "dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ", 162438032Speter major(st.st_dev), minor(st.st_dev), 162538032Speter (unsigned long) st.st_ino, 162638032Speter st.st_nlink, st.st_uid, st.st_gid); 162738032Speter if (sizeof st.st_size > sizeof (long)) 162838032Speter snprintf(p, SPACELEFT(buf, p), "size=%s", 162938032Speter quad_to_string(st.st_size)); 163038032Speter else 163138032Speter snprintf(p, SPACELEFT(buf, p), "size=%lu", 163238032Speter (unsigned long) st.st_size); 163338032Speter break; 163438032Speter } 163538032Speter 163638032Speterprintit: 163738032Speter if (logit) 163838032Speter sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL, 163938032Speter "%.800s", buf); 164038032Speter else 164138032Speter printf("%s\n", buf); 164238032Speter} 164338032Speter/* 164438032Speter** SHORTEN_HOSTNAME -- strip local domain information off of hostname. 164538032Speter** 164638032Speter** Parameters: 164738032Speter** host -- the host to shorten (stripped in place). 164838032Speter** 164938032Speter** Returns: 165038032Speter** none. 165138032Speter*/ 165238032Speter 165338032Spetervoid 165438032Spetershorten_hostname(host) 165538032Speter char host[]; 165638032Speter{ 165738032Speter register char *p; 165838032Speter char *mydom; 165938032Speter int i; 166038032Speter bool canon = FALSE; 166138032Speter 166238032Speter /* strip off final dot */ 166338032Speter p = &host[strlen(host) - 1]; 166438032Speter if (*p == '.') 166538032Speter { 166638032Speter *p = '\0'; 166738032Speter canon = TRUE; 166838032Speter } 166938032Speter 167038032Speter /* see if there is any domain at all -- if not, we are done */ 167138032Speter p = strchr(host, '.'); 167238032Speter if (p == NULL) 167338032Speter return; 167438032Speter 167538032Speter /* yes, we have a domain -- see if it looks like us */ 167638032Speter mydom = macvalue('m', CurEnv); 167738032Speter if (mydom == NULL) 167838032Speter mydom = ""; 167938032Speter i = strlen(++p); 168038032Speter if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 && 168138032Speter (mydom[i] == '.' || mydom[i] == '\0')) 168238032Speter *--p = '\0'; 168338032Speter} 168438032Speter/* 168538032Speter** PROG_OPEN -- open a program for reading 168638032Speter** 168738032Speter** Parameters: 168838032Speter** argv -- the argument list. 168938032Speter** pfd -- pointer to a place to store the file descriptor. 169038032Speter** e -- the current envelope. 169138032Speter** 169238032Speter** Returns: 169338032Speter** pid of the process -- -1 if it failed. 169438032Speter*/ 169538032Speter 169638032Speterint 169738032Speterprog_open(argv, pfd, e) 169838032Speter char **argv; 169938032Speter int *pfd; 170038032Speter ENVELOPE *e; 170138032Speter{ 170238032Speter int pid; 170338032Speter int i; 170438032Speter int saveerrno; 170538032Speter int fdv[2]; 170638032Speter char *p, *q; 170738032Speter char buf[MAXLINE + 1]; 170838032Speter extern int DtableSize; 170938032Speter 171038032Speter if (pipe(fdv) < 0) 171138032Speter { 171238032Speter syserr("%s: cannot create pipe for stdout", argv[0]); 171338032Speter return -1; 171438032Speter } 171538032Speter pid = fork(); 171638032Speter if (pid < 0) 171738032Speter { 171838032Speter syserr("%s: cannot fork", argv[0]); 171938032Speter close(fdv[0]); 172038032Speter close(fdv[1]); 172138032Speter return -1; 172238032Speter } 172338032Speter if (pid > 0) 172438032Speter { 172538032Speter /* parent */ 172638032Speter close(fdv[1]); 172738032Speter *pfd = fdv[0]; 172838032Speter return pid; 172938032Speter } 173038032Speter 173138032Speter /* child -- close stdin */ 173238032Speter close(0); 173338032Speter 173438032Speter /* stdout goes back to parent */ 173538032Speter close(fdv[0]); 173638032Speter if (dup2(fdv[1], 1) < 0) 173738032Speter { 173838032Speter syserr("%s: cannot dup2 for stdout", argv[0]); 173938032Speter _exit(EX_OSERR); 174038032Speter } 174138032Speter close(fdv[1]); 174238032Speter 174338032Speter /* stderr goes to transcript if available */ 174438032Speter if (e->e_xfp != NULL) 174538032Speter { 174638032Speter if (dup2(fileno(e->e_xfp), 2) < 0) 174738032Speter { 174838032Speter syserr("%s: cannot dup2 for stderr", argv[0]); 174938032Speter _exit(EX_OSERR); 175038032Speter } 175138032Speter } 175238032Speter 175338032Speter /* this process has no right to the queue file */ 175438032Speter if (e->e_lockfp != NULL) 175538032Speter close(fileno(e->e_lockfp)); 175638032Speter 175738032Speter /* run as default user */ 175838032Speter endpwent(); 175938032Speter if (setgid(DefGid) < 0 && geteuid() == 0) 176038032Speter syserr("prog_open: setgid(%ld) failed", (long) DefGid); 176138032Speter if (setuid(DefUid) < 0 && geteuid() == 0) 176238032Speter syserr("prog_open: setuid(%ld) failed", (long) DefUid); 176338032Speter 176438032Speter /* run in some directory */ 176538032Speter if (ProgMailer != NULL) 176638032Speter p = ProgMailer->m_execdir; 176738032Speter else 176838032Speter p = NULL; 176938032Speter for (; p != NULL; p = q) 177038032Speter { 177138032Speter q = strchr(p, ':'); 177238032Speter if (q != NULL) 177338032Speter *q = '\0'; 177438032Speter expand(p, buf, sizeof buf, e); 177538032Speter if (q != NULL) 177638032Speter *q++ = ':'; 177738032Speter if (buf[0] != '\0' && chdir(buf) >= 0) 177838032Speter break; 177938032Speter } 178038032Speter if (p == NULL) 178138032Speter { 178238032Speter /* backup directories */ 178338032Speter if (chdir("/tmp") < 0) 178438032Speter (void) chdir("/"); 178538032Speter } 178638032Speter 178738032Speter /* arrange for all the files to be closed */ 178838032Speter for (i = 3; i < DtableSize; i++) 178938032Speter { 179038032Speter register int j; 179138032Speter 179238032Speter if ((j = fcntl(i, F_GETFD, 0)) != -1) 179338032Speter (void) fcntl(i, F_SETFD, j | 1); 179438032Speter } 179538032Speter 179638032Speter /* now exec the process */ 179738032Speter execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron); 179838032Speter 179938032Speter /* woops! failed */ 180038032Speter saveerrno = errno; 180138032Speter syserr("%s: cannot exec", argv[0]); 180238032Speter if (transienterror(saveerrno)) 180338032Speter _exit(EX_OSERR); 180438032Speter _exit(EX_CONFIG); 180538032Speter return -1; /* avoid compiler warning on IRIX */ 180638032Speter} 180738032Speter/* 180838032Speter** GET_COLUMN -- look up a Column in a line buffer 180938032Speter** 181038032Speter** Parameters: 181138032Speter** line -- the raw text line to search. 181238032Speter** col -- the column number to fetch. 181338032Speter** delim -- the delimiter between columns. If null, 181438032Speter** use white space. 181538032Speter** buf -- the output buffer. 181638032Speter** buflen -- the length of buf. 181738032Speter** 181838032Speter** Returns: 181938032Speter** buf if successful. 182038032Speter** NULL otherwise. 182138032Speter*/ 182238032Speter 182338032Speterchar * 182438032Speterget_column(line, col, delim, buf, buflen) 182538032Speter char line[]; 182638032Speter int col; 182738032Speter char delim; 182838032Speter char buf[]; 182938032Speter int buflen; 183038032Speter{ 183138032Speter char *p; 183238032Speter char *begin, *end; 183338032Speter int i; 183438032Speter char delimbuf[4]; 183538032Speter 183638032Speter if (delim == '\0') 183738032Speter strcpy(delimbuf, "\n\t "); 183838032Speter else 183938032Speter { 184038032Speter delimbuf[0] = delim; 184138032Speter delimbuf[1] = '\0'; 184238032Speter } 184338032Speter 184438032Speter p = line; 184538032Speter if (*p == '\0') 184638032Speter return NULL; /* line empty */ 184738032Speter if (*p == delim && col == 0) 184838032Speter return NULL; /* first column empty */ 184938032Speter 185038032Speter begin = line; 185138032Speter 185238032Speter if (col == 0 && delim == '\0') 185338032Speter { 185438032Speter while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 185538032Speter begin++; 185638032Speter } 185738032Speter 185838032Speter for (i = 0; i < col; i++) 185938032Speter { 186038032Speter if ((begin = strpbrk(begin, delimbuf)) == NULL) 186138032Speter return NULL; /* no such column */ 186238032Speter begin++; 186338032Speter if (delim == '\0') 186438032Speter { 186538032Speter while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 186638032Speter begin++; 186738032Speter } 186838032Speter } 186938032Speter 187038032Speter end = strpbrk(begin, delimbuf); 187138032Speter if (end == NULL) 187238032Speter i = strlen(begin); 187338032Speter else 187438032Speter i = end - begin; 187538032Speter if (i >= buflen) 187638032Speter i = buflen - 1; 187738032Speter strncpy(buf, begin, i); 187838032Speter buf[i] = '\0'; 187938032Speter return buf; 188038032Speter} 188138032Speter/* 188238032Speter** CLEANSTRCPY -- copy string keeping out bogus characters 188338032Speter** 188438032Speter** Parameters: 188538032Speter** t -- "to" string. 188638032Speter** f -- "from" string. 188738032Speter** l -- length of space available in "to" string. 188838032Speter** 188938032Speter** Returns: 189038032Speter** none. 189138032Speter*/ 189238032Speter 189338032Spetervoid 189438032Spetercleanstrcpy(t, f, l) 189538032Speter register char *t; 189638032Speter register char *f; 189738032Speter int l; 189838032Speter{ 189938032Speter /* check for newlines and log if necessary */ 190038032Speter (void) denlstring(f, TRUE, TRUE); 190138032Speter 190238032Speter l--; 190338032Speter while (l > 0 && *f != '\0') 190438032Speter { 190538032Speter if (isascii(*f) && 190638032Speter (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) 190738032Speter { 190838032Speter l--; 190938032Speter *t++ = *f; 191038032Speter } 191138032Speter f++; 191238032Speter } 191338032Speter *t = '\0'; 191438032Speter} 191538032Speter/* 191638032Speter** DENLSTRING -- convert newlines in a string to spaces 191738032Speter** 191838032Speter** Parameters: 191938032Speter** s -- the input string 192038032Speter** strict -- if set, don't permit continuation lines. 192138032Speter** logattacks -- if set, log attempted attacks. 192238032Speter** 192338032Speter** Returns: 192438032Speter** A pointer to a version of the string with newlines 192538032Speter** mapped to spaces. This should be copied. 192638032Speter*/ 192738032Speter 192838032Speterchar * 192938032Speterdenlstring(s, strict, logattacks) 193038032Speter char *s; 193138032Speter bool strict; 193238032Speter bool logattacks; 193338032Speter{ 193438032Speter register char *p; 193538032Speter int l; 193638032Speter static char *bp = NULL; 193738032Speter static int bl = 0; 193838032Speter 193938032Speter p = s; 194038032Speter while ((p = strchr(p, '\n')) != NULL) 194138032Speter if (strict || (*++p != ' ' && *p != '\t')) 194238032Speter break; 194338032Speter if (p == NULL) 194438032Speter return s; 194538032Speter 194638032Speter l = strlen(s) + 1; 194738032Speter if (bl < l) 194838032Speter { 194938032Speter /* allocate more space */ 195038032Speter if (bp != NULL) 195138032Speter free(bp); 195238032Speter bp = xalloc(l); 195338032Speter bl = l; 195438032Speter } 195538032Speter strcpy(bp, s); 195638032Speter for (p = bp; (p = strchr(p, '\n')) != NULL; ) 195738032Speter *p++ = ' '; 195838032Speter 195938032Speter if (logattacks) 196038032Speter { 196138032Speter sm_syslog(LOG_NOTICE, CurEnv->e_id, 196238032Speter "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", 196338032Speter RealHostName == NULL ? "[UNKNOWN]" : RealHostName, 196438032Speter shortenstring(bp, MAXSHORTSTR)); 196538032Speter } 196638032Speter 196738032Speter return bp; 196838032Speter} 196938032Speter/* 197038032Speter** PATH_IS_DIR -- check to see if file exists and is a directory. 197138032Speter** 197238032Speter** There are some additional checks for security violations in 197338032Speter** here. This routine is intended to be used for the host status 197438032Speter** support. 197538032Speter** 197638032Speter** Parameters: 197738032Speter** pathname -- pathname to check for directory-ness. 197838032Speter** createflag -- if set, create directory if needed. 197938032Speter** 198038032Speter** Returns: 198138032Speter** TRUE -- if the indicated pathname is a directory 198238032Speter** FALSE -- otherwise 198338032Speter*/ 198438032Speter 198538032Speterint 198638032Speterpath_is_dir(pathname, createflag) 198738032Speter char *pathname; 198838032Speter bool createflag; 198938032Speter{ 199038032Speter struct stat statbuf; 199138032Speter 199238032Speter#if HASLSTAT 199338032Speter if (lstat(pathname, &statbuf) < 0) 199438032Speter#else 199538032Speter if (stat(pathname, &statbuf) < 0) 199638032Speter#endif 199738032Speter { 199838032Speter if (errno != ENOENT || !createflag) 199938032Speter return FALSE; 200038032Speter if (mkdir(pathname, 0755) < 0) 200138032Speter return FALSE; 200238032Speter return TRUE; 200338032Speter } 200438032Speter if (!S_ISDIR(statbuf.st_mode)) 200538032Speter { 200638032Speter errno = ENOTDIR; 200738032Speter return FALSE; 200838032Speter } 200938032Speter 201038032Speter /* security: don't allow writable directories */ 201138032Speter if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) 201238032Speter { 201338032Speter errno = EACCES; 201438032Speter return FALSE; 201538032Speter } 201638032Speter 201738032Speter return TRUE; 201838032Speter} 201938032Speter/* 202038032Speter** PROC_LIST_ADD -- add process id to list of our children 202138032Speter** 202238032Speter** Parameters: 202338032Speter** pid -- pid to add to list. 202438032Speter** 202538032Speter** Returns: 202638032Speter** none 202738032Speter*/ 202838032Speter 202942575Speterstruct procs 203042575Speter{ 203142575Speter pid_t proc_pid; 203242575Speter char *proc_task; 203342575Speter}; 203442575Speter 203542575Speterstatic struct procs *ProcListVec = NULL; 203638032Speterstatic int ProcListSize = 0; 203738032Speter 203838032Speter#define NO_PID ((pid_t) 0) 203938032Speter#ifndef PROC_LIST_SEG 204038032Speter# define PROC_LIST_SEG 32 /* number of pids to alloc at a time */ 204138032Speter#endif 204238032Speter 204338032Spetervoid 204442575Speterproc_list_add(pid, task) 204538032Speter pid_t pid; 204642575Speter char *task; 204738032Speter{ 204838032Speter int i; 204938032Speter 205038032Speter for (i = 0; i < ProcListSize; i++) 205138032Speter { 205242575Speter if (ProcListVec[i].proc_pid == NO_PID) 205338032Speter break; 205438032Speter } 205538032Speter if (i >= ProcListSize) 205638032Speter { 205738032Speter /* probe the existing vector to avoid growing infinitely */ 205838032Speter proc_list_probe(); 205938032Speter 206038032Speter /* now scan again */ 206138032Speter for (i = 0; i < ProcListSize; i++) 206238032Speter { 206342575Speter if (ProcListVec[i].proc_pid == NO_PID) 206438032Speter break; 206538032Speter } 206638032Speter } 206738032Speter if (i >= ProcListSize) 206838032Speter { 206938032Speter /* grow process list */ 207042575Speter struct procs *npv; 207138032Speter 207242575Speter npv = (struct procs *) xalloc(sizeof (struct procs) * (ProcListSize + PROC_LIST_SEG)); 207338032Speter if (ProcListSize > 0) 207438032Speter { 207542575Speter bcopy(ProcListVec, npv, ProcListSize * 207642575Speter sizeof (struct procs)); 207738032Speter free(ProcListVec); 207838032Speter } 207938032Speter for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) 208042575Speter { 208142575Speter npv[i].proc_pid = NO_PID; 208242575Speter npv[i].proc_task = NULL; 208342575Speter } 208438032Speter i = ProcListSize; 208538032Speter ProcListSize += PROC_LIST_SEG; 208638032Speter ProcListVec = npv; 208738032Speter } 208842575Speter ProcListVec[i].proc_pid = pid; 208942575Speter ProcListVec[i].proc_task = newstr(task); 209042575Speter 209142575Speter /* if process adding itself, it's not a child */ 209242575Speter if (pid != getpid()) 209342575Speter CurChildren++; 209438032Speter} 209538032Speter/* 209642575Speter** PROC_LIST_SET -- set pid task in process list 209742575Speter** 209842575Speter** Parameters: 209942575Speter** pid -- pid to set 210042575Speter** task -- task of pid 210142575Speter** 210242575Speter** Returns: 210342575Speter** none. 210442575Speter*/ 210542575Speter 210642575Spetervoid 210742575Speterproc_list_set(pid, task) 210842575Speter pid_t pid; 210942575Speter char *task; 211042575Speter{ 211142575Speter int i; 211242575Speter 211342575Speter for (i = 0; i < ProcListSize; i++) 211442575Speter { 211542575Speter if (ProcListVec[i].proc_pid == pid) 211642575Speter { 211742575Speter if (ProcListVec[i].proc_task != NULL) 211842575Speter free(ProcListVec[i].proc_task); 211942575Speter ProcListVec[i].proc_task = newstr(task); 212042575Speter break; 212142575Speter } 212242575Speter } 212342575Speter} 212442575Speter/* 212538032Speter** PROC_LIST_DROP -- drop pid from process list 212638032Speter** 212738032Speter** Parameters: 212838032Speter** pid -- pid to drop 212938032Speter** 213038032Speter** Returns: 213138032Speter** none. 213238032Speter*/ 213338032Speter 213438032Spetervoid 213538032Speterproc_list_drop(pid) 213638032Speter pid_t pid; 213738032Speter{ 213838032Speter int i; 213938032Speter 214038032Speter for (i = 0; i < ProcListSize; i++) 214138032Speter { 214242575Speter if (ProcListVec[i].proc_pid == pid) 214338032Speter { 214442575Speter ProcListVec[i].proc_pid = NO_PID; 214542575Speter if (ProcListVec[i].proc_task != NULL) 214642575Speter { 214742575Speter free(ProcListVec[i].proc_task); 214842575Speter ProcListVec[i].proc_task = NULL; 214942575Speter } 215038032Speter break; 215138032Speter } 215238032Speter } 215338032Speter if (CurChildren > 0) 215438032Speter CurChildren--; 215538032Speter} 215638032Speter/* 215738032Speter** PROC_LIST_CLEAR -- clear the process list 215838032Speter** 215938032Speter** Parameters: 216038032Speter** none. 216138032Speter** 216238032Speter** Returns: 216338032Speter** none. 216438032Speter*/ 216538032Speter 216638032Spetervoid 216738032Speterproc_list_clear() 216838032Speter{ 216938032Speter int i; 217038032Speter 217142575Speter /* start from 1 since 0 is the daemon itself */ 217242575Speter for (i = 1; i < ProcListSize; i++) 217342575Speter { 217442575Speter ProcListVec[i].proc_pid = NO_PID; 217542575Speter if (ProcListVec[i].proc_task != NULL) 217642575Speter { 217742575Speter free(ProcListVec[i].proc_task); 217842575Speter ProcListVec[i].proc_task = NULL; 217942575Speter } 218042575Speter } 218138032Speter CurChildren = 0; 218238032Speter} 218338032Speter/* 218438032Speter** PROC_LIST_PROBE -- probe processes in the list to see if they still exist 218538032Speter** 218638032Speter** Parameters: 218738032Speter** none 218838032Speter** 218938032Speter** Returns: 219038032Speter** none 219138032Speter*/ 219238032Speter 219338032Spetervoid 219438032Speterproc_list_probe() 219538032Speter{ 219638032Speter int i; 219738032Speter 219842575Speter /* start from 1 since 0 is the daemon itself */ 219942575Speter for (i = 1; i < ProcListSize; i++) 220038032Speter { 220142575Speter if (ProcListVec[i].proc_pid == NO_PID) 220238032Speter continue; 220342575Speter if (kill(ProcListVec[i].proc_pid, 0) < 0) 220438032Speter { 220538032Speter if (LogLevel > 3) 220638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 220738032Speter "proc_list_probe: lost pid %d", 220842575Speter (int) ProcListVec[i].proc_pid); 220942575Speter ProcListVec[i].proc_pid = NO_PID; 221042575Speter if (ProcListVec[i].proc_task != NULL) 221142575Speter { 221242575Speter free(ProcListVec[i].proc_task); 221342575Speter ProcListVec[i].proc_task = NULL; 221442575Speter } 221538032Speter CurChildren--; 221638032Speter } 221738032Speter } 221838032Speter if (CurChildren < 0) 221938032Speter CurChildren = 0; 222038032Speter} 222138032Speter/* 222242575Speter** PROC_LIST_DISPLAY -- display the process list 222342575Speter** 222442575Speter** Parameters: 222542575Speter** out -- output file pointer 222642575Speter** 222742575Speter** Returns: 222842575Speter** none. 222942575Speter*/ 223042575Speter 223142575Spetervoid 223242575Speterproc_list_display(out) 223342575Speter FILE *out; 223442575Speter{ 223542575Speter int i; 223642575Speter 223742575Speter for (i = 0; i < ProcListSize; i++) 223842575Speter { 223942575Speter if (ProcListVec[i].proc_pid == NO_PID) 224042575Speter continue; 224142575Speter 224242575Speter fprintf(out, "%d %s%s\n", (int) ProcListVec[i].proc_pid, 224342575Speter ProcListVec[i].proc_task != NULL ? 224442575Speter ProcListVec[i].proc_task : "(unknown)", 224542575Speter (OpMode == MD_SMTP || 224642575Speter OpMode == MD_DAEMON || 224742575Speter OpMode == MD_ARPAFTP) ? "\r" : ""); 224842575Speter } 224942575Speter} 225042575Speter/* 225138032Speter** SM_STRCASECMP -- 8-bit clean version of strcasecmp 225238032Speter** 225338032Speter** Thank you, vendors, for making this all necessary. 225438032Speter*/ 225538032Speter 225638032Speter/* 225738032Speter * Copyright (c) 1987, 1993 225838032Speter * The Regents of the University of California. All rights reserved. 225938032Speter * 226038032Speter * Redistribution and use in source and binary forms, with or without 226138032Speter * modification, are permitted provided that the following conditions 226238032Speter * are met: 226338032Speter * 1. Redistributions of source code must retain the above copyright 226438032Speter * notice, this list of conditions and the following disclaimer. 226538032Speter * 2. Redistributions in binary form must reproduce the above copyright 226638032Speter * notice, this list of conditions and the following disclaimer in the 226738032Speter * documentation and/or other materials provided with the distribution. 226838032Speter * 3. All advertising materials mentioning features or use of this software 226938032Speter * must display the following acknowledgement: 227038032Speter * This product includes software developed by the University of 227138032Speter * California, Berkeley and its contributors. 227238032Speter * 4. Neither the name of the University nor the names of its contributors 227338032Speter * may be used to endorse or promote products derived from this software 227438032Speter * without specific prior written permission. 227538032Speter * 227638032Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 227738032Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 227838032Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 227938032Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 228038032Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228138032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228238032Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 228338032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228438032Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 228538032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 228638032Speter * SUCH DAMAGE. 228738032Speter */ 228838032Speter 228938032Speter#if defined(LIBC_SCCS) && !defined(lint) 229038032Speterstatic char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; 229138032Speter#endif /* LIBC_SCCS and not lint */ 229238032Speter 229338032Speter/* 229438032Speter * This array is designed for mapping upper and lower case letter 229538032Speter * together for a case independent comparison. The mappings are 229638032Speter * based upon ascii character sequences. 229738032Speter */ 229838032Speterstatic const u_char charmap[] = { 229938032Speter 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 230038032Speter 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, 230138032Speter 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, 230238032Speter 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, 230338032Speter 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, 230438032Speter 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, 230538032Speter 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 230638032Speter 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, 230738032Speter 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 230838032Speter 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 230938032Speter 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 231038032Speter 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, 231138032Speter 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 231238032Speter 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 231338032Speter 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 231438032Speter 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, 231538032Speter 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 231638032Speter 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, 231738032Speter 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 231838032Speter 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, 231938032Speter 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 232038032Speter 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 232138032Speter 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 232238032Speter 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 232338032Speter 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 232438032Speter 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, 232538032Speter 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 232638032Speter 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 232738032Speter 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 232838032Speter 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, 232938032Speter 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 233038032Speter 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, 233138032Speter}; 233238032Speter 233338032Speterint 233438032Spetersm_strcasecmp(s1, s2) 233538032Speter const char *s1, *s2; 233638032Speter{ 233738032Speter register const u_char *cm = charmap, 233838032Speter *us1 = (const u_char *)s1, 233938032Speter *us2 = (const u_char *)s2; 234038032Speter 234138032Speter while (cm[*us1] == cm[*us2++]) 234238032Speter if (*us1++ == '\0') 234338032Speter return (0); 234438032Speter return (cm[*us1] - cm[*--us2]); 234538032Speter} 234638032Speter 234738032Speterint 234838032Spetersm_strncasecmp(s1, s2, n) 234938032Speter const char *s1, *s2; 235038032Speter register size_t n; 235138032Speter{ 235238032Speter if (n != 0) { 235338032Speter register const u_char *cm = charmap, 235438032Speter *us1 = (const u_char *)s1, 235538032Speter *us2 = (const u_char *)s2; 235638032Speter 235738032Speter do { 235838032Speter if (cm[*us1] != cm[*us2++]) 235938032Speter return (cm[*us1] - cm[*--us2]); 236038032Speter if (*us1++ == '\0') 236138032Speter break; 236238032Speter } while (--n != 0); 236338032Speter } 236438032Speter return (0); 236538032Speter} 2366