1 # include <stdio.h> 2 # include <sys/types.h> 3 # include <sys/stat.h> 4 # include <sysexits.h> 5 # include <errno.h> 6 # include <ctype.h> 7 # include "sendmail.h" 8 9 SCCSID(@(#)util.c 3.19 07/05/82); 10 11 /* 12 ** STRIPQUOTES -- Strip quotes & quote bits from a string. 13 ** 14 ** Runs through a string and strips off unquoted quote 15 ** characters and quote bits. This is done in place. 16 ** 17 ** Parameters: 18 ** s -- the string to strip. 19 ** qf -- if set, remove actual `` " '' characters 20 ** as well as the quote bits. 21 ** 22 ** Returns: 23 ** none. 24 ** 25 ** Side Effects: 26 ** none. 27 ** 28 ** Called By: 29 ** deliver 30 */ 31 32 stripquotes(s, qf) 33 char *s; 34 bool qf; 35 { 36 register char *p; 37 register char *q; 38 register char c; 39 40 if (s == NULL) 41 return; 42 43 for (p = q = s; (c = *p++) != '\0'; ) 44 { 45 if (c != '"' || !qf) 46 *q++ = c & 0177; 47 } 48 *q = '\0'; 49 } 50 /* 51 ** CAPITALIZE -- return a copy of a string, properly capitalized. 52 ** 53 ** Parameters: 54 ** s -- the string to capitalize. 55 ** 56 ** Returns: 57 ** a pointer to a properly capitalized string. 58 ** 59 ** Side Effects: 60 ** none. 61 */ 62 63 char * 64 capitalize(s) 65 register char *s; 66 { 67 static char buf[50]; 68 register char *p; 69 70 p = buf; 71 72 for (;;) 73 { 74 while (!isalpha(*s) && *s != '\0') 75 *p++ = *s++; 76 if (*s == '\0') 77 break; 78 *p++ = toupper(*s++); 79 while (isalpha(*s)) 80 *p++ = *s++; 81 } 82 83 *p = '\0'; 84 return (buf); 85 } 86 /* 87 ** XALLOC -- Allocate memory and bitch wildly on failure. 88 ** 89 ** THIS IS A CLUDGE. This should be made to give a proper 90 ** error -- but after all, what can we do? 91 ** 92 ** Parameters: 93 ** sz -- size of area to allocate. 94 ** 95 ** Returns: 96 ** pointer to data region. 97 ** 98 ** Side Effects: 99 ** Memory is allocated. 100 */ 101 102 char * 103 xalloc(sz) 104 register int sz; 105 { 106 register char *p; 107 108 p = malloc(sz); 109 if (p == NULL) 110 { 111 syserr("Out of memory!!"); 112 exit(EX_UNAVAILABLE); 113 } 114 return (p); 115 } 116 /* 117 ** NEWSTR -- make copy of string. 118 ** 119 ** Space is allocated for it using xalloc. 120 ** 121 ** Parameters: 122 ** string to copy. 123 ** 124 ** Returns: 125 ** pointer to new string. 126 ** 127 ** Side Effects: 128 ** none. 129 */ 130 131 char * 132 newstr(s) 133 register char *s; 134 { 135 register char *p; 136 137 p = xalloc(strlen(s) + 1); 138 (void) strcpy(p, s); 139 return (p); 140 } 141 /* 142 ** COPYPLIST -- copy list of pointers. 143 ** 144 ** This routine is the equivalent of newstr for lists of 145 ** pointers. 146 ** 147 ** Parameters: 148 ** list -- list of pointers to copy. 149 ** Must be NULL terminated. 150 ** copycont -- if TRUE, copy the contents of the vector 151 ** (which must be a string) also. 152 ** 153 ** Returns: 154 ** a copy of 'list'. 155 ** 156 ** Side Effects: 157 ** none. 158 */ 159 160 char ** 161 copyplist(list, copycont) 162 char **list; 163 bool copycont; 164 { 165 register char **vp; 166 register char **newvp; 167 168 for (vp = list; *vp != NULL; vp++) 169 continue; 170 171 vp++; 172 173 newvp = (char **) xalloc((vp - list) * sizeof *vp); 174 bmove((char *) list, (char *) newvp, (vp - list) * sizeof *vp); 175 176 if (copycont) 177 { 178 for (vp = newvp; *vp != NULL; vp++) 179 *vp = newstr(*vp); 180 } 181 182 return (newvp); 183 } 184 /* 185 ** PRINTAV -- print argument vector. 186 ** 187 ** Parameters: 188 ** av -- argument vector. 189 ** 190 ** Returns: 191 ** none. 192 ** 193 ** Side Effects: 194 ** prints av. 195 */ 196 197 # ifdef DEBUG 198 printav(av) 199 register char **av; 200 { 201 while (*av != NULL) 202 { 203 printf("\t%08x=", *av); 204 xputs(*av++); 205 putchar('\n'); 206 } 207 } 208 # endif DEBUG 209 /* 210 ** LOWER -- turn letter into lower case. 211 ** 212 ** Parameters: 213 ** c -- character to turn into lower case. 214 ** 215 ** Returns: 216 ** c, in lower case. 217 ** 218 ** Side Effects: 219 ** none. 220 */ 221 222 char 223 lower(c) 224 register char c; 225 { 226 if (isascii(c) && isupper(c)) 227 c = c - 'A' + 'a'; 228 return (c); 229 } 230 /* 231 ** XPUTS -- put string doing control escapes. 232 ** 233 ** Parameters: 234 ** s -- string to put. 235 ** 236 ** Returns: 237 ** none. 238 ** 239 ** Side Effects: 240 ** output to stdout 241 */ 242 243 # ifdef DEBUG 244 xputs(s) 245 register char *s; 246 { 247 register char c; 248 249 while ((c = *s++) != '\0') 250 { 251 if (!isascii(c)) 252 { 253 putchar('\\'); 254 c &= 0177; 255 } 256 if (iscntrl(c)) 257 { 258 putchar('^'); 259 c |= 0100; 260 } 261 putchar(c); 262 } 263 (void) fflush(stdout); 264 } 265 # endif DEBUG 266 /* 267 ** MAKELOWER -- Translate a line into lower case 268 ** 269 ** Parameters: 270 ** p -- the string to translate. If NULL, return is 271 ** immediate. 272 ** 273 ** Returns: 274 ** none. 275 ** 276 ** Side Effects: 277 ** String pointed to by p is translated to lower case. 278 ** 279 ** Called By: 280 ** parse 281 */ 282 283 makelower(p) 284 register char *p; 285 { 286 register char c; 287 288 if (p == NULL) 289 return; 290 for (; (c = *p) != '\0'; p++) 291 if (isascii(c) && isupper(c)) 292 *p = c - 'A' + 'a'; 293 } 294 /* 295 ** SAMEWORD -- return TRUE if the words are the same 296 ** 297 ** Ignores case. 298 ** 299 ** Parameters: 300 ** a, b -- the words to compare. 301 ** 302 ** Returns: 303 ** TRUE if a & b match exactly (modulo case) 304 ** FALSE otherwise. 305 ** 306 ** Side Effects: 307 ** none. 308 */ 309 310 bool 311 sameword(a, b) 312 register char *a, *b; 313 { 314 while (lower(*a) == lower(*b)) 315 { 316 if (*a == '\0') 317 return (TRUE); 318 a++; 319 b++; 320 } 321 return (FALSE); 322 } 323 /* 324 ** CLEAR -- clear a block of memory 325 ** 326 ** Parameters: 327 ** p -- location to clear. 328 ** l -- number of bytes to clear. 329 ** 330 ** Returns: 331 ** none. 332 ** 333 ** Side Effects: 334 ** none. 335 */ 336 337 clear(p, l) 338 register char *p; 339 register int l; 340 { 341 while (l-- > 0) 342 *p++ = 0; 343 } 344 /* 345 ** BUILDFNAME -- build full name from gecos style entry. 346 ** 347 ** This routine interprets the strange entry that would appear 348 ** in the GECOS field of the password file. 349 ** 350 ** Parameters: 351 ** p -- name to build. 352 ** login -- the login name of this user (for &). 353 ** buf -- place to put the result. 354 ** 355 ** Returns: 356 ** none. 357 ** 358 ** Side Effects: 359 ** none. 360 */ 361 362 buildfname(p, login, buf) 363 register char *p; 364 char *login; 365 char *buf; 366 { 367 register char *bp = buf; 368 369 if (*p == '*') 370 p++; 371 while (*p != '\0' && *p != ',' && *p != ';' && *p != '%') 372 { 373 if (*p == '&') 374 { 375 (void) strcpy(bp, login); 376 *bp = toupper(*bp); 377 while (*bp != '\0') 378 bp++; 379 p++; 380 } 381 else 382 *bp++ = *p++; 383 } 384 *bp = '\0'; 385 } 386 /* 387 ** SAFEFILE -- return true if a file exists and is safe for a user. 388 ** 389 ** Parameters: 390 ** fn -- filename to check. 391 ** uid -- uid to compare against. 392 ** mode -- mode bits that must match. 393 ** 394 ** Returns: 395 ** TRUE if fn exists, is owned by uid, and matches mode. 396 ** FALSE otherwise. 397 ** 398 ** Side Effects: 399 ** none. 400 */ 401 402 bool 403 safefile(fn, uid, mode) 404 char *fn; 405 int uid; 406 int mode; 407 { 408 struct stat stbuf; 409 410 if (stat(fn, &stbuf) >= 0 && stbuf.st_uid == uid && 411 (stbuf.st_mode & mode) == mode) 412 return (TRUE); 413 return (FALSE); 414 } 415 /* 416 ** FIXCRLF -- fix <CR><LF> in line. 417 ** 418 ** Looks for the <CR><LF> combination and turns it into the 419 ** UNIX canonical <NL> character. It only takes one line, 420 ** i.e., it is assumed that the first <NL> found is the end 421 ** of the line. 422 ** 423 ** Parameters: 424 ** line -- the line to fix. 425 ** stripnl -- if true, strip the newline also. 426 ** 427 ** Returns: 428 ** none. 429 ** 430 ** Side Effects: 431 ** line is changed in place. 432 */ 433 434 fixcrlf(line, stripnl) 435 char *line; 436 bool stripnl; 437 { 438 register char *p; 439 440 p = index(line, '\n'); 441 if (p == NULL) 442 return; 443 if (p[-1] == '\r') 444 p--; 445 if (!stripnl) 446 *p++ = '\n'; 447 *p = '\0'; 448 } 449 /* 450 ** SYSLOG -- fake entry to fool lint 451 */ 452 453 # ifdef LOG 454 # ifdef lint 455 456 /*VARARGS2*/ 457 syslog(pri, fmt, args) 458 int pri; 459 char *fmt; 460 { 461 pri = *fmt; 462 args = pri; 463 pri = args; 464 } 465 466 # endif lint 467 # endif LOG 468 /* 469 ** DFOPEN -- determined file open 470 ** 471 ** This routine has the semantics of fopen, except that it will 472 ** keep trying a few times to make this happen. The idea is that 473 ** on very loaded systems, we may run out of resources (inodes, 474 ** whatever), so this tries to get around it. 475 */ 476 477 FILE * 478 dfopen(filename, mode) 479 char *filename; 480 char *mode; 481 { 482 register int tries; 483 register FILE *fp; 484 extern int errno; 485 486 for (tries = 0; tries < 10; tries++) 487 { 488 sleep(10 * tries); 489 errno = 0; 490 fp = fopen(filename, mode); 491 if (fp != NULL || errno != ENFILE) 492 break; 493 } 494 return (fp); 495 } 496 /* 497 ** PUTLINE -- put a line like fputs obeying SMTP conventions 498 ** 499 ** Parameters: 500 ** l -- line to put. 501 ** fp -- file to put it onto. 502 ** fullsmtp -- if set, obey strictest SMTP conventions. 503 ** 504 ** Returns: 505 ** none 506 ** 507 ** Side Effects: 508 ** output of l to fp. 509 */ 510 511 # define SMTPLINELIM 120 /* maximum line length */ 512 513 putline(l, fp, fullsmtp) 514 char *l; 515 FILE *fp; 516 bool fullsmtp; 517 { 518 register char *p; 519 520 if (!fullsmtp) 521 { 522 fputs(l, fp); 523 return; 524 } 525 526 /* find the end of the line */ 527 p = index(l, '\n'); 528 if (p == NULL) 529 p = &l[strlen(l)]; 530 531 /* check for line overflow */ 532 while (p - l > SMTPLINELIM) 533 { 534 register char *q = &l[SMTPLINELIM - 1]; 535 char svchar = *q; 536 537 *q = '\0'; 538 fputs(l, fp); 539 fputs("!\r\n", fp); 540 *q = svchar; 541 l = q; 542 } 543 544 /* output last part */ 545 *p = '\0'; 546 fputs(l, fp); 547 fputs("\r\n", fp); 548 *p = '\n'; 549 } 550 /* 551 ** TICK -- take a clock tick 552 ** 553 ** Someday this will have to do more complex event scheduling. 554 ** 555 ** Parameters: 556 ** none. 557 ** 558 ** Returns: 559 ** non-local through TickFrame. 560 ** 561 ** Side Effects: 562 ** none. 563 */ 564 565 tick() 566 { 567 # ifdef DEBUG 568 if (Debug > 0) 569 printf("tick\n"); 570 # endif DEBUG 571 longjmp(TickFrame, 1); 572 } 573