13151Seric # include <stdio.h> 24538Seric # include <sys/types.h> 34538Seric # include <sys/stat.h> 4298Seric # include <sysexits.h> 56890Seric # include <errno.h> 62900Seric # include <ctype.h> 76890Seric # include "sendmail.h" 8298Seric 9*7812Seric SCCSID(@(#)util.c 3.25 08/22/82); 10409Seric 11298Seric /* 12298Seric ** STRIPQUOTES -- Strip quotes & quote bits from a string. 13298Seric ** 14298Seric ** Runs through a string and strips off unquoted quote 15298Seric ** characters and quote bits. This is done in place. 16298Seric ** 17298Seric ** Parameters: 18298Seric ** s -- the string to strip. 194101Seric ** qf -- if set, remove actual `` " '' characters 204101Seric ** as well as the quote bits. 21298Seric ** 22298Seric ** Returns: 23298Seric ** none. 24298Seric ** 25298Seric ** Side Effects: 26298Seric ** none. 27298Seric ** 28298Seric ** Called By: 29298Seric ** deliver 30298Seric */ 31298Seric 324101Seric stripquotes(s, qf) 33298Seric char *s; 344101Seric bool qf; 35298Seric { 36298Seric register char *p; 37298Seric register char *q; 38298Seric register char c; 39298Seric 404101Seric if (s == NULL) 414101Seric return; 424101Seric 43298Seric for (p = q = s; (c = *p++) != '\0'; ) 44298Seric { 454101Seric if (c != '"' || !qf) 46298Seric *q++ = c & 0177; 47298Seric } 48298Seric *q = '\0'; 49298Seric } 50298Seric /* 512900Seric ** CAPITALIZE -- return a copy of a string, properly capitalized. 522900Seric ** 532900Seric ** Parameters: 542900Seric ** s -- the string to capitalize. 552900Seric ** 562900Seric ** Returns: 572900Seric ** a pointer to a properly capitalized string. 582900Seric ** 592900Seric ** Side Effects: 602900Seric ** none. 612900Seric */ 622900Seric 632900Seric char * 642900Seric capitalize(s) 652900Seric register char *s; 662900Seric { 672900Seric static char buf[50]; 682900Seric register char *p; 692900Seric 702900Seric p = buf; 712900Seric 722900Seric for (;;) 732900Seric { 742900Seric while (!isalpha(*s) && *s != '\0') 752900Seric *p++ = *s++; 762900Seric if (*s == '\0') 772900Seric break; 782900Seric *p++ = toupper(*s++); 792900Seric while (isalpha(*s)) 802900Seric *p++ = *s++; 812900Seric } 822900Seric 832900Seric *p = '\0'; 842900Seric return (buf); 852900Seric } 862900Seric /* 87298Seric ** XALLOC -- Allocate memory and bitch wildly on failure. 88298Seric ** 89298Seric ** THIS IS A CLUDGE. This should be made to give a proper 90298Seric ** error -- but after all, what can we do? 91298Seric ** 92298Seric ** Parameters: 93298Seric ** sz -- size of area to allocate. 94298Seric ** 95298Seric ** Returns: 96298Seric ** pointer to data region. 97298Seric ** 98298Seric ** Side Effects: 99298Seric ** Memory is allocated. 100298Seric */ 101298Seric 102298Seric char * 103298Seric xalloc(sz) 1047007Seric register int sz; 105298Seric { 106298Seric register char *p; 107298Seric 108298Seric p = malloc(sz); 109298Seric if (p == NULL) 110298Seric { 111298Seric syserr("Out of memory!!"); 1121598Seric exit(EX_UNAVAILABLE); 113298Seric } 114298Seric return (p); 115298Seric } 116298Seric /* 1172900Seric ** NEWSTR -- make copy of string. 1182900Seric ** 1192900Seric ** Space is allocated for it using xalloc. 1202900Seric ** 1212900Seric ** Parameters: 1222900Seric ** string to copy. 1232900Seric ** 1242900Seric ** Returns: 1252900Seric ** pointer to new string. 1262900Seric ** 1272900Seric ** Side Effects: 1282900Seric ** none. 1292900Seric */ 1302900Seric 1312900Seric char * 1322900Seric newstr(s) 1332900Seric register char *s; 1342900Seric { 1352900Seric register char *p; 1362900Seric 1377007Seric p = xalloc(strlen(s) + 1); 1387007Seric (void) strcpy(p, s); 1392900Seric return (p); 1402900Seric } 1413151Seric /* 1423151Seric ** COPYPLIST -- copy list of pointers. 1433151Seric ** 1443151Seric ** This routine is the equivalent of newstr for lists of 1453151Seric ** pointers. 1463151Seric ** 1473151Seric ** Parameters: 1483151Seric ** list -- list of pointers to copy. 1493151Seric ** Must be NULL terminated. 1503151Seric ** copycont -- if TRUE, copy the contents of the vector 1513151Seric ** (which must be a string) also. 1523151Seric ** 1533151Seric ** Returns: 1543151Seric ** a copy of 'list'. 1553151Seric ** 1563151Seric ** Side Effects: 1573151Seric ** none. 1583151Seric */ 1593151Seric 1603151Seric char ** 1613151Seric copyplist(list, copycont) 1623151Seric char **list; 1633151Seric bool copycont; 1643151Seric { 1653151Seric register char **vp; 1663151Seric register char **newvp; 1673151Seric 1683151Seric for (vp = list; *vp != NULL; vp++) 1693151Seric continue; 1703151Seric 1713151Seric vp++; 1723151Seric 1737007Seric newvp = (char **) xalloc((vp - list) * sizeof *vp); 1744086Seric bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp); 1753151Seric 1763151Seric if (copycont) 1773151Seric { 1783151Seric for (vp = newvp; *vp != NULL; vp++) 1793151Seric *vp = newstr(*vp); 1803151Seric } 1813151Seric 1823151Seric return (newvp); 1833151Seric } 1843151Seric /* 1853151Seric ** PRINTAV -- print argument vector. 1863151Seric ** 1873151Seric ** Parameters: 1883151Seric ** av -- argument vector. 1893151Seric ** 1903151Seric ** Returns: 1913151Seric ** none. 1923151Seric ** 1933151Seric ** Side Effects: 1943151Seric ** prints av. 1953151Seric */ 1963151Seric 1973151Seric # ifdef DEBUG 1983151Seric printav(av) 1993151Seric register char **av; 2003151Seric { 2013151Seric while (*av != NULL) 2023151Seric { 2033151Seric printf("\t%08x=", *av); 2043151Seric xputs(*av++); 2053151Seric putchar('\n'); 2063151Seric } 2073151Seric } 2083151Seric # endif DEBUG 2093151Seric /* 2103151Seric ** LOWER -- turn letter into lower case. 2113151Seric ** 2123151Seric ** Parameters: 2133151Seric ** c -- character to turn into lower case. 2143151Seric ** 2153151Seric ** Returns: 2163151Seric ** c, in lower case. 2173151Seric ** 2183151Seric ** Side Effects: 2193151Seric ** none. 2203151Seric */ 2213151Seric 2223151Seric char 2233151Seric lower(c) 2243151Seric register char c; 2253151Seric { 2263151Seric if (isascii(c) && isupper(c)) 2273151Seric c = c - 'A' + 'a'; 2283151Seric return (c); 2293151Seric } 2303151Seric /* 2313151Seric ** XPUTS -- put string doing control escapes. 2323151Seric ** 2333151Seric ** Parameters: 2343151Seric ** s -- string to put. 2353151Seric ** 2363151Seric ** Returns: 2373151Seric ** none. 2383151Seric ** 2393151Seric ** Side Effects: 2403151Seric ** output to stdout 2413151Seric */ 2423151Seric 2433151Seric # ifdef DEBUG 2443151Seric xputs(s) 2453151Seric register char *s; 2463151Seric { 2473151Seric register char c; 2483151Seric 2493151Seric while ((c = *s++) != '\0') 2503151Seric { 2513151Seric if (!isascii(c)) 2523151Seric { 2533151Seric putchar('\\'); 2543151Seric c &= 0177; 2553151Seric } 2563151Seric if (iscntrl(c)) 2573151Seric { 2583151Seric putchar('^'); 2593151Seric c |= 0100; 2603151Seric } 2613151Seric putchar(c); 2623151Seric } 2634086Seric (void) fflush(stdout); 2643151Seric } 2653151Seric # endif DEBUG 2663151Seric /* 2673151Seric ** MAKELOWER -- Translate a line into lower case 2683151Seric ** 2693151Seric ** Parameters: 2703151Seric ** p -- the string to translate. If NULL, return is 2713151Seric ** immediate. 2723151Seric ** 2733151Seric ** Returns: 2743151Seric ** none. 2753151Seric ** 2763151Seric ** Side Effects: 2773151Seric ** String pointed to by p is translated to lower case. 2783151Seric ** 2793151Seric ** Called By: 2803151Seric ** parse 2813151Seric */ 2823151Seric 2833151Seric makelower(p) 2843151Seric register char *p; 2853151Seric { 2863151Seric register char c; 2873151Seric 2883151Seric if (p == NULL) 2893151Seric return; 2903151Seric for (; (c = *p) != '\0'; p++) 2913151Seric if (isascii(c) && isupper(c)) 2923151Seric *p = c - 'A' + 'a'; 2933151Seric } 2944059Seric /* 2954059Seric ** SAMEWORD -- return TRUE if the words are the same 2964059Seric ** 2974059Seric ** Ignores case. 2984059Seric ** 2994059Seric ** Parameters: 3004059Seric ** a, b -- the words to compare. 3014059Seric ** 3024059Seric ** Returns: 3034059Seric ** TRUE if a & b match exactly (modulo case) 3044059Seric ** FALSE otherwise. 3054059Seric ** 3064059Seric ** Side Effects: 3074059Seric ** none. 3084059Seric */ 3094059Seric 3104059Seric bool 3114059Seric sameword(a, b) 3124059Seric register char *a, *b; 3134059Seric { 3144059Seric while (lower(*a) == lower(*b)) 3154059Seric { 3164059Seric if (*a == '\0') 3174059Seric return (TRUE); 3184059Seric a++; 3194059Seric b++; 3204059Seric } 3214059Seric return (FALSE); 3224059Seric } 3234086Seric /* 3244101Seric ** CLEAR -- clear a block of memory 3254101Seric ** 3264101Seric ** Parameters: 3274101Seric ** p -- location to clear. 3284101Seric ** l -- number of bytes to clear. 3294101Seric ** 3304101Seric ** Returns: 3314101Seric ** none. 3324101Seric ** 3334101Seric ** Side Effects: 3344101Seric ** none. 3354101Seric */ 3364101Seric 3374101Seric clear(p, l) 3384101Seric register char *p; 3394101Seric register int l; 3404101Seric { 3414101Seric while (l-- > 0) 3424101Seric *p++ = 0; 3434101Seric } 3444101Seric /* 3455196Seric ** BUILDFNAME -- build full name from gecos style entry. 3464375Seric ** 3475196Seric ** This routine interprets the strange entry that would appear 3485196Seric ** in the GECOS field of the password file. 3495196Seric ** 3504375Seric ** Parameters: 3515196Seric ** p -- name to build. 3525196Seric ** login -- the login name of this user (for &). 3535196Seric ** buf -- place to put the result. 3544375Seric ** 3554375Seric ** Returns: 3564375Seric ** none. 3574375Seric ** 3584375Seric ** Side Effects: 3594375Seric ** none. 3604375Seric */ 3614375Seric 3625196Seric buildfname(p, login, buf) 3635196Seric register char *p; 3645196Seric char *login; 3654375Seric char *buf; 3664375Seric { 3674375Seric register char *bp = buf; 3684375Seric 3694438Seric if (*p == '*') 3704438Seric p++; 3716278Seric while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 3724375Seric { 3734375Seric if (*p == '&') 3744375Seric { 3755196Seric (void) strcpy(bp, login); 3764375Seric *bp = toupper(*bp); 3774375Seric while (*bp != '\0') 3784375Seric bp++; 3794375Seric p++; 3804375Seric } 3814375Seric else 3824375Seric *bp++ = *p++; 3834375Seric } 3844375Seric *bp = '\0'; 3854375Seric } 3864375Seric /* 3874538Seric ** SAFEFILE -- return true if a file exists and is safe for a user. 3884538Seric ** 3894538Seric ** Parameters: 3904538Seric ** fn -- filename to check. 3914538Seric ** uid -- uid to compare against. 3924538Seric ** mode -- mode bits that must match. 3934538Seric ** 3944538Seric ** Returns: 3954538Seric ** TRUE if fn exists, is owned by uid, and matches mode. 3964538Seric ** FALSE otherwise. 3974538Seric ** 3984538Seric ** Side Effects: 3994538Seric ** none. 4004538Seric */ 4014538Seric 4024538Seric bool 4034538Seric safefile(fn, uid, mode) 4044538Seric char *fn; 4054538Seric int uid; 4064538Seric int mode; 4074538Seric { 4084538Seric struct stat stbuf; 4094538Seric 4104538Seric if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 4114538Seric (stbuf.st_mode & mode) == mode) 4124538Seric return (TRUE); 4134538Seric return (FALSE); 4144538Seric } 4154538Seric /* 4164557Seric ** FIXCRLF -- fix <CR><LF> in line. 4174557Seric ** 4184557Seric ** Looks for the <CR><LF> combination and turns it into the 4194557Seric ** UNIX canonical <NL> character. It only takes one line, 4204557Seric ** i.e., it is assumed that the first <NL> found is the end 4214557Seric ** of the line. 4224557Seric ** 4234557Seric ** Parameters: 4244557Seric ** line -- the line to fix. 4254557Seric ** stripnl -- if true, strip the newline also. 4264557Seric ** 4274557Seric ** Returns: 4284557Seric ** none. 4294557Seric ** 4304557Seric ** Side Effects: 4314557Seric ** line is changed in place. 4324557Seric */ 4334557Seric 4344557Seric fixcrlf(line, stripnl) 4354557Seric char *line; 4364557Seric bool stripnl; 4374557Seric { 4384557Seric register char *p; 4394557Seric 4404557Seric p = index(line, '\n'); 4414557Seric if (p == NULL) 4424557Seric return; 4434794Seric if (p[-1] == '\r') 4444557Seric p--; 4454557Seric if (!stripnl) 4464557Seric *p++ = '\n'; 4474557Seric *p = '\0'; 4484557Seric } 4494557Seric /* 4504086Seric ** SYSLOG -- fake entry to fool lint 4514086Seric */ 4524086Seric 4534086Seric # ifdef LOG 4544086Seric # ifdef lint 4554086Seric 4564086Seric /*VARARGS2*/ 4574086Seric syslog(pri, fmt, args) 4584086Seric int pri; 4594086Seric char *fmt; 4604086Seric { 4614086Seric pri = *fmt; 4624086Seric args = pri; 4634086Seric pri = args; 4644086Seric } 4654086Seric 4664086Seric # endif lint 4674086Seric # endif LOG 4686890Seric /* 4696890Seric ** DFOPEN -- determined file open 4706890Seric ** 4716890Seric ** This routine has the semantics of fopen, except that it will 4726890Seric ** keep trying a few times to make this happen. The idea is that 4736890Seric ** on very loaded systems, we may run out of resources (inodes, 4746890Seric ** whatever), so this tries to get around it. 4756890Seric */ 4766890Seric 4776890Seric FILE * 4786890Seric dfopen(filename, mode) 4796890Seric char *filename; 4806890Seric char *mode; 4816890Seric { 4826890Seric register int tries; 4836890Seric register FILE *fp; 4846890Seric extern int errno; 4856890Seric 4866890Seric for (tries = 0; tries < 10; tries++) 4876890Seric { 4886890Seric sleep(10 * tries); 4896890Seric errno = 0; 4906890Seric fp = fopen(filename, mode); 4916890Seric if (fp != NULL || errno != ENFILE) 4926890Seric break; 4936890Seric } 4946890Seric return (fp); 4956890Seric } 4967124Seric /* 4977124Seric ** PUTLINE -- put a line like fputs obeying SMTP conventions 4987124Seric ** 4997753Seric ** This routine always guarantees outputing a newline (or CRLF, 5007753Seric ** as appropriate) at the end of the string. 5017753Seric ** 5027124Seric ** Parameters: 5037124Seric ** l -- line to put. 5047124Seric ** fp -- file to put it onto. 5057124Seric ** fullsmtp -- if set, obey strictest SMTP conventions. 5067124Seric ** 5077124Seric ** Returns: 5087124Seric ** none 5097124Seric ** 5107124Seric ** Side Effects: 5117124Seric ** output of l to fp. 5127124Seric */ 5137124Seric 5147753Seric # define SMTPLINELIM 990 /* maximum line length */ 5157124Seric 5167124Seric putline(l, fp, fullsmtp) 5177753Seric register char *l; 5187124Seric FILE *fp; 5197124Seric bool fullsmtp; 5207124Seric { 5217124Seric register char *p; 5227753Seric char svchar; 5237124Seric 5247753Seric do 5257124Seric { 5267753Seric /* find the end of the line */ 5277753Seric p = index(l, '\n'); 5287753Seric if (p == NULL) 5297753Seric p = &l[strlen(l)]; 5307124Seric 5317753Seric /* check for line overflow */ 5327753Seric while (fullsmtp && (p - l) > SMTPLINELIM) 5337753Seric { 5347753Seric register char *q = &l[SMTPLINELIM - 1]; 5357124Seric 5367753Seric svchar = *q; 5377753Seric *q = '\0'; 5387753Seric fputs(l, fp); 5397753Seric fputs("!\r\n", fp); 5407753Seric *q = svchar; 5417753Seric l = q; 5427753Seric } 5437124Seric 5447753Seric /* output last part */ 5457753Seric svchar = *p; 5467753Seric *p = '\0'; 5477124Seric fputs(l, fp); 5487753Seric if (fullsmtp) 5497753Seric fputc('\r', fp); 5507753Seric fputc('\n', fp); 5517753Seric *p = svchar; 5527753Seric l = p; 5537753Seric if (*l == '\n') 5547753Seric l++; 5557753Seric } while (l[0] != '\0'); 5567124Seric } 5577676Seric /* 5587676Seric ** XUNLINK -- unlink a file, doing logging as appropriate. 5597676Seric ** 5607676Seric ** Parameters: 5617676Seric ** f -- name of file to unlink. 5627676Seric ** 5637676Seric ** Returns: 5647676Seric ** none. 5657676Seric ** 5667676Seric ** Side Effects: 5677676Seric ** f is unlinked. 5687676Seric */ 5697676Seric 5707676Seric xunlink(f) 5717676Seric char *f; 5727676Seric { 5737676Seric register int i; 5747676Seric 5757676Seric # ifdef LOG 5767676Seric if (LogLevel > 20) 577*7812Seric syslog(LOG_DEBUG, "%s: unlink %s\n", CurEnv->e_id, f); 5787676Seric # endif LOG 5797676Seric 5807676Seric i = unlink(f); 5817676Seric # ifdef LOG 5827676Seric if (i < 0 && LogLevel > 21) 5837676Seric syslog(LOG_DEBUG, "%s: unlink-fail %e"); 5847676Seric # endif LOG 5857676Seric } 5867685Seric /* 5877685Seric ** SFGETS -- "safe" fgets -- times out. 5887685Seric ** 5897685Seric ** Parameters: 5907685Seric ** buf -- place to put the input line. 5917685Seric ** siz -- size of buf. 5927685Seric ** fp -- file to read from. 5937685Seric ** 5947685Seric ** Returns: 5957685Seric ** NULL on error (including timeout). 5967685Seric ** buf otherwise. 5977685Seric ** 5987685Seric ** Side Effects: 5997685Seric ** none. 6007685Seric */ 6017685Seric 6027685Seric jmp_buf TimeoFrame; 6037685Seric 6047685Seric char * 6057685Seric sfgets(buf, siz, fp) 6067685Seric char *buf; 6077685Seric int siz; 6087685Seric FILE *fp; 6097685Seric { 6107685Seric register EVENT *ev; 6117685Seric register char *p; 6127685Seric extern readtimeout(); 6137685Seric 6147685Seric ev = setevent(ReadTimeout, readtimeout, 0); 6157685Seric if (setjmp(TimeoFrame) != 0) 6167685Seric return (NULL); 6177685Seric p = fgets(buf, siz, fp); 6187685Seric clrevent(ev); 6197685Seric return (p); 6207685Seric } 6217685Seric 6227685Seric static 6237685Seric readtimeout() 6247685Seric { 6257685Seric longjmp(TimeoFrame, 1); 6267685Seric } 6277786Seric /* 6287786Seric ** FGETFOLDED -- like fgets, but know about folded lines. 6297786Seric ** 6307786Seric ** Parameters: 6317786Seric ** buf -- place to put result. 6327786Seric ** n -- bytes available. 6337786Seric ** f -- file to read from. 6347786Seric ** 6357786Seric ** Returns: 6367786Seric ** buf on success, NULL on error or EOF. 6377786Seric ** 6387786Seric ** Side Effects: 6397786Seric ** buf gets lines from f, with continuation lines (lines 6407786Seric ** with leading white space) appended. CRLF's are mapped 6417786Seric ** into single newlines. Any trailing NL is stripped. 6427786Seric */ 6437786Seric 6447786Seric char * 6457786Seric fgetfolded(buf, n, f) 6467786Seric char *buf; 6477786Seric register int n; 6487786Seric FILE *f; 6497786Seric { 6507786Seric register char *p = buf; 6517786Seric register int i; 6527786Seric 6537786Seric n--; 6547786Seric while (fgets(p, n, f) != NULL) 6557786Seric { 6567786Seric fixcrlf(p, TRUE); 6577786Seric i = fgetc(f); 6587786Seric if (i != EOF) 6597786Seric ungetc(i, f); 6607786Seric if (i != ' ' && i != '\t') 6617786Seric return (buf); 6627786Seric i = strlen(p); 6637786Seric p += i; 6647786Seric *p++ = '\n'; 6657786Seric n -= i + 1; 6667786Seric } 6677786Seric return (NULL); 6687786Seric } 669