util.c revision 80785
138032Speter/* 273188Sgshapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1438032Speter#ifndef lint 1580785Sgshapirostatic char id[] = "@(#)$Id: util.c,v 8.225.2.1.2.26 2001/06/01 08:23:25 gshapiro Exp $"; 1664562Sgshapiro#endif /* ! lint */ 1738032Speter 1864562Sgshapiro#include <sendmail.h> 1964562Sgshapiro#include <sysexits.h> 2064562Sgshapiro 2164562Sgshapiro 2264562Sgshapirostatic void readtimeout __P((time_t)); 2364562Sgshapiro 2438032Speter/* 2538032Speter** STRIPQUOTES -- Strip quotes & quote bits from a string. 2638032Speter** 2738032Speter** Runs through a string and strips off unquoted quote 2838032Speter** characters and quote bits. This is done in place. 2938032Speter** 3038032Speter** Parameters: 3138032Speter** s -- the string to strip. 3238032Speter** 3338032Speter** Returns: 3438032Speter** none. 3538032Speter** 3638032Speter** Side Effects: 3738032Speter** none. 3838032Speter*/ 3938032Speter 4038032Spetervoid 4138032Speterstripquotes(s) 4238032Speter char *s; 4338032Speter{ 4438032Speter register char *p; 4538032Speter register char *q; 4638032Speter register char c; 4738032Speter 4838032Speter if (s == NULL) 4938032Speter return; 5038032Speter 5138032Speter p = q = s; 5238032Speter do 5338032Speter { 5438032Speter c = *p++; 5538032Speter if (c == '\\') 5638032Speter c = *p++; 5738032Speter else if (c == '"') 5838032Speter continue; 5938032Speter *q++ = c; 6038032Speter } while (c != '\0'); 6138032Speter} 6238032Speter/* 6338032Speter** ADDQUOTES -- Adds quotes & quote bits to a string. 6438032Speter** 6538032Speter** Runs through a string and adds characters and quote bits. 6638032Speter** 6738032Speter** Parameters: 6838032Speter** s -- the string to modify. 6938032Speter** 7038032Speter** Returns: 7138032Speter** pointer to quoted string. 7238032Speter** 7338032Speter** Side Effects: 7438032Speter** none. 7538032Speter** 7638032Speter*/ 7738032Speter 7838032Speterchar * 7938032Speteraddquotes(s) 8038032Speter char *s; 8138032Speter{ 8238032Speter int len = 0; 8338032Speter char c; 8438032Speter char *p = s, *q, *r; 8538032Speter 8638032Speter if (s == NULL) 8738032Speter return NULL; 8838032Speter 8938032Speter /* Find length of quoted string */ 9038032Speter while ((c = *p++) != '\0') 9138032Speter { 9238032Speter len++; 9338032Speter if (c == '\\' || c == '"') 9438032Speter len++; 9538032Speter } 9664562Sgshapiro 9738032Speter q = r = xalloc(len + 3); 9838032Speter p = s; 9938032Speter 10038032Speter /* add leading quote */ 10138032Speter *q++ = '"'; 10238032Speter while ((c = *p++) != '\0') 10338032Speter { 10438032Speter /* quote \ or " */ 10538032Speter if (c == '\\' || c == '"') 10638032Speter *q++ = '\\'; 10738032Speter *q++ = c; 10838032Speter } 10938032Speter *q++ = '"'; 11038032Speter *q = '\0'; 11138032Speter return r; 11238032Speter} 11338032Speter/* 11438032Speter** RFC822_STRING -- Checks string for proper RFC822 string quoting. 11538032Speter** 11638032Speter** Runs through a string and verifies RFC822 special characters 11738032Speter** are only found inside comments, quoted strings, or backslash 11838032Speter** escaped. Also verified balanced quotes and parenthesis. 11938032Speter** 12038032Speter** Parameters: 12138032Speter** s -- the string to modify. 12238032Speter** 12338032Speter** Returns: 12438032Speter** TRUE -- if the string is RFC822 compliant. 12538032Speter** FALSE -- if the string is not RFC822 compliant. 12638032Speter** 12738032Speter** Side Effects: 12838032Speter** none. 12938032Speter** 13038032Speter*/ 13138032Speter 13238032Speterbool 13338032Speterrfc822_string(s) 13438032Speter char *s; 13538032Speter{ 13638032Speter bool quoted = FALSE; 13738032Speter int commentlev = 0; 13838032Speter char *c = s; 13938032Speter 14038032Speter if (s == NULL) 14138032Speter return FALSE; 14238032Speter 14338032Speter while (*c != '\0') 14438032Speter { 14538032Speter /* escaped character */ 14638032Speter if (*c == '\\') 14738032Speter { 14838032Speter c++; 14938032Speter if (*c == '\0') 15038032Speter return FALSE; 15138032Speter } 15238032Speter else if (commentlev == 0 && *c == '"') 15338032Speter quoted = !quoted; 15438032Speter else if (!quoted) 15538032Speter { 15638032Speter if (*c == ')') 15738032Speter { 15838032Speter /* unbalanced ')' */ 15938032Speter if (commentlev == 0) 16038032Speter return FALSE; 16138032Speter else 16238032Speter commentlev--; 16338032Speter } 16438032Speter else if (*c == '(') 16538032Speter commentlev++; 16638032Speter else if (commentlev == 0 && 16738032Speter strchr(MustQuoteChars, *c) != NULL) 16838032Speter return FALSE; 16938032Speter } 17038032Speter c++; 17138032Speter } 17238032Speter /* unbalanced '"' or '(' */ 17338032Speter if (quoted || commentlev != 0) 17438032Speter return FALSE; 17538032Speter else 17638032Speter return TRUE; 17738032Speter} 17838032Speter/* 17942575Speter** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string 18042575Speter** 18164562Sgshapiro** Arbitrarily shorten (in place) an RFC822 string and rebalance 18242575Speter** comments and quotes. 18342575Speter** 18442575Speter** Parameters: 18542575Speter** string -- the string to shorten 18642575Speter** length -- the maximum size, 0 if no maximum 18742575Speter** 18842575Speter** Returns: 18942575Speter** TRUE if string is changed, FALSE otherwise 19042575Speter** 19142575Speter** Side Effects: 19242575Speter** Changes string in place, possibly resulting 19342575Speter** in a shorter string. 19442575Speter*/ 19542575Speter 19642575Speterbool 19742575Spetershorten_rfc822_string(string, length) 19842575Speter char *string; 19942575Speter size_t length; 20042575Speter{ 20142575Speter bool backslash = FALSE; 20242575Speter bool modified = FALSE; 20342575Speter bool quoted = FALSE; 20442575Speter size_t slen; 20542575Speter int parencount = 0; 20642575Speter char *ptr = string; 20764562Sgshapiro 20842575Speter /* 20942575Speter ** If have to rebalance an already short enough string, 21042575Speter ** need to do it within allocated space. 21142575Speter */ 21271345Sgshapiro 21342575Speter slen = strlen(string); 21442575Speter if (length == 0 || slen < length) 21542575Speter length = slen; 21642575Speter 21742575Speter while (*ptr != '\0') 21842575Speter { 21942575Speter if (backslash) 22042575Speter { 22142575Speter backslash = FALSE; 22242575Speter goto increment; 22342575Speter } 22442575Speter 22542575Speter if (*ptr == '\\') 22642575Speter backslash = TRUE; 22742575Speter else if (*ptr == '(') 22842575Speter { 22942575Speter if (!quoted) 23042575Speter parencount++; 23142575Speter } 23242575Speter else if (*ptr == ')') 23342575Speter { 23442575Speter if (--parencount < 0) 23542575Speter parencount = 0; 23642575Speter } 23764562Sgshapiro 23842575Speter /* Inside a comment, quotes don't matter */ 23942575Speter if (parencount <= 0 && *ptr == '"') 24042575Speter quoted = !quoted; 24142575Speter 24242575Speterincrement: 24342575Speter /* Check for sufficient space for next character */ 24464562Sgshapiro if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) + 24542575Speter parencount + 24642575Speter (quoted ? 1 : 0))) 24742575Speter { 24842575Speter /* Not enough, backtrack */ 24942575Speter if (*ptr == '\\') 25042575Speter backslash = FALSE; 25142575Speter else if (*ptr == '(' && !quoted) 25242575Speter parencount--; 25342575Speter else if (*ptr == '"' && parencount == 0) 25442575Speter quoted = FALSE; 25542575Speter break; 25642575Speter } 25742575Speter ptr++; 25842575Speter } 25942575Speter 26042575Speter /* Rebalance */ 26142575Speter while (parencount-- > 0) 26242575Speter { 26342575Speter if (*ptr != ')') 26442575Speter { 26542575Speter modified = TRUE; 26642575Speter *ptr = ')'; 26742575Speter } 26842575Speter ptr++; 26942575Speter } 27042575Speter if (quoted) 27142575Speter { 27242575Speter if (*ptr != '"') 27342575Speter { 27442575Speter modified = TRUE; 27542575Speter *ptr = '"'; 27642575Speter } 27742575Speter ptr++; 27842575Speter } 27942575Speter if (*ptr != '\0') 28042575Speter { 28142575Speter modified = TRUE; 28242575Speter *ptr = '\0'; 28342575Speter } 28442575Speter return modified; 28542575Speter} 28642575Speter/* 28742575Speter** FIND_CHARACTER -- find an unquoted character in an RFC822 string 28842575Speter** 28942575Speter** Find an unquoted, non-commented character in an RFC822 29042575Speter** string and return a pointer to its location in the 29142575Speter** string. 29242575Speter** 29342575Speter** Parameters: 29442575Speter** string -- the string to search 29542575Speter** character -- the character to find 29642575Speter** 29742575Speter** Returns: 29842575Speter** pointer to the character, or 29942575Speter** a pointer to the end of the line if character is not found 30042575Speter*/ 30142575Speter 30242575Speterchar * 30342575Speterfind_character(string, character) 30442575Speter char *string; 30564562Sgshapiro int character; 30642575Speter{ 30742575Speter bool backslash = FALSE; 30842575Speter bool quoted = FALSE; 30942575Speter int parencount = 0; 31064562Sgshapiro 31142575Speter while (string != NULL && *string != '\0') 31242575Speter { 31342575Speter if (backslash) 31442575Speter { 31542575Speter backslash = FALSE; 31642575Speter if (!quoted && character == '\\' && *string == '\\') 31742575Speter break; 31842575Speter string++; 31942575Speter continue; 32042575Speter } 32142575Speter switch (*string) 32242575Speter { 32342575Speter case '\\': 32442575Speter backslash = TRUE; 32542575Speter break; 32664562Sgshapiro 32742575Speter case '(': 32842575Speter if (!quoted) 32942575Speter parencount++; 33042575Speter break; 33164562Sgshapiro 33242575Speter case ')': 33342575Speter if (--parencount < 0) 33442575Speter parencount = 0; 33542575Speter break; 33642575Speter } 33764562Sgshapiro 33842575Speter /* Inside a comment, nothing matters */ 33942575Speter if (parencount > 0) 34042575Speter { 34142575Speter string++; 34242575Speter continue; 34342575Speter } 34464562Sgshapiro 34542575Speter if (*string == '"') 34642575Speter quoted = !quoted; 34742575Speter else if (*string == character && !quoted) 34842575Speter break; 34942575Speter string++; 35042575Speter } 35142575Speter 35242575Speter /* Return pointer to the character */ 35342575Speter return string; 35442575Speter} 35542575Speter/* 35638032Speter** XALLOC -- Allocate memory and bitch wildly on failure. 35738032Speter** 35838032Speter** THIS IS A CLUDGE. This should be made to give a proper 35938032Speter** error -- but after all, what can we do? 36038032Speter** 36138032Speter** Parameters: 36238032Speter** sz -- size of area to allocate. 36338032Speter** 36438032Speter** Returns: 36538032Speter** pointer to data region. 36638032Speter** 36738032Speter** Side Effects: 36838032Speter** Memory is allocated. 36938032Speter*/ 37038032Speter 37138032Speterchar * 37238032Speterxalloc(sz) 37338032Speter register int sz; 37438032Speter{ 37538032Speter register char *p; 37638032Speter 37738032Speter /* some systems can't handle size zero mallocs */ 37838032Speter if (sz <= 0) 37938032Speter sz = 1; 38038032Speter 38177349Sgshapiro ENTER_CRITICAL(); 38238032Speter p = malloc((unsigned) sz); 38377349Sgshapiro LEAVE_CRITICAL(); 38438032Speter if (p == NULL) 38538032Speter { 38638032Speter syserr("!Out of memory!!"); 38777349Sgshapiro 38877349Sgshapiro /* NOTREACHED */ 38977349Sgshapiro exit(EX_UNAVAILABLE); 39038032Speter } 39164562Sgshapiro return p; 39238032Speter} 39338032Speter/* 39477349Sgshapiro** XREALLOC -- Reallocate memory and bitch wildly on failure. 39577349Sgshapiro** 39677349Sgshapiro** THIS IS A CLUDGE. This should be made to give a proper 39777349Sgshapiro** error -- but after all, what can we do? 39877349Sgshapiro** 39977349Sgshapiro** Parameters: 40077349Sgshapiro** ptr -- original area. 40177349Sgshapiro** sz -- size of new area to allocate. 40277349Sgshapiro** 40377349Sgshapiro** Returns: 40477349Sgshapiro** pointer to data region. 40577349Sgshapiro** 40677349Sgshapiro** Side Effects: 40777349Sgshapiro** Memory is allocated. 40877349Sgshapiro*/ 40977349Sgshapiro 41077349Sgshapirochar * 41177349Sgshapiroxrealloc(ptr, sz) 41277349Sgshapiro void *ptr; 41377349Sgshapiro size_t sz; 41477349Sgshapiro{ 41577349Sgshapiro register char *p; 41677349Sgshapiro 41777349Sgshapiro /* some systems can't handle size zero mallocs */ 41877349Sgshapiro if (sz <= 0) 41977349Sgshapiro sz = 1; 42077349Sgshapiro 42177349Sgshapiro ENTER_CRITICAL(); 42277349Sgshapiro p = realloc(ptr, (unsigned) sz); 42377349Sgshapiro LEAVE_CRITICAL(); 42477349Sgshapiro if (p == NULL) 42577349Sgshapiro { 42677349Sgshapiro syserr("!Out of memory!!"); 42777349Sgshapiro 42877349Sgshapiro /* NOTREACHED */ 42977349Sgshapiro exit(EX_UNAVAILABLE); 43077349Sgshapiro } 43177349Sgshapiro return p; 43277349Sgshapiro} 43377349Sgshapiro/* 43477349Sgshapiro** XCALLOC -- Allocate memory and bitch wildly on failure. 43577349Sgshapiro** 43677349Sgshapiro** THIS IS A CLUDGE. This should be made to give a proper 43777349Sgshapiro** error -- but after all, what can we do? 43877349Sgshapiro** 43977349Sgshapiro** Parameters: 44077349Sgshapiro** num -- number of items to allocate 44177349Sgshapiro** sz -- size of new area to allocate. 44277349Sgshapiro** 44377349Sgshapiro** Returns: 44477349Sgshapiro** pointer to data region. 44577349Sgshapiro** 44677349Sgshapiro** Side Effects: 44777349Sgshapiro** Memory is allocated. 44877349Sgshapiro*/ 44977349Sgshapiro 45077349Sgshapirochar * 45177349Sgshapiroxcalloc(num, sz) 45277349Sgshapiro size_t num; 45377349Sgshapiro size_t sz; 45477349Sgshapiro{ 45577349Sgshapiro register char *p; 45677349Sgshapiro 45777349Sgshapiro /* some systems can't handle size zero mallocs */ 45877349Sgshapiro if (num <= 0) 45977349Sgshapiro num = 1; 46077349Sgshapiro if (sz <= 0) 46177349Sgshapiro sz = 1; 46277349Sgshapiro 46377349Sgshapiro ENTER_CRITICAL(); 46477349Sgshapiro p = calloc((unsigned) num, (unsigned) sz); 46577349Sgshapiro LEAVE_CRITICAL(); 46677349Sgshapiro if (p == NULL) 46777349Sgshapiro { 46877349Sgshapiro syserr("!Out of memory!!"); 46977349Sgshapiro 47077349Sgshapiro /* NOTREACHED */ 47177349Sgshapiro exit(EX_UNAVAILABLE); 47277349Sgshapiro } 47377349Sgshapiro return p; 47477349Sgshapiro} 47577349Sgshapiro/* 47677349Sgshapiro** SM_FREE -- Free memory safely. 47777349Sgshapiro** 47877349Sgshapiro** Parameters: 47977349Sgshapiro** ptr -- area to free 48077349Sgshapiro** 48177349Sgshapiro** Returns: 48277349Sgshapiro** none. 48377349Sgshapiro** 48477349Sgshapiro** Side Effects: 48577349Sgshapiro** Memory is freed. 48677349Sgshapiro*/ 48777349Sgshapiro 48877349Sgshapirovoid 48977349Sgshapirosm_free(ptr) 49077349Sgshapiro void *ptr; 49177349Sgshapiro{ 49277349Sgshapiro ENTER_CRITICAL(); 49377349Sgshapiro free(ptr); 49477349Sgshapiro LEAVE_CRITICAL(); 49577349Sgshapiro} 49677349Sgshapiro/* 49738032Speter** COPYPLIST -- copy list of pointers. 49838032Speter** 49938032Speter** This routine is the equivalent of newstr for lists of 50038032Speter** pointers. 50138032Speter** 50238032Speter** Parameters: 50338032Speter** list -- list of pointers to copy. 50438032Speter** Must be NULL terminated. 50538032Speter** copycont -- if TRUE, copy the contents of the vector 50638032Speter** (which must be a string) also. 50738032Speter** 50838032Speter** Returns: 50938032Speter** a copy of 'list'. 51038032Speter** 51138032Speter** Side Effects: 51238032Speter** none. 51338032Speter*/ 51438032Speter 51538032Speterchar ** 51638032Spetercopyplist(list, copycont) 51738032Speter char **list; 51838032Speter bool copycont; 51938032Speter{ 52038032Speter register char **vp; 52138032Speter register char **newvp; 52238032Speter 52338032Speter for (vp = list; *vp != NULL; vp++) 52438032Speter continue; 52538032Speter 52638032Speter vp++; 52738032Speter 52838032Speter newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 52964562Sgshapiro memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof *vp); 53038032Speter 53138032Speter if (copycont) 53238032Speter { 53338032Speter for (vp = newvp; *vp != NULL; vp++) 53438032Speter *vp = newstr(*vp); 53538032Speter } 53638032Speter 53764562Sgshapiro return newvp; 53838032Speter} 53938032Speter/* 54038032Speter** COPYQUEUE -- copy address queue. 54138032Speter** 54238032Speter** This routine is the equivalent of newstr for address queues 54364562Sgshapiro** addresses marked as QS_IS_DEAD() aren't copied 54438032Speter** 54538032Speter** Parameters: 54638032Speter** addr -- list of address structures to copy. 54738032Speter** 54838032Speter** Returns: 54938032Speter** a copy of 'addr'. 55038032Speter** 55138032Speter** Side Effects: 55238032Speter** none. 55338032Speter*/ 55438032Speter 55538032SpeterADDRESS * 55638032Spetercopyqueue(addr) 55738032Speter ADDRESS *addr; 55838032Speter{ 55938032Speter register ADDRESS *newaddr; 56038032Speter ADDRESS *ret; 56138032Speter register ADDRESS **tail = &ret; 56238032Speter 56338032Speter while (addr != NULL) 56438032Speter { 56564562Sgshapiro if (!QS_IS_DEAD(addr->q_state)) 56638032Speter { 56764562Sgshapiro newaddr = (ADDRESS *) xalloc(sizeof *newaddr); 56838032Speter STRUCTCOPY(*addr, *newaddr); 56938032Speter *tail = newaddr; 57038032Speter tail = &newaddr->q_next; 57138032Speter } 57238032Speter addr = addr->q_next; 57338032Speter } 57438032Speter *tail = NULL; 57564562Sgshapiro 57638032Speter return ret; 57738032Speter} 57838032Speter/* 57964562Sgshapiro** LOG_SENDMAIL_PID -- record sendmail pid and command line. 58064562Sgshapiro** 58164562Sgshapiro** Parameters: 58264562Sgshapiro** e -- the current envelope. 58364562Sgshapiro** 58464562Sgshapiro** Returns: 58564562Sgshapiro** none. 58664562Sgshapiro** 58764562Sgshapiro** Side Effects: 58864562Sgshapiro** writes pidfile. 58964562Sgshapiro*/ 59064562Sgshapiro 59164562Sgshapirovoid 59264562Sgshapirolog_sendmail_pid(e) 59364562Sgshapiro ENVELOPE *e; 59464562Sgshapiro{ 59564562Sgshapiro long sff; 59664562Sgshapiro FILE *pidf; 59764562Sgshapiro char pidpath[MAXPATHLEN + 1]; 59864562Sgshapiro 59964562Sgshapiro /* write the pid to the log file for posterity */ 60064562Sgshapiro sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT; 60164562Sgshapiro if (TrustedUid != 0 && RealUid == TrustedUid) 60264562Sgshapiro sff |= SFF_OPENASROOT; 60364562Sgshapiro expand(PidFile, pidpath, sizeof pidpath, e); 60464562Sgshapiro pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, 0644, sff); 60564562Sgshapiro if (pidf == NULL) 60664562Sgshapiro { 60773188Sgshapiro sm_syslog(LOG_ERR, NOQID, "unable to write %s: %s", 60873188Sgshapiro pidpath, errstring(errno)); 60964562Sgshapiro } 61064562Sgshapiro else 61164562Sgshapiro { 61277349Sgshapiro pid_t pid; 61364562Sgshapiro extern char *CommandLineArgs; 61464562Sgshapiro 61577349Sgshapiro pid = getpid(); 61671345Sgshapiro 61764562Sgshapiro /* write the process id on line 1 */ 61877349Sgshapiro fprintf(pidf, "%ld\n", (long) pid); 61964562Sgshapiro 62064562Sgshapiro /* line 2 contains all command line flags */ 62164562Sgshapiro fprintf(pidf, "%s\n", CommandLineArgs); 62264562Sgshapiro 62364562Sgshapiro /* flush and close */ 62464562Sgshapiro (void) fclose(pidf); 62564562Sgshapiro } 62664562Sgshapiro} 62764562Sgshapiro/* 62864562Sgshapiro** SET_DELIVERY_MODE -- set and record the delivery mode 62964562Sgshapiro** 63064562Sgshapiro** Parameters: 63164562Sgshapiro** mode -- delivery mode 63264562Sgshapiro** e -- the current envelope. 63364562Sgshapiro** 63464562Sgshapiro** Returns: 63564562Sgshapiro** none. 63664562Sgshapiro** 63764562Sgshapiro** Side Effects: 63864562Sgshapiro** sets $&{deliveryMode} macro 63964562Sgshapiro*/ 64064562Sgshapiro 64164562Sgshapirovoid 64264562Sgshapiroset_delivery_mode(mode, e) 64364562Sgshapiro int mode; 64464562Sgshapiro ENVELOPE *e; 64564562Sgshapiro{ 64664562Sgshapiro char buf[2]; 64764562Sgshapiro 64864562Sgshapiro e->e_sendmode = (char)mode; 64964562Sgshapiro buf[0] = (char)mode; 65064562Sgshapiro buf[1] = '\0'; 65164562Sgshapiro define(macid("{deliveryMode}", NULL), newstr(buf), e); 65264562Sgshapiro} 65364562Sgshapiro/* 65438032Speter** PRINTAV -- print argument vector. 65538032Speter** 65638032Speter** Parameters: 65738032Speter** av -- argument vector. 65838032Speter** 65938032Speter** Returns: 66038032Speter** none. 66138032Speter** 66238032Speter** Side Effects: 66338032Speter** prints av. 66438032Speter*/ 66538032Speter 66638032Spetervoid 66738032Speterprintav(av) 66838032Speter register char **av; 66938032Speter{ 67038032Speter while (*av != NULL) 67138032Speter { 67238032Speter if (tTd(0, 44)) 67364562Sgshapiro dprintf("\n\t%08lx=", (u_long) *av); 67438032Speter else 67538032Speter (void) putchar(' '); 67638032Speter xputs(*av++); 67738032Speter } 67838032Speter (void) putchar('\n'); 67938032Speter} 68038032Speter/* 68138032Speter** LOWER -- turn letter into lower case. 68238032Speter** 68338032Speter** Parameters: 68438032Speter** c -- character to turn into lower case. 68538032Speter** 68638032Speter** Returns: 68738032Speter** c, in lower case. 68838032Speter** 68938032Speter** Side Effects: 69038032Speter** none. 69138032Speter*/ 69238032Speter 69338032Speterchar 69438032Speterlower(c) 69564562Sgshapiro register int c; 69638032Speter{ 69764562Sgshapiro return ((isascii(c) && isupper(c)) ? tolower(c) : c); 69838032Speter} 69938032Speter/* 70038032Speter** XPUTS -- put string doing control escapes. 70138032Speter** 70238032Speter** Parameters: 70338032Speter** s -- string to put. 70438032Speter** 70538032Speter** Returns: 70638032Speter** none. 70738032Speter** 70838032Speter** Side Effects: 70938032Speter** output to stdout 71038032Speter*/ 71138032Speter 71238032Spetervoid 71338032Speterxputs(s) 71438032Speter register const char *s; 71538032Speter{ 71638032Speter register int c; 71738032Speter register struct metamac *mp; 71838032Speter bool shiftout = FALSE; 71938032Speter extern struct metamac MetaMacros[]; 72038032Speter 72138032Speter if (s == NULL) 72238032Speter { 72338032Speter printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off); 72438032Speter return; 72538032Speter } 72638032Speter while ((c = (*s++ & 0377)) != '\0') 72738032Speter { 72838032Speter if (shiftout) 72938032Speter { 73038032Speter printf("%s", TermEscape.te_rv_off); 73138032Speter shiftout = FALSE; 73238032Speter } 73338032Speter if (!isascii(c)) 73438032Speter { 73538032Speter if (c == MATCHREPL) 73638032Speter { 73738032Speter printf("%s$", TermEscape.te_rv_on); 73838032Speter shiftout = TRUE; 73938032Speter if (*s == '\0') 74038032Speter continue; 74138032Speter c = *s++ & 0377; 74238032Speter goto printchar; 74338032Speter } 74438032Speter if (c == MACROEXPAND || c == MACRODEXPAND) 74538032Speter { 74638032Speter printf("%s$", TermEscape.te_rv_on); 74738032Speter if (c == MACRODEXPAND) 74864562Sgshapiro (void) putchar('&'); 74938032Speter shiftout = TRUE; 75038032Speter if (*s == '\0') 75138032Speter continue; 75238032Speter if (strchr("=~&?", *s) != NULL) 75364562Sgshapiro (void) putchar(*s++); 75438032Speter if (bitset(0200, *s)) 75571345Sgshapiro printf("{%s}", macname(bitidx(*s++))); 75638032Speter else 75738032Speter printf("%c", *s++); 75838032Speter continue; 75938032Speter } 76038032Speter for (mp = MetaMacros; mp->metaname != '\0'; mp++) 76138032Speter { 76238032Speter if ((mp->metaval & 0377) == c) 76338032Speter { 76438032Speter printf("%s$%c", 76538032Speter TermEscape.te_rv_on, 76638032Speter mp->metaname); 76738032Speter shiftout = TRUE; 76838032Speter break; 76938032Speter } 77038032Speter } 77138032Speter if (c == MATCHCLASS || c == MATCHNCLASS) 77238032Speter { 77338032Speter if (bitset(0200, *s)) 77438032Speter printf("{%s}", macname(*s++ & 0377)); 77538032Speter else if (*s != '\0') 77638032Speter printf("%c", *s++); 77738032Speter } 77838032Speter if (mp->metaname != '\0') 77938032Speter continue; 78038032Speter 78138032Speter /* unrecognized meta character */ 78238032Speter printf("%sM-", TermEscape.te_rv_on); 78338032Speter shiftout = TRUE; 78438032Speter c &= 0177; 78538032Speter } 78638032Speter printchar: 78738032Speter if (isprint(c)) 78838032Speter { 78964562Sgshapiro (void) putchar(c); 79038032Speter continue; 79138032Speter } 79238032Speter 79338032Speter /* wasn't a meta-macro -- find another way to print it */ 79438032Speter switch (c) 79538032Speter { 79638032Speter case '\n': 79738032Speter c = 'n'; 79838032Speter break; 79938032Speter 80038032Speter case '\r': 80138032Speter c = 'r'; 80238032Speter break; 80338032Speter 80438032Speter case '\t': 80538032Speter c = 't'; 80638032Speter break; 80738032Speter } 80838032Speter if (!shiftout) 80938032Speter { 81038032Speter printf("%s", TermEscape.te_rv_on); 81138032Speter shiftout = TRUE; 81238032Speter } 81338032Speter if (isprint(c)) 81438032Speter { 81538032Speter (void) putchar('\\'); 81638032Speter (void) putchar(c); 81738032Speter } 81838032Speter else 81938032Speter { 82038032Speter (void) putchar('^'); 82138032Speter (void) putchar(c ^ 0100); 82238032Speter } 82338032Speter } 82438032Speter if (shiftout) 82538032Speter printf("%s", TermEscape.te_rv_off); 82638032Speter (void) fflush(stdout); 82738032Speter} 82838032Speter/* 82938032Speter** MAKELOWER -- Translate a line into lower case 83038032Speter** 83138032Speter** Parameters: 83238032Speter** p -- the string to translate. If NULL, return is 83338032Speter** immediate. 83438032Speter** 83538032Speter** Returns: 83638032Speter** none. 83738032Speter** 83838032Speter** Side Effects: 83938032Speter** String pointed to by p is translated to lower case. 84038032Speter*/ 84138032Speter 84238032Spetervoid 84338032Spetermakelower(p) 84438032Speter register char *p; 84538032Speter{ 84638032Speter register char c; 84738032Speter 84838032Speter if (p == NULL) 84938032Speter return; 85038032Speter for (; (c = *p) != '\0'; p++) 85138032Speter if (isascii(c) && isupper(c)) 85238032Speter *p = tolower(c); 85338032Speter} 85438032Speter/* 85538032Speter** BUILDFNAME -- build full name from gecos style entry. 85638032Speter** 85738032Speter** This routine interprets the strange entry that would appear 85838032Speter** in the GECOS field of the password file. 85938032Speter** 86038032Speter** Parameters: 86138032Speter** p -- name to build. 86264562Sgshapiro** user -- the login name of this user (for &). 86338032Speter** buf -- place to put the result. 86438032Speter** buflen -- length of buf. 86538032Speter** 86638032Speter** Returns: 86738032Speter** none. 86838032Speter** 86938032Speter** Side Effects: 87038032Speter** none. 87138032Speter*/ 87238032Speter 87338032Spetervoid 87464562Sgshapirobuildfname(gecos, user, buf, buflen) 87538032Speter register char *gecos; 87664562Sgshapiro char *user; 87738032Speter char *buf; 87838032Speter int buflen; 87938032Speter{ 88038032Speter register char *p; 88138032Speter register char *bp = buf; 88238032Speter 88338032Speter if (*gecos == '*') 88438032Speter gecos++; 88538032Speter 88638032Speter /* copy gecos, interpolating & to be full name */ 88738032Speter for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 88838032Speter { 88938032Speter if (bp >= &buf[buflen - 1]) 89038032Speter { 89138032Speter /* buffer overflow -- just use login name */ 89264562Sgshapiro snprintf(buf, buflen, "%s", user); 89338032Speter return; 89438032Speter } 89538032Speter if (*p == '&') 89638032Speter { 89738032Speter /* interpolate full name */ 89864562Sgshapiro snprintf(bp, buflen - (bp - buf), "%s", user); 89938032Speter *bp = toupper(*bp); 90038032Speter bp += strlen(bp); 90138032Speter } 90238032Speter else 90338032Speter *bp++ = *p; 90438032Speter } 90538032Speter *bp = '\0'; 90638032Speter} 90738032Speter/* 90838032Speter** FIXCRLF -- fix <CR><LF> in line. 90938032Speter** 91038032Speter** Looks for the <CR><LF> combination and turns it into the 91138032Speter** UNIX canonical <NL> character. It only takes one line, 91238032Speter** i.e., it is assumed that the first <NL> found is the end 91338032Speter** of the line. 91438032Speter** 91538032Speter** Parameters: 91638032Speter** line -- the line to fix. 91738032Speter** stripnl -- if true, strip the newline also. 91838032Speter** 91938032Speter** Returns: 92038032Speter** none. 92138032Speter** 92238032Speter** Side Effects: 92338032Speter** line is changed in place. 92438032Speter*/ 92538032Speter 92638032Spetervoid 92738032Speterfixcrlf(line, stripnl) 92838032Speter char *line; 92938032Speter bool stripnl; 93038032Speter{ 93138032Speter register char *p; 93238032Speter 93338032Speter p = strchr(line, '\n'); 93438032Speter if (p == NULL) 93538032Speter return; 93638032Speter if (p > line && p[-1] == '\r') 93738032Speter p--; 93838032Speter if (!stripnl) 93938032Speter *p++ = '\n'; 94038032Speter *p = '\0'; 94138032Speter} 94238032Speter/* 94338032Speter** PUTLINE -- put a line like fputs obeying SMTP conventions 94438032Speter** 94538032Speter** This routine always guarantees outputing a newline (or CRLF, 94638032Speter** as appropriate) at the end of the string. 94738032Speter** 94838032Speter** Parameters: 94938032Speter** l -- line to put. 95038032Speter** mci -- the mailer connection information. 95138032Speter** 95238032Speter** Returns: 95338032Speter** none 95438032Speter** 95538032Speter** Side Effects: 95638032Speter** output of l to fp. 95738032Speter*/ 95838032Speter 95938032Spetervoid 96038032Speterputline(l, mci) 96138032Speter register char *l; 96238032Speter register MCI *mci; 96338032Speter{ 96438032Speter putxline(l, strlen(l), mci, PXLF_MAPFROM); 96538032Speter} 96638032Speter/* 96738032Speter** PUTXLINE -- putline with flags bits. 96838032Speter** 96938032Speter** This routine always guarantees outputing a newline (or CRLF, 97038032Speter** as appropriate) at the end of the string. 97138032Speter** 97238032Speter** Parameters: 97338032Speter** l -- line to put. 97438032Speter** len -- the length of the line. 97538032Speter** mci -- the mailer connection information. 97638032Speter** pxflags -- flag bits: 97738032Speter** PXLF_MAPFROM -- map From_ to >From_. 97838032Speter** PXLF_STRIP8BIT -- strip 8th bit. 97938032Speter** PXLF_HEADER -- map bare newline in header to newline space. 98038032Speter** 98138032Speter** Returns: 98238032Speter** none 98338032Speter** 98438032Speter** Side Effects: 98538032Speter** output of l to fp. 98638032Speter*/ 98738032Speter 98838032Spetervoid 98938032Speterputxline(l, len, mci, pxflags) 99038032Speter register char *l; 99138032Speter size_t len; 99238032Speter register MCI *mci; 99338032Speter int pxflags; 99438032Speter{ 99564562Sgshapiro bool dead = FALSE; 99638032Speter register char *p, *end; 99738032Speter int slop = 0; 99838032Speter 99938032Speter /* strip out 0200 bits -- these can look like TELNET protocol */ 100038032Speter if (bitset(MCIF_7BIT, mci->mci_flags) || 100138032Speter bitset(PXLF_STRIP8BIT, pxflags)) 100238032Speter { 100338032Speter register char svchar; 100438032Speter 100538032Speter for (p = l; (svchar = *p) != '\0'; ++p) 100638032Speter if (bitset(0200, svchar)) 100738032Speter *p = svchar &~ 0200; 100838032Speter } 100938032Speter 101038032Speter end = l + len; 101138032Speter do 101238032Speter { 101338032Speter /* find the end of the line */ 101438032Speter p = memchr(l, '\n', end - l); 101538032Speter if (p == NULL) 101638032Speter p = end; 101738032Speter 101838032Speter if (TrafficLogFile != NULL) 101938032Speter fprintf(TrafficLogFile, "%05d >>> ", (int) getpid()); 102038032Speter 102138032Speter /* check for line overflow */ 102238032Speter while (mci->mci_mailer->m_linelimit > 0 && 102338032Speter (p - l + slop) > mci->mci_mailer->m_linelimit) 102438032Speter { 102538032Speter char *l_base = l; 102638032Speter register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 102738032Speter 102838032Speter if (l[0] == '.' && slop == 0 && 102938032Speter bitnset(M_XDOT, mci->mci_mailer->m_flags)) 103038032Speter { 103164562Sgshapiro if (putc('.', mci->mci_out) == EOF) 103264562Sgshapiro dead = TRUE; 103371345Sgshapiro else 103471345Sgshapiro { 103571345Sgshapiro /* record progress for DATA timeout */ 103671345Sgshapiro DataProgress = TRUE; 103771345Sgshapiro } 103838032Speter if (TrafficLogFile != NULL) 103938032Speter (void) putc('.', TrafficLogFile); 104038032Speter } 104138032Speter else if (l[0] == 'F' && slop == 0 && 104238032Speter bitset(PXLF_MAPFROM, pxflags) && 104338032Speter strncmp(l, "From ", 5) == 0 && 104438032Speter bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 104538032Speter { 104664562Sgshapiro if (putc('>', mci->mci_out) == EOF) 104764562Sgshapiro dead = TRUE; 104871345Sgshapiro else 104971345Sgshapiro { 105071345Sgshapiro /* record progress for DATA timeout */ 105171345Sgshapiro DataProgress = TRUE; 105271345Sgshapiro } 105338032Speter if (TrafficLogFile != NULL) 105438032Speter (void) putc('>', TrafficLogFile); 105538032Speter } 105664562Sgshapiro if (dead) 105764562Sgshapiro break; 105864562Sgshapiro 105938032Speter while (l < q) 106038032Speter { 106164562Sgshapiro if (putc((unsigned char) *l++, mci->mci_out) == 106264562Sgshapiro EOF) 106364562Sgshapiro { 106464562Sgshapiro dead = TRUE; 106564562Sgshapiro break; 106664562Sgshapiro } 106771345Sgshapiro else 106871345Sgshapiro { 106971345Sgshapiro /* record progress for DATA timeout */ 107071345Sgshapiro DataProgress = TRUE; 107171345Sgshapiro } 107238032Speter } 107364562Sgshapiro if (dead) 107464562Sgshapiro break; 107564562Sgshapiro 107664562Sgshapiro if (putc('!', mci->mci_out) == EOF || 107764562Sgshapiro fputs(mci->mci_mailer->m_eol, 107864562Sgshapiro mci->mci_out) == EOF || 107964562Sgshapiro putc(' ', mci->mci_out) == EOF) 108064562Sgshapiro { 108164562Sgshapiro dead = TRUE; 108264562Sgshapiro break; 108364562Sgshapiro } 108471345Sgshapiro else 108571345Sgshapiro { 108671345Sgshapiro /* record progress for DATA timeout */ 108771345Sgshapiro DataProgress = TRUE; 108871345Sgshapiro } 108938032Speter if (TrafficLogFile != NULL) 109038032Speter { 109138032Speter for (l = l_base; l < q; l++) 109264562Sgshapiro (void) putc((unsigned char)*l, 109364562Sgshapiro TrafficLogFile); 109438032Speter fprintf(TrafficLogFile, "!\n%05d >>> ", 109538032Speter (int) getpid()); 109638032Speter } 109738032Speter slop = 1; 109838032Speter } 109938032Speter 110064562Sgshapiro if (dead) 110164562Sgshapiro break; 110264562Sgshapiro 110338032Speter /* output last part */ 110438032Speter if (l[0] == '.' && slop == 0 && 110538032Speter bitnset(M_XDOT, mci->mci_mailer->m_flags)) 110638032Speter { 110764562Sgshapiro if (putc('.', mci->mci_out) == EOF) 110864562Sgshapiro break; 110971345Sgshapiro else 111071345Sgshapiro { 111171345Sgshapiro /* record progress for DATA timeout */ 111271345Sgshapiro DataProgress = TRUE; 111371345Sgshapiro } 111438032Speter if (TrafficLogFile != NULL) 111538032Speter (void) putc('.', TrafficLogFile); 111638032Speter } 111738032Speter else if (l[0] == 'F' && slop == 0 && 111838032Speter bitset(PXLF_MAPFROM, pxflags) && 111938032Speter strncmp(l, "From ", 5) == 0 && 112038032Speter bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 112138032Speter { 112264562Sgshapiro if (putc('>', mci->mci_out) == EOF) 112364562Sgshapiro break; 112471345Sgshapiro else 112571345Sgshapiro { 112671345Sgshapiro /* record progress for DATA timeout */ 112771345Sgshapiro DataProgress = TRUE; 112871345Sgshapiro } 112938032Speter if (TrafficLogFile != NULL) 113038032Speter (void) putc('>', TrafficLogFile); 113138032Speter } 113238032Speter for ( ; l < p; ++l) 113338032Speter { 113438032Speter if (TrafficLogFile != NULL) 113564562Sgshapiro (void) putc((unsigned char)*l, TrafficLogFile); 113664562Sgshapiro if (putc((unsigned char) *l, mci->mci_out) == EOF) 113764562Sgshapiro { 113864562Sgshapiro dead = TRUE; 113964562Sgshapiro break; 114064562Sgshapiro } 114171345Sgshapiro else 114271345Sgshapiro { 114371345Sgshapiro /* record progress for DATA timeout */ 114471345Sgshapiro DataProgress = TRUE; 114571345Sgshapiro } 114638032Speter } 114764562Sgshapiro if (dead) 114864562Sgshapiro break; 114964562Sgshapiro 115038032Speter if (TrafficLogFile != NULL) 115138032Speter (void) putc('\n', TrafficLogFile); 115264562Sgshapiro if (fputs(mci->mci_mailer->m_eol, mci->mci_out) == EOF) 115364562Sgshapiro break; 115471345Sgshapiro else 115571345Sgshapiro { 115671345Sgshapiro /* record progress for DATA timeout */ 115771345Sgshapiro DataProgress = TRUE; 115871345Sgshapiro } 115938032Speter if (l < end && *l == '\n') 116038032Speter { 116138032Speter if (*++l != ' ' && *l != '\t' && *l != '\0' && 116238032Speter bitset(PXLF_HEADER, pxflags)) 116338032Speter { 116464562Sgshapiro if (putc(' ', mci->mci_out) == EOF) 116564562Sgshapiro break; 116671345Sgshapiro else 116771345Sgshapiro { 116871345Sgshapiro /* record progress for DATA timeout */ 116971345Sgshapiro DataProgress = TRUE; 117071345Sgshapiro } 117138032Speter if (TrafficLogFile != NULL) 117238032Speter (void) putc(' ', TrafficLogFile); 117338032Speter } 117438032Speter } 117538032Speter } while (l < end); 117638032Speter} 117738032Speter/* 117838032Speter** XUNLINK -- unlink a file, doing logging as appropriate. 117938032Speter** 118038032Speter** Parameters: 118138032Speter** f -- name of file to unlink. 118238032Speter** 118338032Speter** Returns: 118438032Speter** none. 118538032Speter** 118638032Speter** Side Effects: 118738032Speter** f is unlinked. 118838032Speter*/ 118938032Speter 119038032Spetervoid 119138032Speterxunlink(f) 119238032Speter char *f; 119338032Speter{ 119438032Speter register int i; 119538032Speter 119638032Speter if (LogLevel > 98) 119738032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 119864562Sgshapiro "unlink %s", 119964562Sgshapiro f); 120038032Speter 120138032Speter i = unlink(f); 120238032Speter if (i < 0 && LogLevel > 97) 120338032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 120464562Sgshapiro "%s: unlink-fail %d", 120564562Sgshapiro f, errno); 120638032Speter} 120738032Speter/* 120838032Speter** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 120938032Speter** 121038032Speter** Parameters: 121138032Speter** buf -- place to put the input line. 121238032Speter** siz -- size of buf. 121338032Speter** fp -- file to read from. 121438032Speter** timeout -- the timeout before error occurs. 121538032Speter** during -- what we are trying to read (for error messages). 121638032Speter** 121738032Speter** Returns: 121838032Speter** NULL on error (including timeout). This will also leave 121938032Speter** buf containing a null string. 122038032Speter** buf otherwise. 122138032Speter** 122238032Speter** Side Effects: 122338032Speter** none. 122438032Speter*/ 122538032Speter 122664562Sgshapiro 122738032Speterstatic jmp_buf CtxReadTimeout; 122838032Speter 122938032Speterchar * 123038032Spetersfgets(buf, siz, fp, timeout, during) 123138032Speter char *buf; 123238032Speter int siz; 123338032Speter FILE *fp; 123438032Speter time_t timeout; 123538032Speter char *during; 123638032Speter{ 123738032Speter register EVENT *ev = NULL; 123838032Speter register char *p; 123943730Speter int save_errno; 124038032Speter 124138032Speter if (fp == NULL) 124238032Speter { 124338032Speter buf[0] = '\0'; 124438032Speter return NULL; 124538032Speter } 124638032Speter 124738032Speter /* set the timeout */ 124838032Speter if (timeout != 0) 124938032Speter { 125038032Speter if (setjmp(CtxReadTimeout) != 0) 125138032Speter { 125238032Speter if (LogLevel > 1) 125338032Speter sm_syslog(LOG_NOTICE, CurEnv->e_id, 125464562Sgshapiro "timeout waiting for input from %.100s during %s", 125564562Sgshapiro CurHostName ? CurHostName : "local", 125664562Sgshapiro during); 125738032Speter buf[0] = '\0'; 125838032Speter#if XDEBUG 125938032Speter checkfd012(during); 126064562Sgshapiro#endif /* XDEBUG */ 126138032Speter if (TrafficLogFile != NULL) 126238032Speter fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n", 126338032Speter (int) getpid()); 126443730Speter errno = 0; 126564562Sgshapiro return NULL; 126638032Speter } 126738032Speter ev = setevent(timeout, readtimeout, 0); 126838032Speter } 126938032Speter 127038032Speter /* try to read */ 127138032Speter p = NULL; 127243730Speter errno = 0; 127338032Speter while (!feof(fp) && !ferror(fp)) 127438032Speter { 127538032Speter errno = 0; 127638032Speter p = fgets(buf, siz, fp); 127738032Speter if (p != NULL || errno != EINTR) 127838032Speter break; 127938032Speter clearerr(fp); 128038032Speter } 128143730Speter save_errno = errno; 128238032Speter 128338032Speter /* clear the event if it has not sprung */ 128438032Speter clrevent(ev); 128538032Speter 128638032Speter /* clean up the books and exit */ 128738032Speter LineNumber++; 128838032Speter if (p == NULL) 128938032Speter { 129038032Speter buf[0] = '\0'; 129138032Speter if (TrafficLogFile != NULL) 129238032Speter fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid()); 129343730Speter errno = save_errno; 129464562Sgshapiro return NULL; 129538032Speter } 129638032Speter if (TrafficLogFile != NULL) 129738032Speter fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf); 129838032Speter if (SevenBitInput) 129938032Speter { 130038032Speter for (p = buf; *p != '\0'; p++) 130138032Speter *p &= ~0200; 130238032Speter } 130338032Speter else if (!HasEightBits) 130438032Speter { 130538032Speter for (p = buf; *p != '\0'; p++) 130638032Speter { 130738032Speter if (bitset(0200, *p)) 130838032Speter { 130938032Speter HasEightBits = TRUE; 131038032Speter break; 131138032Speter } 131238032Speter } 131338032Speter } 131464562Sgshapiro return buf; 131538032Speter} 131638032Speter 131738032Speter/* ARGSUSED */ 131838032Speterstatic void 131938032Speterreadtimeout(timeout) 132038032Speter time_t timeout; 132138032Speter{ 132277349Sgshapiro /* 132377349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 132477349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 132577349Sgshapiro ** DOING. 132677349Sgshapiro */ 132777349Sgshapiro 132877349Sgshapiro errno = ETIMEDOUT; 132938032Speter longjmp(CtxReadTimeout, 1); 133038032Speter} 133138032Speter/* 133238032Speter** FGETFOLDED -- like fgets, but know about folded lines. 133338032Speter** 133438032Speter** Parameters: 133538032Speter** buf -- place to put result. 133638032Speter** n -- bytes available. 133738032Speter** f -- file to read from. 133838032Speter** 133938032Speter** Returns: 134038032Speter** input line(s) on success, NULL on error or EOF. 134138032Speter** This will normally be buf -- unless the line is too 134238032Speter** long, when it will be xalloc()ed. 134338032Speter** 134438032Speter** Side Effects: 134538032Speter** buf gets lines from f, with continuation lines (lines 134638032Speter** with leading white space) appended. CRLF's are mapped 134738032Speter** into single newlines. Any trailing NL is stripped. 134838032Speter*/ 134938032Speter 135038032Speterchar * 135138032Speterfgetfolded(buf, n, f) 135238032Speter char *buf; 135338032Speter register int n; 135438032Speter FILE *f; 135538032Speter{ 135638032Speter register char *p = buf; 135738032Speter char *bp = buf; 135838032Speter register int i; 135938032Speter 136038032Speter n--; 136138032Speter while ((i = getc(f)) != EOF) 136238032Speter { 136338032Speter if (i == '\r') 136438032Speter { 136538032Speter i = getc(f); 136638032Speter if (i != '\n') 136738032Speter { 136838032Speter if (i != EOF) 136938032Speter (void) ungetc(i, f); 137038032Speter i = '\r'; 137138032Speter } 137238032Speter } 137338032Speter if (--n <= 0) 137438032Speter { 137538032Speter /* allocate new space */ 137638032Speter char *nbp; 137738032Speter int nn; 137838032Speter 137938032Speter nn = (p - bp); 138038032Speter if (nn < MEMCHUNKSIZE) 138138032Speter nn *= 2; 138238032Speter else 138338032Speter nn += MEMCHUNKSIZE; 138438032Speter nbp = xalloc(nn); 138564562Sgshapiro memmove(nbp, bp, p - bp); 138638032Speter p = &nbp[p - bp]; 138738032Speter if (bp != buf) 138877349Sgshapiro sm_free(bp); 138938032Speter bp = nbp; 139038032Speter n = nn - (p - bp); 139138032Speter } 139238032Speter *p++ = i; 139338032Speter if (i == '\n') 139438032Speter { 139538032Speter LineNumber++; 139638032Speter i = getc(f); 139738032Speter if (i != EOF) 139838032Speter (void) ungetc(i, f); 139938032Speter if (i != ' ' && i != '\t') 140038032Speter break; 140138032Speter } 140238032Speter } 140338032Speter if (p == bp) 140464562Sgshapiro return NULL; 140538032Speter if (p[-1] == '\n') 140638032Speter p--; 140738032Speter *p = '\0'; 140864562Sgshapiro return bp; 140938032Speter} 141038032Speter/* 141138032Speter** CURTIME -- return current time. 141238032Speter** 141338032Speter** Parameters: 141438032Speter** none. 141538032Speter** 141638032Speter** Returns: 141738032Speter** the current time. 141838032Speter** 141938032Speter** Side Effects: 142038032Speter** none. 142138032Speter*/ 142238032Speter 142338032Spetertime_t 142438032Spetercurtime() 142538032Speter{ 142638032Speter auto time_t t; 142738032Speter 142838032Speter (void) time(&t); 142964562Sgshapiro return t; 143038032Speter} 143138032Speter/* 143238032Speter** ATOBOOL -- convert a string representation to boolean. 143338032Speter** 143438032Speter** Defaults to "TRUE" 143538032Speter** 143638032Speter** Parameters: 143738032Speter** s -- string to convert. Takes "tTyY" as true, 143838032Speter** others as false. 143938032Speter** 144038032Speter** Returns: 144138032Speter** A boolean representation of the string. 144238032Speter** 144338032Speter** Side Effects: 144438032Speter** none. 144538032Speter*/ 144638032Speter 144738032Speterbool 144838032Speteratobool(s) 144938032Speter register char *s; 145038032Speter{ 145138032Speter if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 145264562Sgshapiro return TRUE; 145364562Sgshapiro return FALSE; 145438032Speter} 145538032Speter/* 145638032Speter** ATOOCT -- convert a string representation to octal. 145738032Speter** 145838032Speter** Parameters: 145938032Speter** s -- string to convert. 146038032Speter** 146138032Speter** Returns: 146238032Speter** An integer representing the string interpreted as an 146338032Speter** octal number. 146438032Speter** 146538032Speter** Side Effects: 146638032Speter** none. 146738032Speter*/ 146838032Speter 146938032Speterint 147038032Speteratooct(s) 147138032Speter register char *s; 147238032Speter{ 147338032Speter register int i = 0; 147438032Speter 147538032Speter while (*s >= '0' && *s <= '7') 147638032Speter i = (i << 3) | (*s++ - '0'); 147764562Sgshapiro return i; 147838032Speter} 147938032Speter/* 148038032Speter** BITINTERSECT -- tell if two bitmaps intersect 148138032Speter** 148238032Speter** Parameters: 148338032Speter** a, b -- the bitmaps in question 148438032Speter** 148538032Speter** Returns: 148638032Speter** TRUE if they have a non-null intersection 148738032Speter** FALSE otherwise 148838032Speter** 148938032Speter** Side Effects: 149038032Speter** none. 149138032Speter*/ 149238032Speter 149338032Speterbool 149438032Speterbitintersect(a, b) 149564562Sgshapiro BITMAP256 a; 149664562Sgshapiro BITMAP256 b; 149738032Speter{ 149838032Speter int i; 149938032Speter 150038032Speter for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 150171345Sgshapiro { 150238032Speter if ((a[i] & b[i]) != 0) 150364562Sgshapiro return TRUE; 150471345Sgshapiro } 150564562Sgshapiro return FALSE; 150638032Speter} 150738032Speter/* 150838032Speter** BITZEROP -- tell if a bitmap is all zero 150938032Speter** 151038032Speter** Parameters: 151138032Speter** map -- the bit map to check 151238032Speter** 151338032Speter** Returns: 151438032Speter** TRUE if map is all zero. 151538032Speter** FALSE if there are any bits set in map. 151638032Speter** 151738032Speter** Side Effects: 151838032Speter** none. 151938032Speter*/ 152038032Speter 152138032Speterbool 152238032Speterbitzerop(map) 152364562Sgshapiro BITMAP256 map; 152438032Speter{ 152538032Speter int i; 152638032Speter 152738032Speter for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 152871345Sgshapiro { 152938032Speter if (map[i] != 0) 153064562Sgshapiro return FALSE; 153171345Sgshapiro } 153264562Sgshapiro return TRUE; 153338032Speter} 153438032Speter/* 153538032Speter** STRCONTAINEDIN -- tell if one string is contained in another 153638032Speter** 153738032Speter** Parameters: 153838032Speter** a -- possible substring. 153938032Speter** b -- possible superstring. 154038032Speter** 154138032Speter** Returns: 154238032Speter** TRUE if a is contained in b. 154338032Speter** FALSE otherwise. 154438032Speter*/ 154538032Speter 154638032Speterbool 154738032Speterstrcontainedin(a, b) 154838032Speter register char *a; 154938032Speter register char *b; 155038032Speter{ 155138032Speter int la; 155238032Speter int lb; 155338032Speter int c; 155438032Speter 155538032Speter la = strlen(a); 155638032Speter lb = strlen(b); 155738032Speter c = *a; 155838032Speter if (isascii(c) && isupper(c)) 155938032Speter c = tolower(c); 156038032Speter for (; lb-- >= la; b++) 156138032Speter { 156238032Speter if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) 156338032Speter continue; 156438032Speter if (strncasecmp(a, b, la) == 0) 156538032Speter return TRUE; 156638032Speter } 156738032Speter return FALSE; 156838032Speter} 156938032Speter/* 157038032Speter** CHECKFD012 -- check low numbered file descriptors 157138032Speter** 157238032Speter** File descriptors 0, 1, and 2 should be open at all times. 157338032Speter** This routine verifies that, and fixes it if not true. 157438032Speter** 157538032Speter** Parameters: 157638032Speter** where -- a tag printed if the assertion failed 157738032Speter** 157838032Speter** Returns: 157938032Speter** none 158038032Speter*/ 158138032Speter 158238032Spetervoid 158338032Spetercheckfd012(where) 158438032Speter char *where; 158538032Speter{ 158638032Speter#if XDEBUG 158738032Speter register int i; 158838032Speter 158938032Speter for (i = 0; i < 3; i++) 159038032Speter fill_fd(i, where); 159138032Speter#endif /* XDEBUG */ 159238032Speter} 159338032Speter/* 159438032Speter** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging 159538032Speter** 159638032Speter** Parameters: 159738032Speter** fd -- file descriptor to check. 159838032Speter** where -- tag to print on failure. 159938032Speter** 160038032Speter** Returns: 160138032Speter** none. 160238032Speter*/ 160338032Speter 160438032Spetervoid 160538032Spetercheckfdopen(fd, where) 160638032Speter int fd; 160738032Speter char *where; 160838032Speter{ 160938032Speter#if XDEBUG 161038032Speter struct stat st; 161138032Speter 161238032Speter if (fstat(fd, &st) < 0 && errno == EBADF) 161338032Speter { 161438032Speter syserr("checkfdopen(%d): %s not open as expected!", fd, where); 161538032Speter printopenfds(TRUE); 161638032Speter } 161764562Sgshapiro#endif /* XDEBUG */ 161838032Speter} 161938032Speter/* 162038032Speter** CHECKFDS -- check for new or missing file descriptors 162138032Speter** 162238032Speter** Parameters: 162338032Speter** where -- tag for printing. If null, take a base line. 162438032Speter** 162538032Speter** Returns: 162638032Speter** none 162738032Speter** 162838032Speter** Side Effects: 162938032Speter** If where is set, shows changes since the last call. 163038032Speter*/ 163138032Speter 163238032Spetervoid 163338032Spetercheckfds(where) 163438032Speter char *where; 163538032Speter{ 163638032Speter int maxfd; 163738032Speter register int fd; 163838032Speter bool printhdr = TRUE; 163938032Speter int save_errno = errno; 164064562Sgshapiro static BITMAP256 baseline; 164138032Speter extern int DtableSize; 164238032Speter 164371345Sgshapiro if (DtableSize > BITMAPBITS) 164471345Sgshapiro maxfd = BITMAPBITS; 164538032Speter else 164638032Speter maxfd = DtableSize; 164738032Speter if (where == NULL) 164838032Speter clrbitmap(baseline); 164938032Speter 165038032Speter for (fd = 0; fd < maxfd; fd++) 165138032Speter { 165238032Speter struct stat stbuf; 165338032Speter 165438032Speter if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) 165538032Speter { 165638032Speter if (!bitnset(fd, baseline)) 165738032Speter continue; 165838032Speter clrbitn(fd, baseline); 165938032Speter } 166038032Speter else if (!bitnset(fd, baseline)) 166138032Speter setbitn(fd, baseline); 166238032Speter else 166338032Speter continue; 166438032Speter 166538032Speter /* file state has changed */ 166638032Speter if (where == NULL) 166738032Speter continue; 166838032Speter if (printhdr) 166938032Speter { 167038032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 167164562Sgshapiro "%s: changed fds:", 167264562Sgshapiro where); 167338032Speter printhdr = FALSE; 167438032Speter } 167538032Speter dumpfd(fd, TRUE, TRUE); 167638032Speter } 167738032Speter errno = save_errno; 167838032Speter} 167938032Speter/* 168038032Speter** PRINTOPENFDS -- print the open file descriptors (for debugging) 168138032Speter** 168238032Speter** Parameters: 168338032Speter** logit -- if set, send output to syslog; otherwise 168438032Speter** print for debugging. 168538032Speter** 168638032Speter** Returns: 168738032Speter** none. 168838032Speter*/ 168938032Speter 169064562Sgshapiro#if NETINET || NETINET6 169164562Sgshapiro# include <arpa/inet.h> 169264562Sgshapiro#endif /* NETINET || NETINET6 */ 169338032Speter 169438032Spetervoid 169538032Speterprintopenfds(logit) 169638032Speter bool logit; 169738032Speter{ 169838032Speter register int fd; 169938032Speter extern int DtableSize; 170038032Speter 170138032Speter for (fd = 0; fd < DtableSize; fd++) 170238032Speter dumpfd(fd, FALSE, logit); 170338032Speter} 170438032Speter/* 170538032Speter** DUMPFD -- dump a file descriptor 170638032Speter** 170738032Speter** Parameters: 170838032Speter** fd -- the file descriptor to dump. 170938032Speter** printclosed -- if set, print a notification even if 171038032Speter** it is closed; otherwise print nothing. 171138032Speter** logit -- if set, send output to syslog instead of stdout. 171238032Speter*/ 171338032Speter 171438032Spetervoid 171538032Speterdumpfd(fd, printclosed, logit) 171638032Speter int fd; 171738032Speter bool printclosed; 171838032Speter bool logit; 171938032Speter{ 172038032Speter register char *p; 172138032Speter char *hp; 172238032Speter#ifdef S_IFSOCK 172338032Speter SOCKADDR sa; 172464562Sgshapiro#endif /* S_IFSOCK */ 172538032Speter auto SOCKADDR_LEN_T slen; 172638032Speter int i; 172738032Speter#if STAT64 > 0 172838032Speter struct stat64 st; 172964562Sgshapiro#else /* STAT64 > 0 */ 173038032Speter struct stat st; 173164562Sgshapiro#endif /* STAT64 > 0 */ 173238032Speter char buf[200]; 173338032Speter 173438032Speter p = buf; 173538032Speter snprintf(p, SPACELEFT(buf, p), "%3d: ", fd); 173638032Speter p += strlen(p); 173738032Speter 173838032Speter if ( 173938032Speter#if STAT64 > 0 174038032Speter fstat64(fd, &st) 174164562Sgshapiro#else /* STAT64 > 0 */ 174238032Speter fstat(fd, &st) 174364562Sgshapiro#endif /* STAT64 > 0 */ 174438032Speter < 0) 174538032Speter { 174638032Speter if (errno != EBADF) 174738032Speter { 174838032Speter snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)", 174938032Speter errstring(errno)); 175038032Speter goto printit; 175138032Speter } 175238032Speter else if (printclosed) 175338032Speter { 175438032Speter snprintf(p, SPACELEFT(buf, p), "CLOSED"); 175538032Speter goto printit; 175638032Speter } 175738032Speter return; 175838032Speter } 175938032Speter 176038032Speter i = fcntl(fd, F_GETFL, NULL); 176138032Speter if (i != -1) 176238032Speter { 176338032Speter snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i); 176438032Speter p += strlen(p); 176538032Speter } 176638032Speter 176764562Sgshapiro snprintf(p, SPACELEFT(buf, p), "mode=%o: ", (int) st.st_mode); 176838032Speter p += strlen(p); 176938032Speter switch (st.st_mode & S_IFMT) 177038032Speter { 177138032Speter#ifdef S_IFSOCK 177238032Speter case S_IFSOCK: 177338032Speter snprintf(p, SPACELEFT(buf, p), "SOCK "); 177438032Speter p += strlen(p); 177564562Sgshapiro memset(&sa, '\0', sizeof sa); 177638032Speter slen = sizeof sa; 177738032Speter if (getsockname(fd, &sa.sa, &slen) < 0) 177864562Sgshapiro snprintf(p, SPACELEFT(buf, p), "(%s)", 177964562Sgshapiro errstring(errno)); 178038032Speter else 178138032Speter { 178238032Speter hp = hostnamebyanyaddr(&sa); 178364562Sgshapiro if (hp == NULL) 178464562Sgshapiro { 178564562Sgshapiro /* EMPTY */ 178664562Sgshapiro /* do nothing */ 178764562Sgshapiro } 178864562Sgshapiro# if NETINET 178964562Sgshapiro else if (sa.sa.sa_family == AF_INET) 179038032Speter snprintf(p, SPACELEFT(buf, p), "%s/%d", 179164562Sgshapiro hp, ntohs(sa.sin.sin_port)); 179264562Sgshapiro# endif /* NETINET */ 179364562Sgshapiro# if NETINET6 179464562Sgshapiro else if (sa.sa.sa_family == AF_INET6) 179564562Sgshapiro snprintf(p, SPACELEFT(buf, p), "%s/%d", 179664562Sgshapiro hp, ntohs(sa.sin6.sin6_port)); 179764562Sgshapiro# endif /* NETINET6 */ 179838032Speter else 179938032Speter snprintf(p, SPACELEFT(buf, p), "%s", hp); 180038032Speter } 180138032Speter p += strlen(p); 180238032Speter snprintf(p, SPACELEFT(buf, p), "->"); 180338032Speter p += strlen(p); 180438032Speter slen = sizeof sa; 180538032Speter if (getpeername(fd, &sa.sa, &slen) < 0) 180638032Speter snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno)); 180738032Speter else 180838032Speter { 180938032Speter hp = hostnamebyanyaddr(&sa); 181064562Sgshapiro if (hp == NULL) 181164562Sgshapiro { 181264562Sgshapiro /* EMPTY */ 181364562Sgshapiro /* do nothing */ 181464562Sgshapiro } 181564562Sgshapiro# if NETINET 181664562Sgshapiro else if (sa.sa.sa_family == AF_INET) 181738032Speter snprintf(p, SPACELEFT(buf, p), "%s/%d", 181864562Sgshapiro hp, ntohs(sa.sin.sin_port)); 181964562Sgshapiro# endif /* NETINET */ 182064562Sgshapiro# if NETINET6 182164562Sgshapiro else if (sa.sa.sa_family == AF_INET6) 182264562Sgshapiro snprintf(p, SPACELEFT(buf, p), "%s/%d", 182364562Sgshapiro hp, ntohs(sa.sin6.sin6_port)); 182464562Sgshapiro# endif /* NETINET6 */ 182538032Speter else 182638032Speter snprintf(p, SPACELEFT(buf, p), "%s", hp); 182738032Speter } 182838032Speter break; 182964562Sgshapiro#endif /* S_IFSOCK */ 183038032Speter 183138032Speter case S_IFCHR: 183238032Speter snprintf(p, SPACELEFT(buf, p), "CHR: "); 183338032Speter p += strlen(p); 183438032Speter goto defprint; 183538032Speter 183638032Speter case S_IFBLK: 183738032Speter snprintf(p, SPACELEFT(buf, p), "BLK: "); 183838032Speter p += strlen(p); 183938032Speter goto defprint; 184038032Speter 184138032Speter#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 184238032Speter case S_IFIFO: 184338032Speter snprintf(p, SPACELEFT(buf, p), "FIFO: "); 184438032Speter p += strlen(p); 184538032Speter goto defprint; 184664562Sgshapiro#endif /* defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) */ 184738032Speter 184838032Speter#ifdef S_IFDIR 184938032Speter case S_IFDIR: 185038032Speter snprintf(p, SPACELEFT(buf, p), "DIR: "); 185138032Speter p += strlen(p); 185238032Speter goto defprint; 185364562Sgshapiro#endif /* S_IFDIR */ 185438032Speter 185538032Speter#ifdef S_IFLNK 185638032Speter case S_IFLNK: 185738032Speter snprintf(p, SPACELEFT(buf, p), "LNK: "); 185838032Speter p += strlen(p); 185938032Speter goto defprint; 186064562Sgshapiro#endif /* S_IFLNK */ 186138032Speter 186238032Speter default: 186338032Speterdefprint: 186464562Sgshapiro /*CONSTCOND*/ 186538032Speter if (sizeof st.st_ino > sizeof (long)) 186638032Speter snprintf(p, SPACELEFT(buf, p), 186738032Speter "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ", 186838032Speter major(st.st_dev), minor(st.st_dev), 186938032Speter quad_to_string(st.st_ino), 187064562Sgshapiro (int) st.st_nlink, (int) st.st_uid, 187164562Sgshapiro (int) st.st_gid); 187238032Speter else 187338032Speter snprintf(p, SPACELEFT(buf, p), 187464562Sgshapiro "dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ", 187564562Sgshapiro major(st.st_dev), minor(st.st_dev), 187664562Sgshapiro (unsigned long) st.st_ino, 187764562Sgshapiro (int) st.st_nlink, (int) st.st_uid, 187864562Sgshapiro (int) st.st_gid); 187964562Sgshapiro /*CONSTCOND*/ 188038032Speter if (sizeof st.st_size > sizeof (long)) 188138032Speter snprintf(p, SPACELEFT(buf, p), "size=%s", 188238032Speter quad_to_string(st.st_size)); 188338032Speter else 188438032Speter snprintf(p, SPACELEFT(buf, p), "size=%lu", 188538032Speter (unsigned long) st.st_size); 188638032Speter break; 188738032Speter } 188838032Speter 188938032Speterprintit: 189038032Speter if (logit) 189138032Speter sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL, 189264562Sgshapiro "%.800s", buf); 189338032Speter else 189438032Speter printf("%s\n", buf); 189538032Speter} 189638032Speter/* 189738032Speter** SHORTEN_HOSTNAME -- strip local domain information off of hostname. 189838032Speter** 189938032Speter** Parameters: 190038032Speter** host -- the host to shorten (stripped in place). 190138032Speter** 190238032Speter** Returns: 190373188Sgshapiro** place where string was trunacted, NULL if not truncated. 190438032Speter*/ 190538032Speter 190673188Sgshapirochar * 190738032Spetershorten_hostname(host) 190838032Speter char host[]; 190938032Speter{ 191038032Speter register char *p; 191138032Speter char *mydom; 191238032Speter int i; 191338032Speter bool canon = FALSE; 191438032Speter 191538032Speter /* strip off final dot */ 191638032Speter p = &host[strlen(host) - 1]; 191738032Speter if (*p == '.') 191838032Speter { 191938032Speter *p = '\0'; 192038032Speter canon = TRUE; 192138032Speter } 192238032Speter 192338032Speter /* see if there is any domain at all -- if not, we are done */ 192438032Speter p = strchr(host, '.'); 192538032Speter if (p == NULL) 192673188Sgshapiro return NULL; 192738032Speter 192838032Speter /* yes, we have a domain -- see if it looks like us */ 192938032Speter mydom = macvalue('m', CurEnv); 193038032Speter if (mydom == NULL) 193138032Speter mydom = ""; 193238032Speter i = strlen(++p); 193338032Speter if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 && 193438032Speter (mydom[i] == '.' || mydom[i] == '\0')) 193573188Sgshapiro { 193638032Speter *--p = '\0'; 193773188Sgshapiro return p; 193873188Sgshapiro } 193973188Sgshapiro return NULL; 194038032Speter} 194138032Speter/* 194238032Speter** PROG_OPEN -- open a program for reading 194338032Speter** 194438032Speter** Parameters: 194538032Speter** argv -- the argument list. 194638032Speter** pfd -- pointer to a place to store the file descriptor. 194738032Speter** e -- the current envelope. 194838032Speter** 194938032Speter** Returns: 195038032Speter** pid of the process -- -1 if it failed. 195138032Speter*/ 195238032Speter 195377349Sgshapiropid_t 195438032Speterprog_open(argv, pfd, e) 195538032Speter char **argv; 195638032Speter int *pfd; 195738032Speter ENVELOPE *e; 195838032Speter{ 195977349Sgshapiro pid_t pid; 196038032Speter int i; 196164562Sgshapiro int save_errno; 196238032Speter int fdv[2]; 196338032Speter char *p, *q; 196438032Speter char buf[MAXLINE + 1]; 196538032Speter extern int DtableSize; 196638032Speter 196738032Speter if (pipe(fdv) < 0) 196838032Speter { 196938032Speter syserr("%s: cannot create pipe for stdout", argv[0]); 197038032Speter return -1; 197138032Speter } 197238032Speter pid = fork(); 197338032Speter if (pid < 0) 197438032Speter { 197538032Speter syserr("%s: cannot fork", argv[0]); 197664562Sgshapiro (void) close(fdv[0]); 197764562Sgshapiro (void) close(fdv[1]); 197838032Speter return -1; 197938032Speter } 198038032Speter if (pid > 0) 198138032Speter { 198238032Speter /* parent */ 198364562Sgshapiro (void) close(fdv[1]); 198438032Speter *pfd = fdv[0]; 198538032Speter return pid; 198638032Speter } 198738032Speter 198838032Speter /* child -- close stdin */ 198964562Sgshapiro (void) close(0); 199038032Speter 199177349Sgshapiro /* Reset global flags */ 199277349Sgshapiro RestartRequest = NULL; 199377349Sgshapiro ShutdownRequest = NULL; 199477349Sgshapiro PendingSignal = 0; 199577349Sgshapiro 199638032Speter /* stdout goes back to parent */ 199764562Sgshapiro (void) close(fdv[0]); 199838032Speter if (dup2(fdv[1], 1) < 0) 199938032Speter { 200038032Speter syserr("%s: cannot dup2 for stdout", argv[0]); 200138032Speter _exit(EX_OSERR); 200238032Speter } 200364562Sgshapiro (void) close(fdv[1]); 200438032Speter 200538032Speter /* stderr goes to transcript if available */ 200638032Speter if (e->e_xfp != NULL) 200738032Speter { 200864562Sgshapiro int xfd; 200964562Sgshapiro 201064562Sgshapiro xfd = fileno(e->e_xfp); 201164562Sgshapiro if (xfd >= 0 && dup2(xfd, 2) < 0) 201238032Speter { 201338032Speter syserr("%s: cannot dup2 for stderr", argv[0]); 201438032Speter _exit(EX_OSERR); 201538032Speter } 201638032Speter } 201738032Speter 201838032Speter /* this process has no right to the queue file */ 201938032Speter if (e->e_lockfp != NULL) 202064562Sgshapiro (void) close(fileno(e->e_lockfp)); 202138032Speter 202264562Sgshapiro /* chroot to the program mailer directory, if defined */ 202364562Sgshapiro if (ProgMailer != NULL && ProgMailer->m_rootdir != NULL) 202464562Sgshapiro { 202564562Sgshapiro expand(ProgMailer->m_rootdir, buf, sizeof buf, e); 202664562Sgshapiro if (chroot(buf) < 0) 202764562Sgshapiro { 202864562Sgshapiro syserr("prog_open: cannot chroot(%s)", buf); 202964562Sgshapiro exit(EX_TEMPFAIL); 203064562Sgshapiro } 203164562Sgshapiro if (chdir("/") < 0) 203264562Sgshapiro { 203364562Sgshapiro syserr("prog_open: cannot chdir(/)"); 203464562Sgshapiro exit(EX_TEMPFAIL); 203564562Sgshapiro } 203664562Sgshapiro } 203764562Sgshapiro 203838032Speter /* run as default user */ 203938032Speter endpwent(); 204038032Speter if (setgid(DefGid) < 0 && geteuid() == 0) 204164562Sgshapiro { 204238032Speter syserr("prog_open: setgid(%ld) failed", (long) DefGid); 204364562Sgshapiro exit(EX_TEMPFAIL); 204464562Sgshapiro } 204538032Speter if (setuid(DefUid) < 0 && geteuid() == 0) 204664562Sgshapiro { 204738032Speter syserr("prog_open: setuid(%ld) failed", (long) DefUid); 204864562Sgshapiro exit(EX_TEMPFAIL); 204964562Sgshapiro } 205038032Speter 205138032Speter /* run in some directory */ 205238032Speter if (ProgMailer != NULL) 205338032Speter p = ProgMailer->m_execdir; 205438032Speter else 205538032Speter p = NULL; 205638032Speter for (; p != NULL; p = q) 205738032Speter { 205838032Speter q = strchr(p, ':'); 205938032Speter if (q != NULL) 206038032Speter *q = '\0'; 206138032Speter expand(p, buf, sizeof buf, e); 206238032Speter if (q != NULL) 206338032Speter *q++ = ':'; 206438032Speter if (buf[0] != '\0' && chdir(buf) >= 0) 206538032Speter break; 206638032Speter } 206738032Speter if (p == NULL) 206838032Speter { 206938032Speter /* backup directories */ 207038032Speter if (chdir("/tmp") < 0) 207138032Speter (void) chdir("/"); 207238032Speter } 207338032Speter 207438032Speter /* arrange for all the files to be closed */ 207538032Speter for (i = 3; i < DtableSize; i++) 207638032Speter { 207738032Speter register int j; 207838032Speter 207938032Speter if ((j = fcntl(i, F_GETFD, 0)) != -1) 208064562Sgshapiro (void) fcntl(i, F_SETFD, j | FD_CLOEXEC); 208138032Speter } 208238032Speter 208338032Speter /* now exec the process */ 208464562Sgshapiro (void) execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron); 208538032Speter 208638032Speter /* woops! failed */ 208764562Sgshapiro save_errno = errno; 208838032Speter syserr("%s: cannot exec", argv[0]); 208964562Sgshapiro if (transienterror(save_errno)) 209038032Speter _exit(EX_OSERR); 209138032Speter _exit(EX_CONFIG); 209238032Speter return -1; /* avoid compiler warning on IRIX */ 209338032Speter} 209438032Speter/* 209564562Sgshapiro** GET_COLUMN -- look up a Column in a line buffer 209638032Speter** 209738032Speter** Parameters: 209838032Speter** line -- the raw text line to search. 209938032Speter** col -- the column number to fetch. 210038032Speter** delim -- the delimiter between columns. If null, 210138032Speter** use white space. 210238032Speter** buf -- the output buffer. 210338032Speter** buflen -- the length of buf. 210438032Speter** 210538032Speter** Returns: 210638032Speter** buf if successful. 210738032Speter** NULL otherwise. 210838032Speter*/ 210938032Speter 211038032Speterchar * 211138032Speterget_column(line, col, delim, buf, buflen) 211238032Speter char line[]; 211338032Speter int col; 211464562Sgshapiro int delim; 211538032Speter char buf[]; 211638032Speter int buflen; 211738032Speter{ 211838032Speter char *p; 211938032Speter char *begin, *end; 212038032Speter int i; 212138032Speter char delimbuf[4]; 212264562Sgshapiro 212364562Sgshapiro if ((char)delim == '\0') 212464562Sgshapiro (void) strlcpy(delimbuf, "\n\t ", sizeof delimbuf); 212538032Speter else 212638032Speter { 212764562Sgshapiro delimbuf[0] = (char)delim; 212838032Speter delimbuf[1] = '\0'; 212938032Speter } 213038032Speter 213138032Speter p = line; 213238032Speter if (*p == '\0') 213338032Speter return NULL; /* line empty */ 213464562Sgshapiro if (*p == (char)delim && col == 0) 213538032Speter return NULL; /* first column empty */ 213638032Speter 213738032Speter begin = line; 213838032Speter 213964562Sgshapiro if (col == 0 && (char)delim == '\0') 214038032Speter { 214138032Speter while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 214238032Speter begin++; 214338032Speter } 214438032Speter 214538032Speter for (i = 0; i < col; i++) 214638032Speter { 214738032Speter if ((begin = strpbrk(begin, delimbuf)) == NULL) 214838032Speter return NULL; /* no such column */ 214938032Speter begin++; 215064562Sgshapiro if ((char)delim == '\0') 215138032Speter { 215238032Speter while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 215338032Speter begin++; 215438032Speter } 215538032Speter } 215664562Sgshapiro 215738032Speter end = strpbrk(begin, delimbuf); 215838032Speter if (end == NULL) 215938032Speter i = strlen(begin); 216038032Speter else 216138032Speter i = end - begin; 216238032Speter if (i >= buflen) 216338032Speter i = buflen - 1; 216464562Sgshapiro (void) strlcpy(buf, begin, i + 1); 216538032Speter return buf; 216638032Speter} 216738032Speter/* 216838032Speter** CLEANSTRCPY -- copy string keeping out bogus characters 216938032Speter** 217038032Speter** Parameters: 217138032Speter** t -- "to" string. 217238032Speter** f -- "from" string. 217338032Speter** l -- length of space available in "to" string. 217438032Speter** 217538032Speter** Returns: 217638032Speter** none. 217738032Speter*/ 217838032Speter 217938032Spetervoid 218038032Spetercleanstrcpy(t, f, l) 218138032Speter register char *t; 218238032Speter register char *f; 218338032Speter int l; 218438032Speter{ 218538032Speter /* check for newlines and log if necessary */ 218638032Speter (void) denlstring(f, TRUE, TRUE); 218738032Speter 218864562Sgshapiro if (l <= 0) 218964562Sgshapiro syserr("!cleanstrcpy: length == 0"); 219064562Sgshapiro 219138032Speter l--; 219238032Speter while (l > 0 && *f != '\0') 219338032Speter { 219438032Speter if (isascii(*f) && 219538032Speter (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) 219638032Speter { 219738032Speter l--; 219838032Speter *t++ = *f; 219938032Speter } 220038032Speter f++; 220138032Speter } 220238032Speter *t = '\0'; 220338032Speter} 220464562Sgshapiro 220538032Speter/* 220638032Speter** DENLSTRING -- convert newlines in a string to spaces 220738032Speter** 220838032Speter** Parameters: 220938032Speter** s -- the input string 221038032Speter** strict -- if set, don't permit continuation lines. 221138032Speter** logattacks -- if set, log attempted attacks. 221238032Speter** 221338032Speter** Returns: 221438032Speter** A pointer to a version of the string with newlines 221538032Speter** mapped to spaces. This should be copied. 221638032Speter*/ 221738032Speter 221838032Speterchar * 221938032Speterdenlstring(s, strict, logattacks) 222038032Speter char *s; 222138032Speter bool strict; 222238032Speter bool logattacks; 222338032Speter{ 222438032Speter register char *p; 222538032Speter int l; 222638032Speter static char *bp = NULL; 222738032Speter static int bl = 0; 222838032Speter 222938032Speter p = s; 223038032Speter while ((p = strchr(p, '\n')) != NULL) 223138032Speter if (strict || (*++p != ' ' && *p != '\t')) 223238032Speter break; 223338032Speter if (p == NULL) 223438032Speter return s; 223538032Speter 223638032Speter l = strlen(s) + 1; 223738032Speter if (bl < l) 223838032Speter { 223938032Speter /* allocate more space */ 224038032Speter if (bp != NULL) 224177349Sgshapiro sm_free(bp); 224238032Speter bp = xalloc(l); 224338032Speter bl = l; 224438032Speter } 224564562Sgshapiro (void) strlcpy(bp, s, l); 224638032Speter for (p = bp; (p = strchr(p, '\n')) != NULL; ) 224738032Speter *p++ = ' '; 224838032Speter 224938032Speter if (logattacks) 225038032Speter { 225138032Speter sm_syslog(LOG_NOTICE, CurEnv->e_id, 225264562Sgshapiro "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", 225364562Sgshapiro RealHostName == NULL ? "[UNKNOWN]" : RealHostName, 225464562Sgshapiro shortenstring(bp, MAXSHORTSTR)); 225538032Speter } 225638032Speter 225738032Speter return bp; 225838032Speter} 225938032Speter/* 226038032Speter** PATH_IS_DIR -- check to see if file exists and is a directory. 226138032Speter** 226238032Speter** There are some additional checks for security violations in 226338032Speter** here. This routine is intended to be used for the host status 226438032Speter** support. 226538032Speter** 226638032Speter** Parameters: 226738032Speter** pathname -- pathname to check for directory-ness. 226838032Speter** createflag -- if set, create directory if needed. 226938032Speter** 227038032Speter** Returns: 227138032Speter** TRUE -- if the indicated pathname is a directory 227238032Speter** FALSE -- otherwise 227338032Speter*/ 227438032Speter 227538032Speterint 227638032Speterpath_is_dir(pathname, createflag) 227738032Speter char *pathname; 227838032Speter bool createflag; 227938032Speter{ 228038032Speter struct stat statbuf; 228138032Speter 228238032Speter#if HASLSTAT 228338032Speter if (lstat(pathname, &statbuf) < 0) 228464562Sgshapiro#else /* HASLSTAT */ 228538032Speter if (stat(pathname, &statbuf) < 0) 228664562Sgshapiro#endif /* HASLSTAT */ 228738032Speter { 228838032Speter if (errno != ENOENT || !createflag) 228938032Speter return FALSE; 229038032Speter if (mkdir(pathname, 0755) < 0) 229138032Speter return FALSE; 229238032Speter return TRUE; 229338032Speter } 229438032Speter if (!S_ISDIR(statbuf.st_mode)) 229538032Speter { 229638032Speter errno = ENOTDIR; 229738032Speter return FALSE; 229838032Speter } 229938032Speter 230038032Speter /* security: don't allow writable directories */ 230138032Speter if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) 230238032Speter { 230338032Speter errno = EACCES; 230438032Speter return FALSE; 230538032Speter } 230638032Speter 230738032Speter return TRUE; 230838032Speter} 230938032Speter/* 231038032Speter** PROC_LIST_ADD -- add process id to list of our children 231138032Speter** 231238032Speter** Parameters: 231338032Speter** pid -- pid to add to list. 231464562Sgshapiro** task -- task of pid. 231564562Sgshapiro** type -- type of process. 231638032Speter** 231738032Speter** Returns: 231838032Speter** none 231938032Speter*/ 232038032Speter 232177349Sgshapirostatic struct procs *volatile ProcListVec = NULL; 232264562Sgshapirostatic int ProcListSize = 0; 232342575Speter 232438032Spetervoid 232564562Sgshapiroproc_list_add(pid, task, type) 232638032Speter pid_t pid; 232742575Speter char *task; 232864562Sgshapiro int type; 232938032Speter{ 233038032Speter int i; 233138032Speter 233238032Speter for (i = 0; i < ProcListSize; i++) 233338032Speter { 233442575Speter if (ProcListVec[i].proc_pid == NO_PID) 233538032Speter break; 233638032Speter } 233738032Speter if (i >= ProcListSize) 233838032Speter { 233938032Speter /* probe the existing vector to avoid growing infinitely */ 234038032Speter proc_list_probe(); 234138032Speter 234238032Speter /* now scan again */ 234338032Speter for (i = 0; i < ProcListSize; i++) 234438032Speter { 234542575Speter if (ProcListVec[i].proc_pid == NO_PID) 234638032Speter break; 234738032Speter } 234838032Speter } 234938032Speter if (i >= ProcListSize) 235038032Speter { 235138032Speter /* grow process list */ 235242575Speter struct procs *npv; 235338032Speter 235464562Sgshapiro npv = (struct procs *) xalloc((sizeof *npv) * 235564562Sgshapiro (ProcListSize + PROC_LIST_SEG)); 235638032Speter if (ProcListSize > 0) 235738032Speter { 235864562Sgshapiro memmove(npv, ProcListVec, 235964562Sgshapiro ProcListSize * sizeof (struct procs)); 236077349Sgshapiro sm_free(ProcListVec); 236138032Speter } 236238032Speter for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) 236342575Speter { 236442575Speter npv[i].proc_pid = NO_PID; 236542575Speter npv[i].proc_task = NULL; 236664562Sgshapiro npv[i].proc_type = PROC_NONE; 236742575Speter } 236838032Speter i = ProcListSize; 236938032Speter ProcListSize += PROC_LIST_SEG; 237038032Speter ProcListVec = npv; 237138032Speter } 237242575Speter ProcListVec[i].proc_pid = pid; 237364562Sgshapiro if (ProcListVec[i].proc_task != NULL) 237477349Sgshapiro sm_free(ProcListVec[i].proc_task); 237542575Speter ProcListVec[i].proc_task = newstr(task); 237664562Sgshapiro ProcListVec[i].proc_type = type; 237742575Speter 237842575Speter /* if process adding itself, it's not a child */ 237942575Speter if (pid != getpid()) 238042575Speter CurChildren++; 238138032Speter} 238238032Speter/* 238342575Speter** PROC_LIST_SET -- set pid task in process list 238442575Speter** 238542575Speter** Parameters: 238642575Speter** pid -- pid to set 238742575Speter** task -- task of pid 238842575Speter** 238942575Speter** Returns: 239042575Speter** none. 239142575Speter*/ 239242575Speter 239342575Spetervoid 239442575Speterproc_list_set(pid, task) 239542575Speter pid_t pid; 239642575Speter char *task; 239742575Speter{ 239842575Speter int i; 239942575Speter 240042575Speter for (i = 0; i < ProcListSize; i++) 240142575Speter { 240242575Speter if (ProcListVec[i].proc_pid == pid) 240342575Speter { 240442575Speter if (ProcListVec[i].proc_task != NULL) 240577349Sgshapiro sm_free(ProcListVec[i].proc_task); 240642575Speter ProcListVec[i].proc_task = newstr(task); 240742575Speter break; 240842575Speter } 240942575Speter } 241042575Speter} 241142575Speter/* 241238032Speter** PROC_LIST_DROP -- drop pid from process list 241338032Speter** 241438032Speter** Parameters: 241538032Speter** pid -- pid to drop 241638032Speter** 241738032Speter** Returns: 241864562Sgshapiro** type of process 241977349Sgshapiro** 242077349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 242177349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 242277349Sgshapiro** DOING. 242338032Speter*/ 242438032Speter 242564562Sgshapiroint 242638032Speterproc_list_drop(pid) 242738032Speter pid_t pid; 242838032Speter{ 242938032Speter int i; 243064562Sgshapiro int type = PROC_NONE; 243138032Speter 243238032Speter for (i = 0; i < ProcListSize; i++) 243338032Speter { 243442575Speter if (ProcListVec[i].proc_pid == pid) 243538032Speter { 243642575Speter ProcListVec[i].proc_pid = NO_PID; 243764562Sgshapiro type = ProcListVec[i].proc_type; 243838032Speter break; 243938032Speter } 244038032Speter } 244138032Speter if (CurChildren > 0) 244238032Speter CurChildren--; 244364562Sgshapiro 244464562Sgshapiro 244564562Sgshapiro return type; 244638032Speter} 244738032Speter/* 244838032Speter** PROC_LIST_CLEAR -- clear the process list 244938032Speter** 245038032Speter** Parameters: 245138032Speter** none. 245238032Speter** 245338032Speter** Returns: 245438032Speter** none. 245538032Speter*/ 245638032Speter 245738032Spetervoid 245838032Speterproc_list_clear() 245938032Speter{ 246038032Speter int i; 246138032Speter 246242575Speter /* start from 1 since 0 is the daemon itself */ 246342575Speter for (i = 1; i < ProcListSize; i++) 246442575Speter { 246542575Speter ProcListVec[i].proc_pid = NO_PID; 246642575Speter } 246738032Speter CurChildren = 0; 246838032Speter} 246938032Speter/* 247038032Speter** PROC_LIST_PROBE -- probe processes in the list to see if they still exist 247138032Speter** 247238032Speter** Parameters: 247338032Speter** none 247438032Speter** 247538032Speter** Returns: 247638032Speter** none 247738032Speter*/ 247838032Speter 247938032Spetervoid 248038032Speterproc_list_probe() 248138032Speter{ 248238032Speter int i; 248338032Speter 248442575Speter /* start from 1 since 0 is the daemon itself */ 248542575Speter for (i = 1; i < ProcListSize; i++) 248638032Speter { 248742575Speter if (ProcListVec[i].proc_pid == NO_PID) 248838032Speter continue; 248942575Speter if (kill(ProcListVec[i].proc_pid, 0) < 0) 249038032Speter { 249138032Speter if (LogLevel > 3) 249238032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 249364562Sgshapiro "proc_list_probe: lost pid %d", 249464562Sgshapiro (int) ProcListVec[i].proc_pid); 249542575Speter ProcListVec[i].proc_pid = NO_PID; 249638032Speter CurChildren--; 249738032Speter } 249838032Speter } 249938032Speter if (CurChildren < 0) 250038032Speter CurChildren = 0; 250138032Speter} 250238032Speter/* 250342575Speter** PROC_LIST_DISPLAY -- display the process list 250442575Speter** 250542575Speter** Parameters: 250642575Speter** out -- output file pointer 250742575Speter** 250842575Speter** Returns: 250942575Speter** none. 251042575Speter*/ 251142575Speter 251242575Spetervoid 251342575Speterproc_list_display(out) 251442575Speter FILE *out; 251542575Speter{ 251642575Speter int i; 251742575Speter 251842575Speter for (i = 0; i < ProcListSize; i++) 251942575Speter { 252042575Speter if (ProcListVec[i].proc_pid == NO_PID) 252142575Speter continue; 252242575Speter 252342575Speter fprintf(out, "%d %s%s\n", (int) ProcListVec[i].proc_pid, 252442575Speter ProcListVec[i].proc_task != NULL ? 252542575Speter ProcListVec[i].proc_task : "(unknown)", 252642575Speter (OpMode == MD_SMTP || 252742575Speter OpMode == MD_DAEMON || 252842575Speter OpMode == MD_ARPAFTP) ? "\r" : ""); 252942575Speter } 253042575Speter} 253142575Speter/* 253280785Sgshapiro** SAFEFOPEN -- do a file open with extra checking 253380785Sgshapiro** 253480785Sgshapiro** Parameters: 253580785Sgshapiro** fn -- the file name to open. 253680785Sgshapiro** omode -- the open-style mode flags. 253780785Sgshapiro** cmode -- the create-style mode flags. 253880785Sgshapiro** sff -- safefile flags. 253980785Sgshapiro** 254080785Sgshapiro** Returns: 254180785Sgshapiro** Same as fopen. 254280785Sgshapiro*/ 254380785Sgshapiro 254480785SgshapiroFILE * 254580785Sgshapirosafefopen(fn, omode, cmode, sff) 254680785Sgshapiro char *fn; 254780785Sgshapiro int omode; 254880785Sgshapiro int cmode; 254980785Sgshapiro long sff; 255080785Sgshapiro{ 255180785Sgshapiro int fd; 255280785Sgshapiro int save_errno; 255380785Sgshapiro FILE *fp; 255480785Sgshapiro char *fmode; 255580785Sgshapiro 255680785Sgshapiro switch (omode & O_ACCMODE) 255780785Sgshapiro { 255880785Sgshapiro case O_RDONLY: 255980785Sgshapiro fmode = "r"; 256080785Sgshapiro break; 256180785Sgshapiro 256280785Sgshapiro case O_WRONLY: 256380785Sgshapiro if (bitset(O_APPEND, omode)) 256480785Sgshapiro fmode = "a"; 256580785Sgshapiro else 256680785Sgshapiro fmode = "w"; 256780785Sgshapiro break; 256880785Sgshapiro 256980785Sgshapiro case O_RDWR: 257080785Sgshapiro if (bitset(O_TRUNC, omode)) 257180785Sgshapiro fmode = "w+"; 257280785Sgshapiro else if (bitset(O_APPEND, omode)) 257380785Sgshapiro fmode = "a+"; 257480785Sgshapiro else 257580785Sgshapiro fmode = "r+"; 257680785Sgshapiro break; 257780785Sgshapiro 257880785Sgshapiro default: 257980785Sgshapiro syserr("554 5.3.5 safefopen: unknown omode %o", omode); 258080785Sgshapiro fmode = "x"; 258180785Sgshapiro } 258280785Sgshapiro fd = safeopen(fn, omode, cmode, sff); 258380785Sgshapiro if (fd < 0) 258480785Sgshapiro { 258580785Sgshapiro save_errno = errno; 258680785Sgshapiro if (tTd(44, 10)) 258780785Sgshapiro dprintf("safefopen: safeopen failed: %s\n", 258880785Sgshapiro errstring(errno)); 258980785Sgshapiro errno = save_errno; 259080785Sgshapiro return NULL; 259180785Sgshapiro } 259280785Sgshapiro fp = fdopen(fd, fmode); 259380785Sgshapiro if (fp != NULL) 259480785Sgshapiro return fp; 259580785Sgshapiro 259680785Sgshapiro save_errno = errno; 259780785Sgshapiro if (tTd(44, 10)) 259880785Sgshapiro { 259980785Sgshapiro dprintf("safefopen: fdopen(%s, %s) failed: omode=%x, sff=%lx, err=%s\n", 260080785Sgshapiro fn, fmode, omode, sff, errstring(errno)); 260180785Sgshapiro } 260280785Sgshapiro (void) close(fd); 260380785Sgshapiro errno = save_errno; 260480785Sgshapiro return NULL; 260580785Sgshapiro} 260680785Sgshapiro/* 260738032Speter** SM_STRCASECMP -- 8-bit clean version of strcasecmp 260838032Speter** 260938032Speter** Thank you, vendors, for making this all necessary. 261038032Speter*/ 261138032Speter 261238032Speter/* 261338032Speter * Copyright (c) 1987, 1993 261438032Speter * The Regents of the University of California. All rights reserved. 261538032Speter * 261638032Speter * Redistribution and use in source and binary forms, with or without 261738032Speter * modification, are permitted provided that the following conditions 261838032Speter * are met: 261938032Speter * 1. Redistributions of source code must retain the above copyright 262038032Speter * notice, this list of conditions and the following disclaimer. 262138032Speter * 2. Redistributions in binary form must reproduce the above copyright 262238032Speter * notice, this list of conditions and the following disclaimer in the 262338032Speter * documentation and/or other materials provided with the distribution. 262438032Speter * 3. All advertising materials mentioning features or use of this software 262538032Speter * must display the following acknowledgement: 262638032Speter * This product includes software developed by the University of 262738032Speter * California, Berkeley and its contributors. 262838032Speter * 4. Neither the name of the University nor the names of its contributors 262938032Speter * may be used to endorse or promote products derived from this software 263038032Speter * without specific prior written permission. 263138032Speter * 263238032Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 263338032Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 263438032Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 263538032Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 263638032Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 263738032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 263838032Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 263938032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 264038032Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 264138032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264238032Speter * SUCH DAMAGE. 264338032Speter */ 264438032Speter 264538032Speter#if defined(LIBC_SCCS) && !defined(lint) 264638032Speterstatic char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; 264764562Sgshapiro#endif /* defined(LIBC_SCCS) && !defined(lint) */ 264838032Speter 264938032Speter/* 265038032Speter * This array is designed for mapping upper and lower case letter 265138032Speter * together for a case independent comparison. The mappings are 265238032Speter * based upon ascii character sequences. 265338032Speter */ 265438032Speterstatic const u_char charmap[] = { 265538032Speter 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 265638032Speter 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, 265738032Speter 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, 265838032Speter 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, 265938032Speter 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, 266038032Speter 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, 266138032Speter 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, 266238032Speter 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, 266338032Speter 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 266438032Speter 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 266538032Speter 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 266638032Speter 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, 266738032Speter 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, 266838032Speter 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, 266938032Speter 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, 267038032Speter 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, 267138032Speter 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, 267238032Speter 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, 267338032Speter 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, 267438032Speter 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, 267538032Speter 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 267638032Speter 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, 267738032Speter 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, 267838032Speter 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, 267938032Speter 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, 268038032Speter 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, 268138032Speter 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, 268238032Speter 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, 268338032Speter 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 268438032Speter 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, 268538032Speter 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, 268638032Speter 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, 268738032Speter}; 268838032Speter 268938032Speterint 269038032Spetersm_strcasecmp(s1, s2) 269138032Speter const char *s1, *s2; 269238032Speter{ 269338032Speter register const u_char *cm = charmap, 269438032Speter *us1 = (const u_char *)s1, 269538032Speter *us2 = (const u_char *)s2; 269638032Speter 269738032Speter while (cm[*us1] == cm[*us2++]) 269838032Speter if (*us1++ == '\0') 269964562Sgshapiro return 0; 270038032Speter return (cm[*us1] - cm[*--us2]); 270138032Speter} 270238032Speter 270338032Speterint 270438032Spetersm_strncasecmp(s1, s2, n) 270538032Speter const char *s1, *s2; 270638032Speter register size_t n; 270738032Speter{ 270838032Speter if (n != 0) { 270938032Speter register const u_char *cm = charmap, 271038032Speter *us1 = (const u_char *)s1, 271138032Speter *us2 = (const u_char *)s2; 271238032Speter 271338032Speter do { 271438032Speter if (cm[*us1] != cm[*us2++]) 271538032Speter return (cm[*us1] - cm[*--us2]); 271638032Speter if (*us1++ == '\0') 271738032Speter break; 271838032Speter } while (--n != 0); 271938032Speter } 272064562Sgshapiro return 0; 272138032Speter} 2722