122717Sdist /* 242833Sbostic * Copyright (c) 1983 Eric P. Allman 363589Sbostic * Copyright (c) 1988, 1993 463589Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642833Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822717Sdist 922717Sdist #ifndef lint 10*68464Seric static char sccsid[] = "@(#)util.c 8.52 (Berkeley) 02/28/95"; 1133731Sbostic #endif /* not lint */ 1222717Sdist 1358332Seric # include "sendmail.h" 14298Seric # include <sysexits.h> 1557135Seric /* 16298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 17298Seric ** 18298Seric ** Runs through a string and strips off unquoted quote 19298Seric ** characters and quote bits. This is done in place. 20298Seric ** 21298Seric ** Parameters: 22298Seric ** s -- the string to strip. 23298Seric ** 24298Seric ** Returns: 25298Seric ** none. 26298Seric ** 27298Seric ** Side Effects: 28298Seric ** none. 29298Seric ** 30298Seric ** Called By: 31298Seric ** deliver 32298Seric */ 33298Seric 3454983Seric stripquotes(s) 35298Seric char *s; 36298Seric { 37298Seric register char *p; 38298Seric register char *q; 39298Seric register char c; 40298Seric 414101Seric if (s == NULL) 424101Seric return; 434101Seric 4454983Seric p = q = s; 4554983Seric do 46298Seric { 4754983Seric c = *p++; 4854983Seric if (c == '\\') 4954983Seric c = *p++; 5054983Seric else if (c == '"') 5154983Seric continue; 5254983Seric *q++ = c; 5354983Seric } while (c != '\0'); 54298Seric } 55298Seric /* 56298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 57298Seric ** 58298Seric ** THIS IS A CLUDGE. This should be made to give a proper 59298Seric ** error -- but after all, what can we do? 60298Seric ** 61298Seric ** Parameters: 62298Seric ** sz -- size of area to allocate. 63298Seric ** 64298Seric ** Returns: 65298Seric ** pointer to data region. 66298Seric ** 67298Seric ** Side Effects: 68298Seric ** Memory is allocated. 69298Seric */ 70298Seric 71298Seric char * 72298Seric xalloc(sz) 737007Seric register int sz; 74298Seric { 75298Seric register char *p; 76298Seric 7766747Seric /* some systems can't handle size zero mallocs */ 7866747Seric if (sz <= 0) 7966747Seric sz = 1; 8066747Seric 8123121Seric p = malloc((unsigned) sz); 82298Seric if (p == NULL) 83298Seric { 84298Seric syserr("Out of memory!!"); 8510685Seric abort(); 8610685Seric /* exit(EX_UNAVAILABLE); */ 87298Seric } 88298Seric return (p); 89298Seric } 90298Seric /* 913151Seric ** COPYPLIST -- copy list of pointers. 923151Seric ** 933151Seric ** This routine is the equivalent of newstr for lists of 943151Seric ** pointers. 953151Seric ** 963151Seric ** Parameters: 973151Seric ** list -- list of pointers to copy. 983151Seric ** Must be NULL terminated. 993151Seric ** copycont -- if TRUE, copy the contents of the vector 1003151Seric ** (which must be a string) also. 1013151Seric ** 1023151Seric ** Returns: 1033151Seric ** a copy of 'list'. 1043151Seric ** 1053151Seric ** Side Effects: 1063151Seric ** none. 1073151Seric */ 1083151Seric 1093151Seric char ** 1103151Seric copyplist(list, copycont) 1113151Seric char **list; 1123151Seric bool copycont; 1133151Seric { 1143151Seric register char **vp; 1153151Seric register char **newvp; 1163151Seric 1173151Seric for (vp = list; *vp != NULL; vp++) 1183151Seric continue; 1193151Seric 1203151Seric vp++; 1213151Seric 12216897Seric newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); 12316897Seric bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); 1243151Seric 1253151Seric if (copycont) 1263151Seric { 1273151Seric for (vp = newvp; *vp != NULL; vp++) 1283151Seric *vp = newstr(*vp); 1293151Seric } 1303151Seric 1313151Seric return (newvp); 1323151Seric } 1333151Seric /* 13458170Seric ** COPYQUEUE -- copy address queue. 13558170Seric ** 13658170Seric ** This routine is the equivalent of newstr for address queues 13758170Seric ** addresses marked with QDONTSEND aren't copied 13858170Seric ** 13958170Seric ** Parameters: 14058170Seric ** addr -- list of address structures to copy. 14158170Seric ** 14258170Seric ** Returns: 14358170Seric ** a copy of 'addr'. 14458170Seric ** 14558170Seric ** Side Effects: 14658170Seric ** none. 14758170Seric */ 14858170Seric 14958170Seric ADDRESS * 15058170Seric copyqueue(addr) 15158170Seric ADDRESS *addr; 15258170Seric { 15358170Seric register ADDRESS *newaddr; 15458170Seric ADDRESS *ret; 15558170Seric register ADDRESS **tail = &ret; 15658170Seric 15758170Seric while (addr != NULL) 15858170Seric { 15958170Seric if (!bitset(QDONTSEND, addr->q_flags)) 16058170Seric { 16158170Seric newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); 16258170Seric STRUCTCOPY(*addr, *newaddr); 16358170Seric *tail = newaddr; 16458170Seric tail = &newaddr->q_next; 16558170Seric } 16658170Seric addr = addr->q_next; 16758170Seric } 16858170Seric *tail = NULL; 16958170Seric 17058170Seric return ret; 17158170Seric } 17258170Seric /* 1733151Seric ** PRINTAV -- print argument vector. 1743151Seric ** 1753151Seric ** Parameters: 1763151Seric ** av -- argument vector. 1773151Seric ** 1783151Seric ** Returns: 1793151Seric ** none. 1803151Seric ** 1813151Seric ** Side Effects: 1823151Seric ** prints av. 1833151Seric */ 1843151Seric 1853151Seric printav(av) 1863151Seric register char **av; 1873151Seric { 1883151Seric while (*av != NULL) 1893151Seric { 1908063Seric if (tTd(0, 44)) 1918063Seric printf("\n\t%08x=", *av); 1928063Seric else 19323105Seric (void) putchar(' '); 1943151Seric xputs(*av++); 1953151Seric } 19623105Seric (void) putchar('\n'); 1973151Seric } 1983151Seric /* 1993151Seric ** LOWER -- turn letter into lower case. 2003151Seric ** 2013151Seric ** Parameters: 2023151Seric ** c -- character to turn into lower case. 2033151Seric ** 2043151Seric ** Returns: 2053151Seric ** c, in lower case. 2063151Seric ** 2073151Seric ** Side Effects: 2083151Seric ** none. 2093151Seric */ 2103151Seric 2113151Seric char 2123151Seric lower(c) 2133151Seric register char c; 2143151Seric { 21558050Seric return((isascii(c) && isupper(c)) ? tolower(c) : c); 2163151Seric } 2173151Seric /* 2183151Seric ** XPUTS -- put string doing control escapes. 2193151Seric ** 2203151Seric ** Parameters: 2213151Seric ** s -- string to put. 2223151Seric ** 2233151Seric ** Returns: 2243151Seric ** none. 2253151Seric ** 2263151Seric ** Side Effects: 2273151Seric ** output to stdout 2283151Seric */ 2293151Seric 2303151Seric xputs(s) 2313151Seric register char *s; 2323151Seric { 23358050Seric register int c; 23451781Seric register struct metamac *mp; 23551781Seric extern struct metamac MetaMacros[]; 2363151Seric 2378055Seric if (s == NULL) 2388055Seric { 2398055Seric printf("<null>"); 2408055Seric return; 2418055Seric } 24258050Seric while ((c = (*s++ & 0377)) != '\0') 2433151Seric { 2443151Seric if (!isascii(c)) 2453151Seric { 246*68464Seric if (c == MATCHREPL) 24758050Seric { 24858050Seric putchar('$'); 24958050Seric continue; 25058050Seric } 251*68464Seric if (c == MACROEXPAND) 252*68464Seric { 253*68464Seric putchar('$'); 254*68464Seric if (bitset(0200, *s)) 255*68464Seric printf("{%s}", macname(*s++ & 0377)); 256*68464Seric continue; 257*68464Seric } 25858050Seric for (mp = MetaMacros; mp->metaname != '\0'; mp++) 25958050Seric { 26058050Seric if ((mp->metaval & 0377) == c) 26158050Seric { 26258050Seric printf("$%c", mp->metaname); 26358050Seric break; 26458050Seric } 26558050Seric } 26658050Seric if (mp->metaname != '\0') 26758050Seric continue; 26823105Seric (void) putchar('\\'); 2693151Seric c &= 0177; 2703151Seric } 27157589Seric if (isprint(c)) 2723151Seric { 27357589Seric putchar(c); 27457589Seric continue; 27557589Seric } 27652050Seric 27757589Seric /* wasn't a meta-macro -- find another way to print it */ 27857589Seric switch (c) 27957589Seric { 28057589Seric case '\0': 28157589Seric continue; 28252050Seric 28357589Seric case '\n': 28457589Seric c = 'n'; 28557589Seric break; 28652050Seric 28757589Seric case '\r': 28857589Seric c = 'r'; 28957589Seric break; 29052637Seric 29157589Seric case '\t': 29257589Seric c = 't'; 29357589Seric break; 29457589Seric 29557589Seric default: 29657589Seric (void) putchar('^'); 29757589Seric (void) putchar(c ^ 0100); 29857589Seric continue; 2993151Seric } 3003151Seric } 3014086Seric (void) fflush(stdout); 3023151Seric } 3033151Seric /* 3043151Seric ** MAKELOWER -- Translate a line into lower case 3053151Seric ** 3063151Seric ** Parameters: 3073151Seric ** p -- the string to translate. If NULL, return is 3083151Seric ** immediate. 3093151Seric ** 3103151Seric ** Returns: 3113151Seric ** none. 3123151Seric ** 3133151Seric ** Side Effects: 3143151Seric ** String pointed to by p is translated to lower case. 3153151Seric ** 3163151Seric ** Called By: 3173151Seric ** parse 3183151Seric */ 3193151Seric 320*68464Seric void 3213151Seric makelower(p) 3223151Seric register char *p; 3233151Seric { 3243151Seric register char c; 3253151Seric 3263151Seric if (p == NULL) 3273151Seric return; 3283151Seric for (; (c = *p) != '\0'; p++) 3293151Seric if (isascii(c) && isupper(c)) 33033724Sbostic *p = tolower(c); 3313151Seric } 3324059Seric /* 3335196Seric ** BUILDFNAME -- build full name from gecos style entry. 3344375Seric ** 3355196Seric ** This routine interprets the strange entry that would appear 3365196Seric ** in the GECOS field of the password file. 3375196Seric ** 3384375Seric ** Parameters: 3395196Seric ** p -- name to build. 3405196Seric ** login -- the login name of this user (for &). 3415196Seric ** buf -- place to put the result. 3424375Seric ** 3434375Seric ** Returns: 34465006Seric ** none. 3454375Seric ** 3464375Seric ** Side Effects: 3474375Seric ** none. 3484375Seric */ 3494375Seric 35054984Seric buildfname(gecos, login, buf) 35165006Seric register char *gecos; 35265006Seric char *login; 35365006Seric char *buf; 3544375Seric { 35565006Seric register char *p; 35665006Seric register char *bp = buf; 35765006Seric int l; 3584375Seric 35965006Seric if (*gecos == '*') 36065006Seric gecos++; 36165006Seric 36265006Seric /* find length of final string */ 36365006Seric l = 0; 36465006Seric for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 36554984Seric { 36665006Seric if (*p == '&') 36765006Seric l += strlen(login); 36865006Seric else 36965006Seric l++; 37054984Seric } 37165006Seric 37265006Seric /* now fill in buf */ 37365006Seric for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 3744375Seric { 37565006Seric if (*p == '&') 3764375Seric { 37765006Seric (void) strcpy(bp, login); 37865006Seric *bp = toupper(*bp); 37965006Seric while (*bp != '\0') 38065006Seric bp++; 3814375Seric } 38265006Seric else 38365006Seric *bp++ = *p; 3844375Seric } 3854375Seric *bp = '\0'; 3864375Seric } 3874375Seric /* 3884538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 3894538Seric ** 3904538Seric ** Parameters: 3914538Seric ** fn -- filename to check. 39264083Seric ** uid -- user id to compare against. 39364083Seric ** gid -- group id to compare against. 39464083Seric ** uname -- user name to compare against (used for group 39564083Seric ** sets). 39664944Seric ** flags -- modifiers: 39765064Seric ** SFF_MUSTOWN -- "uid" must own this file. 39865064Seric ** SFF_NOSLINK -- file cannot be a symbolic link. 3994538Seric ** mode -- mode bits that must match. 4004538Seric ** 4014538Seric ** Returns: 40258247Seric ** 0 if fn exists, is owned by uid, and matches mode. 40358247Seric ** An errno otherwise. The actual errno is cleared. 4044538Seric ** 4054538Seric ** Side Effects: 4064538Seric ** none. 4074538Seric */ 4084538Seric 40964083Seric #include <grp.h> 41064083Seric 41163581Seric #ifndef S_IXOTH 41263581Seric # define S_IXOTH (S_IEXEC >> 6) 41363581Seric #endif 41463581Seric 41564083Seric #ifndef S_IXGRP 41664083Seric # define S_IXGRP (S_IEXEC >> 3) 41764083Seric #endif 41864083Seric 41963753Seric #ifndef S_IXUSR 42063753Seric # define S_IXUSR (S_IEXEC) 42163753Seric #endif 42263753Seric 42358247Seric int 42464944Seric safefile(fn, uid, gid, uname, flags, mode) 4254538Seric char *fn; 42655372Seric uid_t uid; 42764083Seric gid_t gid; 42864083Seric char *uname; 42964944Seric int flags; 4304538Seric int mode; 4314538Seric { 43263581Seric register char *p; 43364083Seric register struct group *gr = NULL; 4344538Seric struct stat stbuf; 4354538Seric 43663581Seric if (tTd(54, 4)) 43764944Seric printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", 43864944Seric fn, uid, gid, flags, mode); 43963581Seric errno = 0; 44063581Seric 441*68464Seric if (!bitset(SFF_NOPATHCHECK, flags) || 442*68464Seric (uid == 0 && !bitset(SFF_ROOTOK, flags))) 44363581Seric { 444*68464Seric /* check the path to the file for acceptability */ 445*68464Seric for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') 44665225Seric { 447*68464Seric *p = '\0'; 448*68464Seric if (stat(fn, &stbuf) < 0) 449*68464Seric break; 450*68464Seric if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 451*68464Seric { 452*68464Seric if (bitset(S_IXOTH, stbuf.st_mode)) 453*68464Seric continue; 454*68464Seric break; 455*68464Seric } 456*68464Seric if (stbuf.st_uid == uid && 457*68464Seric bitset(S_IXUSR, stbuf.st_mode)) 45865225Seric continue; 459*68464Seric if (stbuf.st_gid == gid && 460*68464Seric bitset(S_IXGRP, stbuf.st_mode)) 461*68464Seric continue; 462*68464Seric #ifndef NO_GROUP_SET 463*68464Seric if (uname != NULL && 464*68464Seric ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 465*68464Seric (gr = getgrgid(stbuf.st_gid)) != NULL)) 466*68464Seric { 467*68464Seric register char **gp; 468*68464Seric 469*68464Seric for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++) 470*68464Seric if (strcmp(*gp, uname) == 0) 471*68464Seric break; 472*68464Seric if (gp != NULL && *gp != NULL && 473*68464Seric bitset(S_IXGRP, stbuf.st_mode)) 474*68464Seric continue; 475*68464Seric } 476*68464Seric #endif 477*68464Seric if (!bitset(S_IXOTH, stbuf.st_mode)) 478*68464Seric break; 47968457Seric } 480*68464Seric if (p != NULL) 48163581Seric { 482*68464Seric int ret = errno; 48363581Seric 484*68464Seric if (ret == 0) 485*68464Seric ret = EACCES; 486*68464Seric if (tTd(54, 4)) 487*68464Seric printf("\t[dir %s] %s\n", fn, errstring(ret)); 488*68464Seric *p = '/'; 489*68464Seric return ret; 49063581Seric } 49163581Seric } 49263581Seric 49364944Seric #ifdef HASLSTAT 49465064Seric if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, &stbuf) 49565064Seric : stat(fn, &stbuf)) < 0) 49664944Seric #else 49758247Seric if (stat(fn, &stbuf) < 0) 49864944Seric #endif 49958247Seric { 50058247Seric int ret = errno; 50158247Seric 50263581Seric if (tTd(54, 4)) 50364083Seric printf("\t%s\n", errstring(ret)); 50463581Seric 50558247Seric errno = 0; 50658247Seric return ret; 50758247Seric } 50864944Seric 50964944Seric #ifdef S_ISLNK 51065064Seric if (bitset(SFF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode)) 51164944Seric { 51264944Seric if (tTd(54, 4)) 51365123Seric printf("\t[slink mode %o]\tEPERM\n", stbuf.st_mode); 51464944Seric return EPERM; 51564944Seric } 51664944Seric #endif 51764944Seric 51865139Seric if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 51963581Seric mode >>= 6; 52064084Seric else if (stbuf.st_uid != uid) 52164084Seric { 52264084Seric mode >>= 3; 52364084Seric if (stbuf.st_gid == gid) 52464084Seric ; 52564084Seric #ifndef NO_GROUP_SET 52664084Seric else if (uname != NULL && 52764084Seric ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 52864084Seric (gr = getgrgid(stbuf.st_gid)) != NULL)) 52964084Seric { 53064084Seric register char **gp; 53164084Seric 53264084Seric for (gp = gr->gr_mem; *gp != NULL; gp++) 53364084Seric if (strcmp(*gp, uname) == 0) 53464084Seric break; 53564084Seric if (*gp == NULL) 53664084Seric mode >>= 3; 53764084Seric } 53864084Seric #endif 53964084Seric else 54064084Seric mode >>= 3; 54164084Seric } 54263581Seric if (tTd(54, 4)) 54364084Seric printf("\t[uid %d, stat %o, mode %o] ", 54464084Seric stbuf.st_uid, stbuf.st_mode, mode); 54564944Seric if ((stbuf.st_uid == uid || stbuf.st_uid == 0 || 54665064Seric !bitset(SFF_MUSTOWN, flags)) && 54763581Seric (stbuf.st_mode & mode) == mode) 54863581Seric { 54963581Seric if (tTd(54, 4)) 55064083Seric printf("\tOK\n"); 55158247Seric return 0; 55263581Seric } 55363581Seric if (tTd(54, 4)) 55464083Seric printf("\tEACCES\n"); 55563581Seric return EACCES; 5564538Seric } 5574538Seric /* 5584557Seric ** FIXCRLF -- fix <CR><LF> in line. 5594557Seric ** 5604557Seric ** Looks for the <CR><LF> combination and turns it into the 5614557Seric ** UNIX canonical <NL> character. It only takes one line, 5624557Seric ** i.e., it is assumed that the first <NL> found is the end 5634557Seric ** of the line. 5644557Seric ** 5654557Seric ** Parameters: 5664557Seric ** line -- the line to fix. 5674557Seric ** stripnl -- if true, strip the newline also. 5684557Seric ** 5694557Seric ** Returns: 5704557Seric ** none. 5714557Seric ** 5724557Seric ** Side Effects: 5734557Seric ** line is changed in place. 5744557Seric */ 5754557Seric 5764557Seric fixcrlf(line, stripnl) 5774557Seric char *line; 5784557Seric bool stripnl; 5794557Seric { 5804557Seric register char *p; 5814557Seric 58256795Seric p = strchr(line, '\n'); 5834557Seric if (p == NULL) 5844557Seric return; 58536291Sbostic if (p > line && p[-1] == '\r') 5864557Seric p--; 5874557Seric if (!stripnl) 5884557Seric *p++ = '\n'; 5894557Seric *p = '\0'; 5904557Seric } 5914557Seric /* 5926890Seric ** DFOPEN -- determined file open 5936890Seric ** 5946890Seric ** This routine has the semantics of fopen, except that it will 5956890Seric ** keep trying a few times to make this happen. The idea is that 5966890Seric ** on very loaded systems, we may run out of resources (inodes, 5976890Seric ** whatever), so this tries to get around it. 5986890Seric */ 5996890Seric 60063753Seric #ifndef O_ACCMODE 60163753Seric # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 60263753Seric #endif 60363753Seric 60459745Seric struct omodes 60559745Seric { 60659745Seric int mask; 60759745Seric int mode; 60859745Seric char *farg; 60959745Seric } OpenModes[] = 61059745Seric { 61159745Seric O_ACCMODE, O_RDONLY, "r", 61259745Seric O_ACCMODE|O_APPEND, O_WRONLY, "w", 61359745Seric O_ACCMODE|O_APPEND, O_WRONLY|O_APPEND, "a", 61459745Seric O_TRUNC, 0, "w+", 61559745Seric O_APPEND, O_APPEND, "a+", 61659745Seric 0, 0, "r+", 61759745Seric }; 61859745Seric 6196890Seric FILE * 62059745Seric dfopen(filename, omode, cmode) 6216890Seric char *filename; 62259745Seric int omode; 62359745Seric int cmode; 6246890Seric { 6256890Seric register int tries; 62659745Seric int fd; 62759745Seric register struct omodes *om; 62859431Seric struct stat st; 6296890Seric 63059745Seric for (om = OpenModes; om->mask != 0; om++) 63159745Seric if ((omode & om->mask) == om->mode) 63259745Seric break; 63359745Seric 6346890Seric for (tries = 0; tries < 10; tries++) 6356890Seric { 63625618Seric sleep((unsigned) (10 * tries)); 6376890Seric errno = 0; 63859745Seric fd = open(filename, omode, cmode); 63959745Seric if (fd >= 0) 6406890Seric break; 64166017Seric switch (errno) 64266017Seric { 64366017Seric case ENFILE: /* system file table full */ 64466017Seric case EINTR: /* interrupted syscall */ 64566017Seric #ifdef ETXTBSY 64666017Seric case ETXTBSY: /* Apollo: net file locked */ 64766017Seric #endif 64866017Seric continue; 64966017Seric } 65066017Seric break; 6516890Seric } 65259745Seric if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) 65356328Seric { 65456328Seric int locktype; 65556328Seric 65656328Seric /* lock the file to avoid accidental conflicts */ 65759745Seric if ((omode & O_ACCMODE) != O_RDONLY) 65856328Seric locktype = LOCK_EX; 65956328Seric else 66056328Seric locktype = LOCK_SH; 66164335Seric (void) lockfile(fd, filename, NULL, locktype); 66256328Seric errno = 0; 66356328Seric } 66463787Seric if (fd < 0) 66563787Seric return NULL; 66663787Seric else 66763787Seric return fdopen(fd, om->farg); 6686890Seric } 6697124Seric /* 6707124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 6717124Seric ** 6727753Seric ** This routine always guarantees outputing a newline (or CRLF, 6737753Seric ** as appropriate) at the end of the string. 6747753Seric ** 6757124Seric ** Parameters: 6767124Seric ** l -- line to put. 67765870Seric ** mci -- the mailer connection information. 6787124Seric ** 6797124Seric ** Returns: 6807124Seric ** none 6817124Seric ** 6827124Seric ** Side Effects: 6837124Seric ** output of l to fp. 6847124Seric */ 6857124Seric 68665870Seric putline(l, mci) 6877753Seric register char *l; 68865870Seric register MCI *mci; 6897124Seric { 6907124Seric register char *p; 69147157Sbostic register char svchar; 69266004Seric int slop = 0; 6937124Seric 69411275Seric /* strip out 0200 bits -- these can look like TELNET protocol */ 69565870Seric if (bitset(MCIF_7BIT, mci->mci_flags)) 69611275Seric { 69761707Seric for (p = l; (svchar = *p) != '\0'; ++p) 69861707Seric if (bitset(0200, svchar)) 69947157Sbostic *p = svchar &~ 0200; 70011275Seric } 70111275Seric 7027753Seric do 7037124Seric { 7047753Seric /* find the end of the line */ 70556795Seric p = strchr(l, '\n'); 7067753Seric if (p == NULL) 7077753Seric p = &l[strlen(l)]; 7087124Seric 70963753Seric if (TrafficLogFile != NULL) 71063753Seric fprintf(TrafficLogFile, "%05d >>> ", getpid()); 71163753Seric 7127753Seric /* check for line overflow */ 71365870Seric while (mci->mci_mailer->m_linelimit > 0 && 71466004Seric (p - l + slop) > mci->mci_mailer->m_linelimit) 7157753Seric { 71666004Seric register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 7177124Seric 7187753Seric svchar = *q; 7197753Seric *q = '\0'; 72066004Seric if (l[0] == '.' && slop == 0 && 72166004Seric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 72263753Seric { 72365870Seric (void) putc('.', mci->mci_out); 72463753Seric if (TrafficLogFile != NULL) 72563753Seric (void) putc('.', TrafficLogFile); 72663753Seric } 72765870Seric fputs(l, mci->mci_out); 72865870Seric (void) putc('!', mci->mci_out); 72965870Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 73066004Seric (void) putc(' ', mci->mci_out); 73163753Seric if (TrafficLogFile != NULL) 73266004Seric fprintf(TrafficLogFile, "%s!\n%05d >>> ", 73363753Seric l, getpid()); 7347753Seric *q = svchar; 7357753Seric l = q; 73666004Seric slop = 1; 7377753Seric } 7387124Seric 7397753Seric /* output last part */ 74066004Seric if (l[0] == '.' && slop == 0 && 74166004Seric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 74263753Seric { 74365870Seric (void) putc('.', mci->mci_out); 74463753Seric if (TrafficLogFile != NULL) 74563753Seric (void) putc('.', TrafficLogFile); 74663753Seric } 74763753Seric if (TrafficLogFile != NULL) 74863753Seric fprintf(TrafficLogFile, "%.*s\n", p - l, l); 74947157Sbostic for ( ; l < p; ++l) 75065870Seric (void) putc(*l, mci->mci_out); 75165870Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 7527753Seric if (*l == '\n') 75347157Sbostic ++l; 7547753Seric } while (l[0] != '\0'); 7557124Seric } 7567676Seric /* 7577676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 7587676Seric ** 7597676Seric ** Parameters: 7607676Seric ** f -- name of file to unlink. 7617676Seric ** 7627676Seric ** Returns: 7637676Seric ** none. 7647676Seric ** 7657676Seric ** Side Effects: 7667676Seric ** f is unlinked. 7677676Seric */ 7687676Seric 7697676Seric xunlink(f) 7707676Seric char *f; 7717676Seric { 7727676Seric register int i; 7737676Seric 7747676Seric # ifdef LOG 77558020Seric if (LogLevel > 98) 77658020Seric syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); 77756795Seric # endif /* LOG */ 7787676Seric 7797676Seric i = unlink(f); 7807676Seric # ifdef LOG 78158020Seric if (i < 0 && LogLevel > 97) 7827942Seric syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); 78356795Seric # endif /* LOG */ 7847676Seric } 7857685Seric /* 78658680Seric ** XFCLOSE -- close a file, doing logging as appropriate. 78758680Seric ** 78858680Seric ** Parameters: 78958680Seric ** fp -- file pointer for the file to close 79058680Seric ** a, b -- miscellaneous crud to print for debugging 79158680Seric ** 79258680Seric ** Returns: 79358680Seric ** none. 79458680Seric ** 79558680Seric ** Side Effects: 79658680Seric ** fp is closed. 79758680Seric */ 79858680Seric 79958680Seric xfclose(fp, a, b) 80058680Seric FILE *fp; 80158680Seric char *a, *b; 80258680Seric { 80358796Seric if (tTd(53, 99)) 80458680Seric printf("xfclose(%x) %s %s\n", fp, a, b); 80564401Seric #ifdef XDEBUG 80664401Seric if (fileno(fp) == 1) 80764401Seric syserr("xfclose(%s %s): fd = 1", a, b); 80864401Seric #endif 80958796Seric if (fclose(fp) < 0 && tTd(53, 99)) 81058680Seric printf("xfclose FAILURE: %s\n", errstring(errno)); 81158680Seric } 81258680Seric /* 81314885Seric ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 8147685Seric ** 8157685Seric ** Parameters: 8167685Seric ** buf -- place to put the input line. 8177685Seric ** siz -- size of buf. 8187685Seric ** fp -- file to read from. 81957384Seric ** timeout -- the timeout before error occurs. 82061093Seric ** during -- what we are trying to read (for error messages). 8217685Seric ** 8227685Seric ** Returns: 82315533Seric ** NULL on error (including timeout). This will also leave 82415533Seric ** buf containing a null string. 8257685Seric ** buf otherwise. 8267685Seric ** 8277685Seric ** Side Effects: 8287685Seric ** none. 8297685Seric */ 8307685Seric 83114885Seric static jmp_buf CtxReadTimeout; 832*68464Seric static void readtimeout(); 8337685Seric 8347685Seric char * 83561093Seric sfgets(buf, siz, fp, timeout, during) 8367685Seric char *buf; 8377685Seric int siz; 8387685Seric FILE *fp; 83957384Seric time_t timeout; 84061093Seric char *during; 8417685Seric { 8427942Seric register EVENT *ev = NULL; 8437685Seric register char *p; 8447685Seric 84566332Seric if (fp == NULL) 84666332Seric { 84766332Seric buf[0] = '\0'; 84866332Seric return NULL; 84966332Seric } 85066332Seric 85114885Seric /* set the timeout */ 85257384Seric if (timeout != 0) 85314885Seric { 85414885Seric if (setjmp(CtxReadTimeout) != 0) 85514885Seric { 85636233Skarels # ifdef LOG 85736230Skarels syslog(LOG_NOTICE, 85861093Seric "timeout waiting for input from %s during %s\n", 85961093Seric CurHostName? CurHostName: "local", during); 86036233Skarels # endif 86136230Skarels errno = 0; 86261093Seric usrerr("451 timeout waiting for input during %s", 86361093Seric during); 86419037Seric buf[0] = '\0'; 86563753Seric #ifdef XDEBUG 86663753Seric checkfd012(during); 86763753Seric #endif 86814885Seric return (NULL); 86914885Seric } 870*68464Seric ev = setevent(timeout, readtimeout, 0); 87114885Seric } 87214885Seric 87314885Seric /* try to read */ 87415533Seric p = NULL; 87565190Seric while (!feof(fp) && !ferror(fp)) 8767942Seric { 8777942Seric errno = 0; 8787942Seric p = fgets(buf, siz, fp); 87965190Seric if (p != NULL || errno != EINTR) 88065186Seric break; 88165190Seric clearerr(fp); 88215533Seric } 88314885Seric 88414885Seric /* clear the event if it has not sprung */ 885*68464Seric clrevent(ev); 88614885Seric 88714885Seric /* clean up the books and exit */ 8888055Seric LineNumber++; 88915533Seric if (p == NULL) 89016880Seric { 89115533Seric buf[0] = '\0'; 89263753Seric if (TrafficLogFile != NULL) 89363753Seric fprintf(TrafficLogFile, "%05d <<< [EOF]\n", getpid()); 89416880Seric return (NULL); 89516880Seric } 89663753Seric if (TrafficLogFile != NULL) 89763753Seric fprintf(TrafficLogFile, "%05d <<< %s", getpid(), buf); 898*68464Seric if (SevenBitInput) 899*68464Seric { 90052106Seric for (p = buf; *p != '\0'; p++) 90152106Seric *p &= ~0200; 90267546Seric } 903*68464Seric else if (!HasEightBits) 90467546Seric { 905*68464Seric for (p = buf; *p != '\0'; p++) 906*68464Seric { 907*68464Seric if (bitset(0200, *p)) 908*68464Seric { 909*68464Seric HasEightBits = TRUE; 910*68464Seric break; 911*68464Seric } 912*68464Seric } 91367546Seric } 914*68464Seric return (buf); 9157685Seric } 9167685Seric 917*68464Seric static void 91866765Seric readtimeout(timeout) 91966765Seric time_t timeout; 9207685Seric { 921*68464Seric longjmp(CtxReadTimeout, 1); 9227685Seric } 9237786Seric /* 9247786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 9257786Seric ** 9267786Seric ** Parameters: 9277786Seric ** buf -- place to put result. 9287786Seric ** n -- bytes available. 9297786Seric ** f -- file to read from. 9307786Seric ** 9317786Seric ** Returns: 93257135Seric ** input line(s) on success, NULL on error or EOF. 93357135Seric ** This will normally be buf -- unless the line is too 93457135Seric ** long, when it will be xalloc()ed. 9357786Seric ** 9367786Seric ** Side Effects: 9377786Seric ** buf gets lines from f, with continuation lines (lines 9387786Seric ** with leading white space) appended. CRLF's are mapped 9397786Seric ** into single newlines. Any trailing NL is stripped. 9407786Seric */ 9417786Seric 9427786Seric char * 9437786Seric fgetfolded(buf, n, f) 9447786Seric char *buf; 9457786Seric register int n; 9467786Seric FILE *f; 9477786Seric { 9487786Seric register char *p = buf; 94957135Seric char *bp = buf; 9507786Seric register int i; 9517786Seric 9527786Seric n--; 95317350Seric while ((i = getc(f)) != EOF) 9547786Seric { 95517350Seric if (i == '\r') 95617350Seric { 95717350Seric i = getc(f); 95817350Seric if (i != '\n') 95917350Seric { 96017350Seric if (i != EOF) 96123105Seric (void) ungetc(i, f); 96217350Seric i = '\r'; 96317350Seric } 96417350Seric } 96557135Seric if (--n <= 0) 96657135Seric { 96757135Seric /* allocate new space */ 96857135Seric char *nbp; 96957135Seric int nn; 97057135Seric 97157135Seric nn = (p - bp); 97257232Seric if (nn < MEMCHUNKSIZE) 97357135Seric nn *= 2; 97457135Seric else 97557232Seric nn += MEMCHUNKSIZE; 97657135Seric nbp = xalloc(nn); 97757135Seric bcopy(bp, nbp, p - bp); 97857135Seric p = &nbp[p - bp]; 97957135Seric if (bp != buf) 98057135Seric free(bp); 98157135Seric bp = nbp; 98257135Seric n = nn - (p - bp); 98357135Seric } 98457135Seric *p++ = i; 98517350Seric if (i == '\n') 98617350Seric { 98717350Seric LineNumber++; 98817350Seric i = getc(f); 98917350Seric if (i != EOF) 99023105Seric (void) ungetc(i, f); 99117350Seric if (i != ' ' && i != '\t') 99252647Seric break; 99317350Seric } 9947786Seric } 99557135Seric if (p == bp) 99652647Seric return (NULL); 99752647Seric *--p = '\0'; 99857135Seric return (bp); 9997786Seric } 10007860Seric /* 10017886Seric ** CURTIME -- return current time. 10027886Seric ** 10037886Seric ** Parameters: 10047886Seric ** none. 10057886Seric ** 10067886Seric ** Returns: 10077886Seric ** the current time. 10087886Seric ** 10097886Seric ** Side Effects: 10107886Seric ** none. 10117886Seric */ 10127886Seric 10137886Seric time_t 10147886Seric curtime() 10157886Seric { 10167886Seric auto time_t t; 10177886Seric 10187886Seric (void) time(&t); 10197886Seric return (t); 10207886Seric } 10218264Seric /* 10228264Seric ** ATOBOOL -- convert a string representation to boolean. 10238264Seric ** 10248264Seric ** Defaults to "TRUE" 10258264Seric ** 10268264Seric ** Parameters: 10278264Seric ** s -- string to convert. Takes "tTyY" as true, 10288264Seric ** others as false. 10298264Seric ** 10308264Seric ** Returns: 10318264Seric ** A boolean representation of the string. 10328264Seric ** 10338264Seric ** Side Effects: 10348264Seric ** none. 10358264Seric */ 10368264Seric 10378264Seric bool 10388264Seric atobool(s) 10398264Seric register char *s; 10408264Seric { 104163833Seric if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 10428264Seric return (TRUE); 10438264Seric return (FALSE); 10448264Seric } 10459048Seric /* 10469048Seric ** ATOOCT -- convert a string representation to octal. 10479048Seric ** 10489048Seric ** Parameters: 10499048Seric ** s -- string to convert. 10509048Seric ** 10519048Seric ** Returns: 10529048Seric ** An integer representing the string interpreted as an 10539048Seric ** octal number. 10549048Seric ** 10559048Seric ** Side Effects: 10569048Seric ** none. 10579048Seric */ 10589048Seric 10599048Seric atooct(s) 10609048Seric register char *s; 10619048Seric { 10629048Seric register int i = 0; 10639048Seric 10649048Seric while (*s >= '0' && *s <= '7') 10659048Seric i = (i << 3) | (*s++ - '0'); 10669048Seric return (i); 10679048Seric } 10689376Seric /* 10699376Seric ** WAITFOR -- wait for a particular process id. 10709376Seric ** 10719376Seric ** Parameters: 10729376Seric ** pid -- process id to wait for. 10739376Seric ** 10749376Seric ** Returns: 10759376Seric ** status of pid. 10769376Seric ** -1 if pid never shows up. 10779376Seric ** 10789376Seric ** Side Effects: 10799376Seric ** none. 10809376Seric */ 10819376Seric 108264562Seric int 10839376Seric waitfor(pid) 10849376Seric int pid; 10859376Seric { 108664562Seric #ifdef WAITUNION 108764562Seric union wait st; 108864562Seric #else 10899376Seric auto int st; 109064562Seric #endif 10919376Seric int i; 10929376Seric 10939376Seric do 10949376Seric { 10959376Seric errno = 0; 10969376Seric i = wait(&st); 10979376Seric } while ((i >= 0 || errno == EINTR) && i != pid); 10989376Seric if (i < 0) 109964562Seric return -1; 110064562Seric #ifdef WAITUNION 110164562Seric return st.w_status; 110264562Seric #else 110364562Seric return st; 110464562Seric #endif 11059376Seric } 11069376Seric /* 110710685Seric ** BITINTERSECT -- tell if two bitmaps intersect 110810685Seric ** 110910685Seric ** Parameters: 111010685Seric ** a, b -- the bitmaps in question 111110685Seric ** 111210685Seric ** Returns: 111310685Seric ** TRUE if they have a non-null intersection 111410685Seric ** FALSE otherwise 111510685Seric ** 111610685Seric ** Side Effects: 111710685Seric ** none. 111810685Seric */ 111910685Seric 112010685Seric bool 112110685Seric bitintersect(a, b) 112210685Seric BITMAP a; 112310685Seric BITMAP b; 112410685Seric { 112510685Seric int i; 112610685Seric 112710685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 112810685Seric if ((a[i] & b[i]) != 0) 112910685Seric return (TRUE); 113010685Seric return (FALSE); 113110685Seric } 113210685Seric /* 113310685Seric ** BITZEROP -- tell if a bitmap is all zero 113410685Seric ** 113510685Seric ** Parameters: 113610685Seric ** map -- the bit map to check 113710685Seric ** 113810685Seric ** Returns: 113910685Seric ** TRUE if map is all zero. 114010685Seric ** FALSE if there are any bits set in map. 114110685Seric ** 114210685Seric ** Side Effects: 114310685Seric ** none. 114410685Seric */ 114510685Seric 114610685Seric bool 114710685Seric bitzerop(map) 114810685Seric BITMAP map; 114910685Seric { 115010685Seric int i; 115110685Seric 115210685Seric for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) 115310685Seric if (map[i] != 0) 115410685Seric return (FALSE); 115510685Seric return (TRUE); 115610685Seric } 115758247Seric /* 115858318Seric ** STRCONTAINEDIN -- tell if one string is contained in another 115958318Seric ** 116058318Seric ** Parameters: 116158318Seric ** a -- possible substring. 116258318Seric ** b -- possible superstring. 116358318Seric ** 116458318Seric ** Returns: 116558318Seric ** TRUE if a is contained in b. 116658318Seric ** FALSE otherwise. 116758318Seric */ 116858318Seric 116958318Seric bool 117058318Seric strcontainedin(a, b) 117158318Seric register char *a; 117258318Seric register char *b; 117358318Seric { 117465012Seric int la; 117565012Seric int lb; 117665012Seric int c; 117758318Seric 117865012Seric la = strlen(a); 117965012Seric lb = strlen(b); 118065012Seric c = *a; 118165012Seric if (isascii(c) && isupper(c)) 118265012Seric c = tolower(c); 118365012Seric for (; lb-- >= la; b++) 118458318Seric { 118565012Seric if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) 118665012Seric continue; 118765012Seric if (strncasecmp(a, b, la) == 0) 118858318Seric return TRUE; 118958318Seric } 119065012Seric return FALSE; 119158318Seric } 119263753Seric /* 119363753Seric ** CHECKFD012 -- check low numbered file descriptors 119463753Seric ** 119563753Seric ** File descriptors 0, 1, and 2 should be open at all times. 119663753Seric ** This routine verifies that, and fixes it if not true. 119763753Seric ** 119863753Seric ** Parameters: 119963753Seric ** where -- a tag printed if the assertion failed 120063753Seric ** 120163753Seric ** Returns: 120263753Seric ** none 120363753Seric */ 120463753Seric 120563753Seric checkfd012(where) 120663753Seric char *where; 120763753Seric { 120863753Seric #ifdef XDEBUG 120963753Seric register int i; 121063753Seric struct stat stbuf; 121163753Seric 121263753Seric for (i = 0; i < 3; i++) 121363753Seric { 121464735Seric if (fstat(i, &stbuf) < 0 && errno != EOPNOTSUPP) 121563753Seric { 121663753Seric /* oops.... */ 121763753Seric int fd; 121863753Seric 121963753Seric syserr("%s: fd %d not open", where, i); 122063753Seric fd = open("/dev/null", i == 0 ? O_RDONLY : O_WRONLY, 0666); 122163753Seric if (fd != i) 122263753Seric { 122363753Seric (void) dup2(fd, i); 122463753Seric (void) close(fd); 122563753Seric } 122663753Seric } 122763753Seric } 122863937Seric #endif /* XDEBUG */ 122963753Seric } 123064725Seric /* 123164725Seric ** PRINTOPENFDS -- print the open file descriptors (for debugging) 123264725Seric ** 123364725Seric ** Parameters: 123464725Seric ** logit -- if set, send output to syslog; otherwise 123564725Seric ** print for debugging. 123664725Seric ** 123764725Seric ** Returns: 123864725Seric ** none. 123964725Seric */ 124064725Seric 124164725Seric #include <netdb.h> 124264725Seric #include <arpa/inet.h> 124364725Seric 124464725Seric printopenfds(logit) 124564725Seric bool logit; 124664725Seric { 124764725Seric register int fd; 124864743Seric extern int DtableSize; 124964743Seric 125064743Seric for (fd = 0; fd < DtableSize; fd++) 125164743Seric dumpfd(fd, FALSE, logit); 125264743Seric } 125364743Seric /* 125464743Seric ** DUMPFD -- dump a file descriptor 125564743Seric ** 125664743Seric ** Parameters: 125764743Seric ** fd -- the file descriptor to dump. 125864743Seric ** printclosed -- if set, print a notification even if 125964743Seric ** it is closed; otherwise print nothing. 126064743Seric ** logit -- if set, send output to syslog instead of stdout. 126164743Seric */ 126264743Seric 126364743Seric dumpfd(fd, printclosed, logit) 126464743Seric int fd; 126564743Seric bool printclosed; 126664743Seric bool logit; 126764743Seric { 126864725Seric register struct hostent *hp; 126964725Seric register char *p; 127066747Seric char *fmtstr; 127164743Seric struct sockaddr_in sin; 127264743Seric auto int slen; 127364743Seric struct stat st; 127464725Seric char buf[200]; 127564725Seric 127664743Seric p = buf; 127764743Seric sprintf(p, "%3d: ", fd); 127864743Seric p += strlen(p); 127964743Seric 128064743Seric if (fstat(fd, &st) < 0) 128164725Seric { 128264743Seric if (printclosed || errno != EBADF) 128364743Seric { 128464743Seric sprintf(p, "CANNOT STAT (%s)", errstring(errno)); 128564743Seric goto printit; 128664743Seric } 128764743Seric return; 128864743Seric } 128964725Seric 129064743Seric slen = fcntl(fd, F_GETFL, NULL); 129164743Seric if (slen != -1) 129264743Seric { 129364743Seric sprintf(p, "fl=0x%x, ", slen); 129464743Seric p += strlen(p); 129564743Seric } 129664725Seric 129764743Seric sprintf(p, "mode=%o: ", st.st_mode); 129864743Seric p += strlen(p); 129964743Seric switch (st.st_mode & S_IFMT) 130064743Seric { 130164807Seric #ifdef S_IFSOCK 130264743Seric case S_IFSOCK: 130364743Seric sprintf(p, "SOCK "); 130464725Seric p += strlen(p); 130564743Seric slen = sizeof sin; 130664743Seric if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0) 130764743Seric sprintf(p, "(badsock)"); 130864743Seric else 130964725Seric { 1310*68464Seric hp = gethostbyaddr((char *) &sin.sin_addr, 1311*68464Seric INADDRSZ, AF_INET); 131264743Seric sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 131364743Seric : hp->h_name, ntohs(sin.sin_port)); 131464743Seric } 131564743Seric p += strlen(p); 131664743Seric sprintf(p, "->"); 131764743Seric p += strlen(p); 131864743Seric slen = sizeof sin; 131964743Seric if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0) 132064743Seric sprintf(p, "(badsock)"); 132164743Seric else 132264743Seric { 1323*68464Seric hp = gethostbyaddr((char *) &sin.sin_addr, 1324*68464Seric INADDRSZ, AF_INET); 132564743Seric sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr) 132664743Seric : hp->h_name, ntohs(sin.sin_port)); 132764743Seric } 132864743Seric break; 132964807Seric #endif 133064725Seric 133164743Seric case S_IFCHR: 133264743Seric sprintf(p, "CHR: "); 133364743Seric p += strlen(p); 133464743Seric goto defprint; 133564725Seric 133664743Seric case S_IFBLK: 133764743Seric sprintf(p, "BLK: "); 133864743Seric p += strlen(p); 133964743Seric goto defprint; 134064725Seric 134166252Seric #if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 134265378Seric case S_IFIFO: 134365378Seric sprintf(p, "FIFO: "); 134465378Seric p += strlen(p); 134565378Seric goto defprint; 134665378Seric #endif 134765378Seric 134865378Seric #ifdef S_IFDIR 134965378Seric case S_IFDIR: 135065378Seric sprintf(p, "DIR: "); 135165378Seric p += strlen(p); 135265378Seric goto defprint; 135365378Seric #endif 135465378Seric 135565378Seric #ifdef S_IFLNK 135665378Seric case S_IFLNK: 135765378Seric sprintf(p, "LNK: "); 135865378Seric p += strlen(p); 135965378Seric goto defprint; 136065378Seric #endif 136165378Seric 136264743Seric default: 136364725Seric defprint: 136466785Seric if (sizeof st.st_size > sizeof (long)) 136566751Seric fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%qd"; 136666747Seric else 136766751Seric fmtstr = "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld"; 136866747Seric sprintf(p, fmtstr, 136964743Seric major(st.st_dev), minor(st.st_dev), st.st_ino, 137064743Seric st.st_nlink, st.st_uid, st.st_gid, st.st_size); 137164743Seric break; 137264743Seric } 137364725Seric 137464743Seric printit: 137566748Seric #ifdef LOG 137664743Seric if (logit) 137765006Seric syslog(LOG_DEBUG, "%s", buf); 137864743Seric else 137966748Seric #endif 138064743Seric printf("%s\n", buf); 138164725Seric } 138265015Seric /* 138365015Seric ** SHORTENSTRING -- return short version of a string 138465015Seric ** 138565015Seric ** If the string is already short, just return it. If it is too 138665015Seric ** long, return the head and tail of the string. 138765015Seric ** 138865015Seric ** Parameters: 138965015Seric ** s -- the string to shorten. 139065015Seric ** m -- the max length of the string. 139165015Seric ** 139265015Seric ** Returns: 139365015Seric ** Either s or a short version of s. 139465015Seric */ 139565015Seric 139665015Seric #ifndef MAXSHORTSTR 139765055Seric # define MAXSHORTSTR 203 139865015Seric #endif 139965015Seric 140065015Seric char * 140165015Seric shortenstring(s, m) 140265015Seric register char *s; 140365015Seric int m; 140465015Seric { 140565015Seric int l; 140665015Seric static char buf[MAXSHORTSTR + 1]; 140765015Seric 140865015Seric l = strlen(s); 140965015Seric if (l < m) 141065015Seric return s; 141165015Seric if (m > MAXSHORTSTR) 141265015Seric m = MAXSHORTSTR; 141365015Seric else if (m < 10) 141465015Seric { 141565015Seric if (m < 5) 141665015Seric { 141765015Seric strncpy(buf, s, m); 141865015Seric buf[m] = '\0'; 141965015Seric return buf; 142065015Seric } 142165015Seric strncpy(buf, s, m - 3); 142265015Seric strcpy(buf + m - 3, "..."); 142365015Seric return buf; 142465015Seric } 142565015Seric m = (m - 3) / 2; 142665015Seric strncpy(buf, s, m); 142765015Seric strcpy(buf + m, "..."); 142865015Seric strcpy(buf + m + 3, s + l - m); 142965015Seric return buf; 143065015Seric } 143167848Seric /* 1432*68464Seric ** GET_COLUMN -- look up a Column in a line buffer 1433*68464Seric ** 1434*68464Seric ** Parameters: 1435*68464Seric ** line -- the raw text line to search. 1436*68464Seric ** col -- the column number to fetch. 1437*68464Seric ** delim -- the delimiter between columns. If null, 1438*68464Seric ** use white space. 1439*68464Seric ** buf -- the output buffer. 1440*68464Seric ** 1441*68464Seric ** Returns: 1442*68464Seric ** buf if successful. 1443*68464Seric ** NULL otherwise. 1444*68464Seric */ 1445*68464Seric 1446*68464Seric char * 1447*68464Seric get_column(line, col, delim, buf) 1448*68464Seric char line[]; 1449*68464Seric int col; 1450*68464Seric char delim; 1451*68464Seric char buf[]; 1452*68464Seric { 1453*68464Seric char *p; 1454*68464Seric char *begin, *end; 1455*68464Seric int i; 1456*68464Seric char delimbuf[3]; 1457*68464Seric 1458*68464Seric if (delim == '\0') 1459*68464Seric strcpy(delimbuf, "\t "); 1460*68464Seric else 1461*68464Seric { 1462*68464Seric delimbuf[0] = delim; 1463*68464Seric delimbuf[1] = '\0'; 1464*68464Seric } 1465*68464Seric 1466*68464Seric p = line; 1467*68464Seric if (*p == '\0') 1468*68464Seric return NULL; /* line empty */ 1469*68464Seric if (*p == delim && col == 0) 1470*68464Seric return NULL; /* first column empty */ 1471*68464Seric 1472*68464Seric begin = line; 1473*68464Seric 1474*68464Seric if (col == 0 && delim == '\0') 1475*68464Seric { 1476*68464Seric while (*begin && isspace(*begin)) 1477*68464Seric begin++; 1478*68464Seric } 1479*68464Seric 1480*68464Seric for (i = 0; i < col; i++) 1481*68464Seric { 1482*68464Seric if ((begin = strpbrk(begin, delimbuf)) == NULL) 1483*68464Seric return NULL; /* no such column */ 1484*68464Seric begin++; 1485*68464Seric if (delim == '\0') 1486*68464Seric { 1487*68464Seric while (*begin && isspace(*begin)) 1488*68464Seric begin++; 1489*68464Seric } 1490*68464Seric } 1491*68464Seric 1492*68464Seric end = strpbrk(begin, delimbuf); 1493*68464Seric if (end == NULL) 1494*68464Seric { 1495*68464Seric strcpy(buf, begin); 1496*68464Seric } 1497*68464Seric else 1498*68464Seric { 1499*68464Seric strncpy(buf, begin, end - begin); 1500*68464Seric buf[end - begin] = '\0'; 1501*68464Seric } 1502*68464Seric return buf; 1503*68464Seric } 1504*68464Seric /* 150568267Seric ** CLEANSTRCPY -- copy string keeping out bogus characters 150668267Seric ** 150768267Seric ** Parameters: 150868267Seric ** t -- "to" string. 150968267Seric ** f -- "from" string. 151068267Seric ** l -- length of space available in "to" string. 151168267Seric ** 151268267Seric ** Returns: 151368267Seric ** none. 151468267Seric */ 151568267Seric 151668267Seric void 151768267Seric cleanstrcpy(t, f, l) 151868267Seric register char *t; 151968267Seric register char *f; 152068267Seric int l; 152168267Seric { 152268281Seric #ifdef LOG 152368281Seric /* check for newlines and log if necessary */ 152468457Seric (void) denlstring(f, TRUE); 152568281Seric #endif 152668281Seric 152768267Seric l--; 152868267Seric while (l > 0 && *f != '\0') 152968267Seric { 153068267Seric if (isascii(*f) && 153168267Seric (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) 153268267Seric { 153368267Seric l--; 153468267Seric *t++ = *f; 153568267Seric } 153668267Seric f++; 153768267Seric } 153868267Seric *t = '\0'; 153968267Seric } 154068267Seric /* 154168267Seric ** DENLSTRING -- convert newlines in a string to spaces 154268267Seric ** 154368267Seric ** Parameters: 154468267Seric ** s -- the input string 154568457Seric ** logattacks -- if set, log attempted attacks. 154668267Seric ** 154768267Seric ** Returns: 154868267Seric ** A pointer to a version of the string with newlines 154968267Seric ** mapped to spaces. This should be copied. 155068267Seric */ 155168267Seric 155268267Seric char * 155368457Seric denlstring(s, logattacks) 155468267Seric char *s; 155568457Seric bool logattacks; 155668267Seric { 155768267Seric register char *p; 155868267Seric int l; 155968267Seric static char *bp = NULL; 156068267Seric static int bl = 0; 156168267Seric 156268267Seric if (strchr(s, '\n') == NULL) 156368267Seric return s; 156468267Seric 156568267Seric l = strlen(s) + 1; 156668267Seric if (bl < l) 156768267Seric { 156868267Seric /* allocate more space */ 156968267Seric if (bp != NULL) 157068267Seric free(bp); 157168267Seric bp = xalloc(l); 157268267Seric bl = l; 157368267Seric } 157468267Seric strcpy(bp, s); 157568267Seric for (p = bp; (p = strchr(p, '\n')) != NULL; ) 157668267Seric *p++ = ' '; 157768281Seric 1578*68464Seric /* 157968281Seric #ifdef LOG 158068457Seric if (logattacks) 158168457Seric { 158268457Seric syslog(LOG_NOTICE, "POSSIBLE ATTACK from %s: newline in string \"%s\"", 158368457Seric RealHostName == NULL ? "[UNKNOWN]" : RealHostName, 158468457Seric shortenstring(bp, 80)); 158568457Seric } 158668281Seric #endif 1587*68464Seric */ 158868281Seric 158968267Seric return bp; 159068267Seric } 1591