[12553] | 1 | /* |
---|
| 2 | * Copyright (c) 1998 Sendmail, Inc. All rights reserved. |
---|
| 3 | * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. |
---|
| 4 | * Copyright (c) 1988, 1993 |
---|
| 5 | * The Regents of the University of California. All rights reserved. |
---|
| 6 | * |
---|
| 7 | * By using this file, you agree to the terms and conditions set |
---|
| 8 | * forth in the LICENSE file which can be found at the top level of |
---|
| 9 | * the sendmail distribution. |
---|
| 10 | * |
---|
| 11 | */ |
---|
| 12 | |
---|
| 13 | #ifndef lint |
---|
| 14 | static char sccsid[] = "@(#)util.c 8.168 (Berkeley) 1/21/1999"; |
---|
| 15 | #endif /* not lint */ |
---|
| 16 | |
---|
| 17 | # include "sendmail.h" |
---|
| 18 | # include <sysexits.h> |
---|
| 19 | /* |
---|
| 20 | ** STRIPQUOTES -- Strip quotes & quote bits from a string. |
---|
| 21 | ** |
---|
| 22 | ** Runs through a string and strips off unquoted quote |
---|
| 23 | ** characters and quote bits. This is done in place. |
---|
| 24 | ** |
---|
| 25 | ** Parameters: |
---|
| 26 | ** s -- the string to strip. |
---|
| 27 | ** |
---|
| 28 | ** Returns: |
---|
| 29 | ** none. |
---|
| 30 | ** |
---|
| 31 | ** Side Effects: |
---|
| 32 | ** none. |
---|
| 33 | ** |
---|
| 34 | ** Called By: |
---|
| 35 | ** deliver |
---|
| 36 | */ |
---|
| 37 | |
---|
| 38 | void |
---|
| 39 | stripquotes(s) |
---|
| 40 | char *s; |
---|
| 41 | { |
---|
| 42 | register char *p; |
---|
| 43 | register char *q; |
---|
| 44 | register char c; |
---|
| 45 | |
---|
| 46 | if (s == NULL) |
---|
| 47 | return; |
---|
| 48 | |
---|
| 49 | p = q = s; |
---|
| 50 | do |
---|
| 51 | { |
---|
| 52 | c = *p++; |
---|
| 53 | if (c == '\\') |
---|
| 54 | c = *p++; |
---|
| 55 | else if (c == '"') |
---|
| 56 | continue; |
---|
| 57 | *q++ = c; |
---|
| 58 | } while (c != '\0'); |
---|
| 59 | } |
---|
| 60 | /* |
---|
| 61 | ** ADDQUOTES -- Adds quotes & quote bits to a string. |
---|
| 62 | ** |
---|
| 63 | ** Runs through a string and adds characters and quote bits. |
---|
| 64 | ** |
---|
| 65 | ** Parameters: |
---|
| 66 | ** s -- the string to modify. |
---|
| 67 | ** |
---|
| 68 | ** Returns: |
---|
| 69 | ** pointer to quoted string. |
---|
| 70 | ** |
---|
| 71 | ** Side Effects: |
---|
| 72 | ** none. |
---|
| 73 | ** |
---|
| 74 | */ |
---|
| 75 | |
---|
| 76 | char * |
---|
| 77 | addquotes(s) |
---|
| 78 | char *s; |
---|
| 79 | { |
---|
| 80 | int len = 0; |
---|
| 81 | char c; |
---|
| 82 | char *p = s, *q, *r; |
---|
| 83 | |
---|
| 84 | if (s == NULL) |
---|
| 85 | return NULL; |
---|
| 86 | |
---|
| 87 | /* Find length of quoted string */ |
---|
| 88 | while ((c = *p++) != '\0') |
---|
| 89 | { |
---|
| 90 | len++; |
---|
| 91 | if (c == '\\' || c == '"') |
---|
| 92 | len++; |
---|
| 93 | } |
---|
| 94 | |
---|
| 95 | q = r = xalloc(len + 3); |
---|
| 96 | p = s; |
---|
| 97 | |
---|
| 98 | /* add leading quote */ |
---|
| 99 | *q++ = '"'; |
---|
| 100 | while ((c = *p++) != '\0') |
---|
| 101 | { |
---|
| 102 | /* quote \ or " */ |
---|
| 103 | if (c == '\\' || c == '"') |
---|
| 104 | *q++ = '\\'; |
---|
| 105 | *q++ = c; |
---|
| 106 | } |
---|
| 107 | *q++ = '"'; |
---|
| 108 | *q = '\0'; |
---|
| 109 | return r; |
---|
| 110 | } |
---|
| 111 | /* |
---|
| 112 | ** RFC822_STRING -- Checks string for proper RFC822 string quoting. |
---|
| 113 | ** |
---|
| 114 | ** Runs through a string and verifies RFC822 special characters |
---|
| 115 | ** are only found inside comments, quoted strings, or backslash |
---|
| 116 | ** escaped. Also verified balanced quotes and parenthesis. |
---|
| 117 | ** |
---|
| 118 | ** Parameters: |
---|
| 119 | ** s -- the string to modify. |
---|
| 120 | ** |
---|
| 121 | ** Returns: |
---|
| 122 | ** TRUE -- if the string is RFC822 compliant. |
---|
| 123 | ** FALSE -- if the string is not RFC822 compliant. |
---|
| 124 | ** |
---|
| 125 | ** Side Effects: |
---|
| 126 | ** none. |
---|
| 127 | ** |
---|
| 128 | */ |
---|
| 129 | |
---|
| 130 | bool |
---|
| 131 | rfc822_string(s) |
---|
| 132 | char *s; |
---|
| 133 | { |
---|
| 134 | bool quoted = FALSE; |
---|
| 135 | int commentlev = 0; |
---|
| 136 | char *c = s; |
---|
| 137 | |
---|
| 138 | if (s == NULL) |
---|
| 139 | return FALSE; |
---|
| 140 | |
---|
| 141 | while (*c != '\0') |
---|
| 142 | { |
---|
| 143 | /* escaped character */ |
---|
| 144 | if (*c == '\\') |
---|
| 145 | { |
---|
| 146 | c++; |
---|
| 147 | if (*c == '\0') |
---|
| 148 | return FALSE; |
---|
| 149 | } |
---|
| 150 | else if (commentlev == 0 && *c == '"') |
---|
| 151 | quoted = !quoted; |
---|
| 152 | else if (!quoted) |
---|
| 153 | { |
---|
| 154 | if (*c == ')') |
---|
| 155 | { |
---|
| 156 | /* unbalanced ')' */ |
---|
| 157 | if (commentlev == 0) |
---|
| 158 | return FALSE; |
---|
| 159 | else |
---|
| 160 | commentlev--; |
---|
| 161 | } |
---|
| 162 | else if (*c == '(') |
---|
| 163 | commentlev++; |
---|
| 164 | else if (commentlev == 0 && |
---|
| 165 | strchr(MustQuoteChars, *c) != NULL) |
---|
| 166 | return FALSE; |
---|
| 167 | } |
---|
| 168 | c++; |
---|
| 169 | } |
---|
| 170 | /* unbalanced '"' or '(' */ |
---|
| 171 | if (quoted || commentlev != 0) |
---|
| 172 | return FALSE; |
---|
| 173 | else |
---|
| 174 | return TRUE; |
---|
| 175 | } |
---|
| 176 | /* |
---|
| 177 | ** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string |
---|
| 178 | ** |
---|
| 179 | ** Arbitratily shorten (in place) an RFC822 string and rebalance |
---|
| 180 | ** comments and quotes. |
---|
| 181 | ** |
---|
| 182 | ** Parameters: |
---|
| 183 | ** string -- the string to shorten |
---|
| 184 | ** length -- the maximum size, 0 if no maximum |
---|
| 185 | ** |
---|
| 186 | ** Returns: |
---|
| 187 | ** TRUE if string is changed, FALSE otherwise |
---|
| 188 | ** |
---|
| 189 | ** Side Effects: |
---|
| 190 | ** Changes string in place, possibly resulting |
---|
| 191 | ** in a shorter string. |
---|
| 192 | */ |
---|
| 193 | |
---|
| 194 | bool |
---|
| 195 | shorten_rfc822_string(string, length) |
---|
| 196 | char *string; |
---|
| 197 | size_t length; |
---|
| 198 | { |
---|
| 199 | bool backslash = FALSE; |
---|
| 200 | bool modified = FALSE; |
---|
| 201 | bool quoted = FALSE; |
---|
| 202 | size_t slen; |
---|
| 203 | int parencount = 0; |
---|
| 204 | char *ptr = string; |
---|
| 205 | |
---|
| 206 | /* |
---|
| 207 | ** If have to rebalance an already short enough string, |
---|
| 208 | ** need to do it within allocated space. |
---|
| 209 | */ |
---|
| 210 | slen = strlen(string); |
---|
| 211 | if (length == 0 || slen < length) |
---|
| 212 | length = slen; |
---|
| 213 | |
---|
| 214 | while (*ptr != '\0') |
---|
| 215 | { |
---|
| 216 | if (backslash) |
---|
| 217 | { |
---|
| 218 | backslash = FALSE; |
---|
| 219 | goto increment; |
---|
| 220 | } |
---|
| 221 | |
---|
| 222 | if (*ptr == '\\') |
---|
| 223 | backslash = TRUE; |
---|
| 224 | else if (*ptr == '(') |
---|
| 225 | { |
---|
| 226 | if (!quoted) |
---|
| 227 | parencount++; |
---|
| 228 | } |
---|
| 229 | else if (*ptr == ')') |
---|
| 230 | { |
---|
| 231 | if (--parencount < 0) |
---|
| 232 | parencount = 0; |
---|
| 233 | } |
---|
| 234 | |
---|
| 235 | /* Inside a comment, quotes don't matter */ |
---|
| 236 | if (parencount <= 0 && *ptr == '"') |
---|
| 237 | quoted = !quoted; |
---|
| 238 | |
---|
| 239 | increment: |
---|
| 240 | /* Check for sufficient space for next character */ |
---|
| 241 | if (length - (ptr - string) <= ((backslash ? 1 : 0) + |
---|
| 242 | parencount + |
---|
| 243 | (quoted ? 1 : 0))) |
---|
| 244 | { |
---|
| 245 | /* Not enough, backtrack */ |
---|
| 246 | if (*ptr == '\\') |
---|
| 247 | backslash = FALSE; |
---|
| 248 | else if (*ptr == '(' && !quoted) |
---|
| 249 | parencount--; |
---|
| 250 | else if (*ptr == '"' && parencount == 0) |
---|
| 251 | quoted = FALSE; |
---|
| 252 | break; |
---|
| 253 | } |
---|
| 254 | ptr++; |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | /* Rebalance */ |
---|
| 258 | while (parencount-- > 0) |
---|
| 259 | { |
---|
| 260 | if (*ptr != ')') |
---|
| 261 | { |
---|
| 262 | modified = TRUE; |
---|
| 263 | *ptr = ')'; |
---|
| 264 | } |
---|
| 265 | ptr++; |
---|
| 266 | } |
---|
| 267 | if (quoted) |
---|
| 268 | { |
---|
| 269 | if (*ptr != '"') |
---|
| 270 | { |
---|
| 271 | modified = TRUE; |
---|
| 272 | *ptr = '"'; |
---|
| 273 | } |
---|
| 274 | ptr++; |
---|
| 275 | } |
---|
| 276 | if (*ptr != '\0') |
---|
| 277 | { |
---|
| 278 | modified = TRUE; |
---|
| 279 | *ptr = '\0'; |
---|
| 280 | } |
---|
| 281 | return modified; |
---|
| 282 | } |
---|
| 283 | /* |
---|
| 284 | ** FIND_CHARACTER -- find an unquoted character in an RFC822 string |
---|
| 285 | ** |
---|
| 286 | ** Find an unquoted, non-commented character in an RFC822 |
---|
| 287 | ** string and return a pointer to its location in the |
---|
| 288 | ** string. |
---|
| 289 | ** |
---|
| 290 | ** Parameters: |
---|
| 291 | ** string -- the string to search |
---|
| 292 | ** character -- the character to find |
---|
| 293 | ** |
---|
| 294 | ** Returns: |
---|
| 295 | ** pointer to the character, or |
---|
| 296 | ** a pointer to the end of the line if character is not found |
---|
| 297 | */ |
---|
| 298 | |
---|
| 299 | char * |
---|
| 300 | find_character(string, character) |
---|
| 301 | char *string; |
---|
| 302 | char character; |
---|
| 303 | { |
---|
| 304 | bool backslash = FALSE; |
---|
| 305 | bool quoted = FALSE; |
---|
| 306 | int parencount = 0; |
---|
| 307 | |
---|
| 308 | while (string != NULL && *string != '\0') |
---|
| 309 | { |
---|
| 310 | if (backslash) |
---|
| 311 | { |
---|
| 312 | backslash = FALSE; |
---|
| 313 | if (!quoted && character == '\\' && *string == '\\') |
---|
| 314 | break; |
---|
| 315 | string++; |
---|
| 316 | continue; |
---|
| 317 | } |
---|
| 318 | switch (*string) |
---|
| 319 | { |
---|
| 320 | case '\\': |
---|
| 321 | backslash = TRUE; |
---|
| 322 | break; |
---|
| 323 | |
---|
| 324 | case '(': |
---|
| 325 | if (!quoted) |
---|
| 326 | parencount++; |
---|
| 327 | break; |
---|
| 328 | |
---|
| 329 | case ')': |
---|
| 330 | if (--parencount < 0) |
---|
| 331 | parencount = 0; |
---|
| 332 | break; |
---|
| 333 | } |
---|
| 334 | |
---|
| 335 | /* Inside a comment, nothing matters */ |
---|
| 336 | if (parencount > 0) |
---|
| 337 | { |
---|
| 338 | string++; |
---|
| 339 | continue; |
---|
| 340 | } |
---|
| 341 | |
---|
| 342 | if (*string == '"') |
---|
| 343 | quoted = !quoted; |
---|
| 344 | else if (*string == character && !quoted) |
---|
| 345 | break; |
---|
| 346 | string++; |
---|
| 347 | } |
---|
| 348 | |
---|
| 349 | /* Return pointer to the character */ |
---|
| 350 | return string; |
---|
| 351 | } |
---|
| 352 | /* |
---|
| 353 | ** XALLOC -- Allocate memory and bitch wildly on failure. |
---|
| 354 | ** |
---|
| 355 | ** THIS IS A CLUDGE. This should be made to give a proper |
---|
| 356 | ** error -- but after all, what can we do? |
---|
| 357 | ** |
---|
| 358 | ** Parameters: |
---|
| 359 | ** sz -- size of area to allocate. |
---|
| 360 | ** |
---|
| 361 | ** Returns: |
---|
| 362 | ** pointer to data region. |
---|
| 363 | ** |
---|
| 364 | ** Side Effects: |
---|
| 365 | ** Memory is allocated. |
---|
| 366 | */ |
---|
| 367 | |
---|
| 368 | char * |
---|
| 369 | xalloc(sz) |
---|
| 370 | register int sz; |
---|
| 371 | { |
---|
| 372 | register char *p; |
---|
| 373 | |
---|
| 374 | /* some systems can't handle size zero mallocs */ |
---|
| 375 | if (sz <= 0) |
---|
| 376 | sz = 1; |
---|
| 377 | |
---|
| 378 | p = malloc((unsigned) sz); |
---|
| 379 | if (p == NULL) |
---|
| 380 | { |
---|
| 381 | syserr("!Out of memory!!"); |
---|
| 382 | /* exit(EX_UNAVAILABLE); */ |
---|
| 383 | } |
---|
| 384 | return (p); |
---|
| 385 | } |
---|
| 386 | /* |
---|
| 387 | ** COPYPLIST -- copy list of pointers. |
---|
| 388 | ** |
---|
| 389 | ** This routine is the equivalent of newstr for lists of |
---|
| 390 | ** pointers. |
---|
| 391 | ** |
---|
| 392 | ** Parameters: |
---|
| 393 | ** list -- list of pointers to copy. |
---|
| 394 | ** Must be NULL terminated. |
---|
| 395 | ** copycont -- if TRUE, copy the contents of the vector |
---|
| 396 | ** (which must be a string) also. |
---|
| 397 | ** |
---|
| 398 | ** Returns: |
---|
| 399 | ** a copy of 'list'. |
---|
| 400 | ** |
---|
| 401 | ** Side Effects: |
---|
| 402 | ** none. |
---|
| 403 | */ |
---|
| 404 | |
---|
| 405 | char ** |
---|
| 406 | copyplist(list, copycont) |
---|
| 407 | char **list; |
---|
| 408 | bool copycont; |
---|
| 409 | { |
---|
| 410 | register char **vp; |
---|
| 411 | register char **newvp; |
---|
| 412 | |
---|
| 413 | for (vp = list; *vp != NULL; vp++) |
---|
| 414 | continue; |
---|
| 415 | |
---|
| 416 | vp++; |
---|
| 417 | |
---|
| 418 | newvp = (char **) xalloc((int) (vp - list) * sizeof *vp); |
---|
| 419 | bcopy((char *) list, (char *) newvp, (int) (vp - list) * sizeof *vp); |
---|
| 420 | |
---|
| 421 | if (copycont) |
---|
| 422 | { |
---|
| 423 | for (vp = newvp; *vp != NULL; vp++) |
---|
| 424 | *vp = newstr(*vp); |
---|
| 425 | } |
---|
| 426 | |
---|
| 427 | return (newvp); |
---|
| 428 | } |
---|
| 429 | /* |
---|
| 430 | ** COPYQUEUE -- copy address queue. |
---|
| 431 | ** |
---|
| 432 | ** This routine is the equivalent of newstr for address queues |
---|
| 433 | ** addresses marked with QDONTSEND aren't copied |
---|
| 434 | ** |
---|
| 435 | ** Parameters: |
---|
| 436 | ** addr -- list of address structures to copy. |
---|
| 437 | ** |
---|
| 438 | ** Returns: |
---|
| 439 | ** a copy of 'addr'. |
---|
| 440 | ** |
---|
| 441 | ** Side Effects: |
---|
| 442 | ** none. |
---|
| 443 | */ |
---|
| 444 | |
---|
| 445 | ADDRESS * |
---|
| 446 | copyqueue(addr) |
---|
| 447 | ADDRESS *addr; |
---|
| 448 | { |
---|
| 449 | register ADDRESS *newaddr; |
---|
| 450 | ADDRESS *ret; |
---|
| 451 | register ADDRESS **tail = &ret; |
---|
| 452 | |
---|
| 453 | while (addr != NULL) |
---|
| 454 | { |
---|
| 455 | if (!bitset(QDONTSEND, addr->q_flags)) |
---|
| 456 | { |
---|
| 457 | newaddr = (ADDRESS *) xalloc(sizeof(ADDRESS)); |
---|
| 458 | STRUCTCOPY(*addr, *newaddr); |
---|
| 459 | *tail = newaddr; |
---|
| 460 | tail = &newaddr->q_next; |
---|
| 461 | } |
---|
| 462 | addr = addr->q_next; |
---|
| 463 | } |
---|
| 464 | *tail = NULL; |
---|
| 465 | |
---|
| 466 | return ret; |
---|
| 467 | } |
---|
| 468 | /* |
---|
| 469 | ** PRINTAV -- print argument vector. |
---|
| 470 | ** |
---|
| 471 | ** Parameters: |
---|
| 472 | ** av -- argument vector. |
---|
| 473 | ** |
---|
| 474 | ** Returns: |
---|
| 475 | ** none. |
---|
| 476 | ** |
---|
| 477 | ** Side Effects: |
---|
| 478 | ** prints av. |
---|
| 479 | */ |
---|
| 480 | |
---|
| 481 | void |
---|
| 482 | printav(av) |
---|
| 483 | register char **av; |
---|
| 484 | { |
---|
| 485 | while (*av != NULL) |
---|
| 486 | { |
---|
| 487 | if (tTd(0, 44)) |
---|
| 488 | printf("\n\t%08lx=", (u_long) *av); |
---|
| 489 | else |
---|
| 490 | (void) putchar(' '); |
---|
| 491 | xputs(*av++); |
---|
| 492 | } |
---|
| 493 | (void) putchar('\n'); |
---|
| 494 | } |
---|
| 495 | /* |
---|
| 496 | ** LOWER -- turn letter into lower case. |
---|
| 497 | ** |
---|
| 498 | ** Parameters: |
---|
| 499 | ** c -- character to turn into lower case. |
---|
| 500 | ** |
---|
| 501 | ** Returns: |
---|
| 502 | ** c, in lower case. |
---|
| 503 | ** |
---|
| 504 | ** Side Effects: |
---|
| 505 | ** none. |
---|
| 506 | */ |
---|
| 507 | |
---|
| 508 | char |
---|
| 509 | lower(c) |
---|
| 510 | register char c; |
---|
| 511 | { |
---|
| 512 | return((isascii(c) && isupper(c)) ? tolower(c) : c); |
---|
| 513 | } |
---|
| 514 | /* |
---|
| 515 | ** XPUTS -- put string doing control escapes. |
---|
| 516 | ** |
---|
| 517 | ** Parameters: |
---|
| 518 | ** s -- string to put. |
---|
| 519 | ** |
---|
| 520 | ** Returns: |
---|
| 521 | ** none. |
---|
| 522 | ** |
---|
| 523 | ** Side Effects: |
---|
| 524 | ** output to stdout |
---|
| 525 | */ |
---|
| 526 | |
---|
| 527 | void |
---|
| 528 | xputs(s) |
---|
| 529 | register const char *s; |
---|
| 530 | { |
---|
| 531 | register int c; |
---|
| 532 | register struct metamac *mp; |
---|
| 533 | bool shiftout = FALSE; |
---|
| 534 | extern struct metamac MetaMacros[]; |
---|
| 535 | |
---|
| 536 | if (s == NULL) |
---|
| 537 | { |
---|
| 538 | printf("%s<null>%s", TermEscape.te_rv_on, TermEscape.te_rv_off); |
---|
| 539 | return; |
---|
| 540 | } |
---|
| 541 | while ((c = (*s++ & 0377)) != '\0') |
---|
| 542 | { |
---|
| 543 | if (shiftout) |
---|
| 544 | { |
---|
| 545 | printf("%s", TermEscape.te_rv_off); |
---|
| 546 | shiftout = FALSE; |
---|
| 547 | } |
---|
| 548 | if (!isascii(c)) |
---|
| 549 | { |
---|
| 550 | if (c == MATCHREPL) |
---|
| 551 | { |
---|
| 552 | printf("%s$", TermEscape.te_rv_on); |
---|
| 553 | shiftout = TRUE; |
---|
| 554 | if (*s == '\0') |
---|
| 555 | continue; |
---|
| 556 | c = *s++ & 0377; |
---|
| 557 | goto printchar; |
---|
| 558 | } |
---|
| 559 | if (c == MACROEXPAND || c == MACRODEXPAND) |
---|
| 560 | { |
---|
| 561 | printf("%s$", TermEscape.te_rv_on); |
---|
| 562 | if (c == MACRODEXPAND) |
---|
| 563 | putchar('&'); |
---|
| 564 | shiftout = TRUE; |
---|
| 565 | if (*s == '\0') |
---|
| 566 | continue; |
---|
| 567 | if (strchr("=~&?", *s) != NULL) |
---|
| 568 | putchar(*s++); |
---|
| 569 | if (bitset(0200, *s)) |
---|
| 570 | printf("{%s}", macname(*s++ & 0377)); |
---|
| 571 | else |
---|
| 572 | printf("%c", *s++); |
---|
| 573 | continue; |
---|
| 574 | } |
---|
| 575 | for (mp = MetaMacros; mp->metaname != '\0'; mp++) |
---|
| 576 | { |
---|
| 577 | if ((mp->metaval & 0377) == c) |
---|
| 578 | { |
---|
| 579 | printf("%s$%c", |
---|
| 580 | TermEscape.te_rv_on, |
---|
| 581 | mp->metaname); |
---|
| 582 | shiftout = TRUE; |
---|
| 583 | break; |
---|
| 584 | } |
---|
| 585 | } |
---|
| 586 | if (c == MATCHCLASS || c == MATCHNCLASS) |
---|
| 587 | { |
---|
| 588 | if (bitset(0200, *s)) |
---|
| 589 | printf("{%s}", macname(*s++ & 0377)); |
---|
| 590 | else if (*s != '\0') |
---|
| 591 | printf("%c", *s++); |
---|
| 592 | } |
---|
| 593 | if (mp->metaname != '\0') |
---|
| 594 | continue; |
---|
| 595 | |
---|
| 596 | /* unrecognized meta character */ |
---|
| 597 | printf("%sM-", TermEscape.te_rv_on); |
---|
| 598 | shiftout = TRUE; |
---|
| 599 | c &= 0177; |
---|
| 600 | } |
---|
| 601 | printchar: |
---|
| 602 | if (isprint(c)) |
---|
| 603 | { |
---|
| 604 | putchar(c); |
---|
| 605 | continue; |
---|
| 606 | } |
---|
| 607 | |
---|
| 608 | /* wasn't a meta-macro -- find another way to print it */ |
---|
| 609 | switch (c) |
---|
| 610 | { |
---|
| 611 | case '\n': |
---|
| 612 | c = 'n'; |
---|
| 613 | break; |
---|
| 614 | |
---|
| 615 | case '\r': |
---|
| 616 | c = 'r'; |
---|
| 617 | break; |
---|
| 618 | |
---|
| 619 | case '\t': |
---|
| 620 | c = 't'; |
---|
| 621 | break; |
---|
| 622 | } |
---|
| 623 | if (!shiftout) |
---|
| 624 | { |
---|
| 625 | printf("%s", TermEscape.te_rv_on); |
---|
| 626 | shiftout = TRUE; |
---|
| 627 | } |
---|
| 628 | if (isprint(c)) |
---|
| 629 | { |
---|
| 630 | (void) putchar('\\'); |
---|
| 631 | (void) putchar(c); |
---|
| 632 | } |
---|
| 633 | else |
---|
| 634 | { |
---|
| 635 | (void) putchar('^'); |
---|
| 636 | (void) putchar(c ^ 0100); |
---|
| 637 | } |
---|
| 638 | } |
---|
| 639 | if (shiftout) |
---|
| 640 | printf("%s", TermEscape.te_rv_off); |
---|
| 641 | (void) fflush(stdout); |
---|
| 642 | } |
---|
| 643 | /* |
---|
| 644 | ** MAKELOWER -- Translate a line into lower case |
---|
| 645 | ** |
---|
| 646 | ** Parameters: |
---|
| 647 | ** p -- the string to translate. If NULL, return is |
---|
| 648 | ** immediate. |
---|
| 649 | ** |
---|
| 650 | ** Returns: |
---|
| 651 | ** none. |
---|
| 652 | ** |
---|
| 653 | ** Side Effects: |
---|
| 654 | ** String pointed to by p is translated to lower case. |
---|
| 655 | ** |
---|
| 656 | ** Called By: |
---|
| 657 | ** parse |
---|
| 658 | */ |
---|
| 659 | |
---|
| 660 | void |
---|
| 661 | makelower(p) |
---|
| 662 | register char *p; |
---|
| 663 | { |
---|
| 664 | register char c; |
---|
| 665 | |
---|
| 666 | if (p == NULL) |
---|
| 667 | return; |
---|
| 668 | for (; (c = *p) != '\0'; p++) |
---|
| 669 | if (isascii(c) && isupper(c)) |
---|
| 670 | *p = tolower(c); |
---|
| 671 | } |
---|
| 672 | /* |
---|
| 673 | ** BUILDFNAME -- build full name from gecos style entry. |
---|
| 674 | ** |
---|
| 675 | ** This routine interprets the strange entry that would appear |
---|
| 676 | ** in the GECOS field of the password file. |
---|
| 677 | ** |
---|
| 678 | ** Parameters: |
---|
| 679 | ** p -- name to build. |
---|
| 680 | ** login -- the login name of this user (for &). |
---|
| 681 | ** buf -- place to put the result. |
---|
| 682 | ** buflen -- length of buf. |
---|
| 683 | ** |
---|
| 684 | ** Returns: |
---|
| 685 | ** none. |
---|
| 686 | ** |
---|
| 687 | ** Side Effects: |
---|
| 688 | ** none. |
---|
| 689 | */ |
---|
| 690 | |
---|
| 691 | void |
---|
| 692 | buildfname(gecos, login, buf, buflen) |
---|
| 693 | register char *gecos; |
---|
| 694 | char *login; |
---|
| 695 | char *buf; |
---|
| 696 | int buflen; |
---|
| 697 | { |
---|
| 698 | register char *p; |
---|
| 699 | register char *bp = buf; |
---|
| 700 | |
---|
| 701 | if (*gecos == '*') |
---|
| 702 | gecos++; |
---|
| 703 | |
---|
| 704 | /* copy gecos, interpolating & to be full name */ |
---|
| 705 | for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) |
---|
| 706 | { |
---|
| 707 | if (bp >= &buf[buflen - 1]) |
---|
| 708 | { |
---|
| 709 | /* buffer overflow -- just use login name */ |
---|
| 710 | snprintf(buf, buflen, "%s", login); |
---|
| 711 | return; |
---|
| 712 | } |
---|
| 713 | if (*p == '&') |
---|
| 714 | { |
---|
| 715 | /* interpolate full name */ |
---|
| 716 | snprintf(bp, buflen - (bp - buf), "%s", login); |
---|
| 717 | *bp = toupper(*bp); |
---|
| 718 | bp += strlen(bp); |
---|
| 719 | } |
---|
| 720 | else |
---|
| 721 | *bp++ = *p; |
---|
| 722 | } |
---|
| 723 | *bp = '\0'; |
---|
| 724 | } |
---|
| 725 | /* |
---|
| 726 | ** FIXCRLF -- fix <CR><LF> in line. |
---|
| 727 | ** |
---|
| 728 | ** Looks for the <CR><LF> combination and turns it into the |
---|
| 729 | ** UNIX canonical <NL> character. It only takes one line, |
---|
| 730 | ** i.e., it is assumed that the first <NL> found is the end |
---|
| 731 | ** of the line. |
---|
| 732 | ** |
---|
| 733 | ** Parameters: |
---|
| 734 | ** line -- the line to fix. |
---|
| 735 | ** stripnl -- if true, strip the newline also. |
---|
| 736 | ** |
---|
| 737 | ** Returns: |
---|
| 738 | ** none. |
---|
| 739 | ** |
---|
| 740 | ** Side Effects: |
---|
| 741 | ** line is changed in place. |
---|
| 742 | */ |
---|
| 743 | |
---|
| 744 | void |
---|
| 745 | fixcrlf(line, stripnl) |
---|
| 746 | char *line; |
---|
| 747 | bool stripnl; |
---|
| 748 | { |
---|
| 749 | register char *p; |
---|
| 750 | |
---|
| 751 | p = strchr(line, '\n'); |
---|
| 752 | if (p == NULL) |
---|
| 753 | return; |
---|
| 754 | if (p > line && p[-1] == '\r') |
---|
| 755 | p--; |
---|
| 756 | if (!stripnl) |
---|
| 757 | *p++ = '\n'; |
---|
| 758 | *p = '\0'; |
---|
| 759 | } |
---|
| 760 | /* |
---|
| 761 | ** PUTLINE -- put a line like fputs obeying SMTP conventions |
---|
| 762 | ** |
---|
| 763 | ** This routine always guarantees outputing a newline (or CRLF, |
---|
| 764 | ** as appropriate) at the end of the string. |
---|
| 765 | ** |
---|
| 766 | ** Parameters: |
---|
| 767 | ** l -- line to put. |
---|
| 768 | ** mci -- the mailer connection information. |
---|
| 769 | ** |
---|
| 770 | ** Returns: |
---|
| 771 | ** none |
---|
| 772 | ** |
---|
| 773 | ** Side Effects: |
---|
| 774 | ** output of l to fp. |
---|
| 775 | */ |
---|
| 776 | |
---|
| 777 | void |
---|
| 778 | putline(l, mci) |
---|
| 779 | register char *l; |
---|
| 780 | register MCI *mci; |
---|
| 781 | { |
---|
| 782 | putxline(l, strlen(l), mci, PXLF_MAPFROM); |
---|
| 783 | } |
---|
| 784 | /* |
---|
| 785 | ** PUTXLINE -- putline with flags bits. |
---|
| 786 | ** |
---|
| 787 | ** This routine always guarantees outputing a newline (or CRLF, |
---|
| 788 | ** as appropriate) at the end of the string. |
---|
| 789 | ** |
---|
| 790 | ** Parameters: |
---|
| 791 | ** l -- line to put. |
---|
| 792 | ** len -- the length of the line. |
---|
| 793 | ** mci -- the mailer connection information. |
---|
| 794 | ** pxflags -- flag bits: |
---|
| 795 | ** PXLF_MAPFROM -- map From_ to >From_. |
---|
| 796 | ** PXLF_STRIP8BIT -- strip 8th bit. |
---|
| 797 | ** PXLF_HEADER -- map bare newline in header to newline space. |
---|
| 798 | ** |
---|
| 799 | ** Returns: |
---|
| 800 | ** none |
---|
| 801 | ** |
---|
| 802 | ** Side Effects: |
---|
| 803 | ** output of l to fp. |
---|
| 804 | */ |
---|
| 805 | |
---|
| 806 | void |
---|
| 807 | putxline(l, len, mci, pxflags) |
---|
| 808 | register char *l; |
---|
| 809 | size_t len; |
---|
| 810 | register MCI *mci; |
---|
| 811 | int pxflags; |
---|
| 812 | { |
---|
| 813 | register char *p, *end; |
---|
| 814 | int slop = 0; |
---|
| 815 | size_t eol_len = strlen(mci->mci_mailer->m_eol); |
---|
| 816 | |
---|
| 817 | /* strip out 0200 bits -- these can look like TELNET protocol */ |
---|
| 818 | if (bitset(MCIF_7BIT, mci->mci_flags) || |
---|
| 819 | bitset(PXLF_STRIP8BIT, pxflags)) |
---|
| 820 | { |
---|
| 821 | register char svchar; |
---|
| 822 | |
---|
| 823 | for (p = l; (svchar = *p) != '\0'; ++p) |
---|
| 824 | if (bitset(0200, svchar)) |
---|
| 825 | *p = svchar &~ 0200; |
---|
| 826 | } |
---|
| 827 | |
---|
| 828 | end = l + len; |
---|
| 829 | do |
---|
| 830 | { |
---|
| 831 | /* find the end of the line */ |
---|
| 832 | p = memchr(l, '\n', end - l); |
---|
| 833 | if (p == NULL) |
---|
| 834 | p = end; |
---|
| 835 | |
---|
| 836 | if (TrafficLogFile != NULL) |
---|
| 837 | fprintf(TrafficLogFile, "%05d >>> ", (int) getpid()); |
---|
| 838 | |
---|
| 839 | /* check for line overflow */ |
---|
| 840 | while (mci->mci_mailer->m_linelimit > 0 && |
---|
| 841 | (p - l + slop) > mci->mci_mailer->m_linelimit) |
---|
| 842 | { |
---|
| 843 | char *l_base = l; |
---|
| 844 | register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; |
---|
| 845 | |
---|
| 846 | if (l[0] == '.' && slop == 0 && |
---|
| 847 | bitnset(M_XDOT, mci->mci_mailer->m_flags)) |
---|
| 848 | { |
---|
| 849 | (void) putc('.', mci->mci_out); |
---|
| 850 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 851 | mci->mci_contentlen++; |
---|
| 852 | if (TrafficLogFile != NULL) |
---|
| 853 | (void) putc('.', TrafficLogFile); |
---|
| 854 | } |
---|
| 855 | else if (l[0] == 'F' && slop == 0 && |
---|
| 856 | bitset(PXLF_MAPFROM, pxflags) && |
---|
| 857 | strncmp(l, "From ", 5) == 0 && |
---|
| 858 | bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) |
---|
| 859 | { |
---|
| 860 | (void) putc('>', mci->mci_out); |
---|
| 861 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 862 | mci->mci_contentlen++; |
---|
| 863 | if (TrafficLogFile != NULL) |
---|
| 864 | (void) putc('>', TrafficLogFile); |
---|
| 865 | } |
---|
| 866 | while (l < q) |
---|
| 867 | { |
---|
| 868 | (void) putc(*l++, mci->mci_out); |
---|
| 869 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 870 | mci->mci_contentlen++; |
---|
| 871 | } |
---|
| 872 | (void) putc('!', mci->mci_out); |
---|
| 873 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 874 | mci->mci_contentlen++; |
---|
| 875 | fputs(mci->mci_mailer->m_eol, mci->mci_out); |
---|
| 876 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 877 | mci->mci_contentlen += eol_len; |
---|
| 878 | (void) putc(' ', mci->mci_out); |
---|
| 879 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 880 | mci->mci_contentlen++; |
---|
| 881 | if (TrafficLogFile != NULL) |
---|
| 882 | { |
---|
| 883 | for (l = l_base; l < q; l++) |
---|
| 884 | (void) putc(*l, TrafficLogFile); |
---|
| 885 | fprintf(TrafficLogFile, "!\n%05d >>> ", |
---|
| 886 | (int) getpid()); |
---|
| 887 | } |
---|
| 888 | slop = 1; |
---|
| 889 | } |
---|
| 890 | |
---|
| 891 | /* output last part */ |
---|
| 892 | if (l[0] == '.' && slop == 0 && |
---|
| 893 | bitnset(M_XDOT, mci->mci_mailer->m_flags)) |
---|
| 894 | { |
---|
| 895 | (void) putc('.', mci->mci_out); |
---|
| 896 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 897 | mci->mci_contentlen++; |
---|
| 898 | if (TrafficLogFile != NULL) |
---|
| 899 | (void) putc('.', TrafficLogFile); |
---|
| 900 | } |
---|
| 901 | else if (l[0] == 'F' && slop == 0 && |
---|
| 902 | bitset(PXLF_MAPFROM, pxflags) && |
---|
| 903 | strncmp(l, "From ", 5) == 0 && |
---|
| 904 | bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) |
---|
| 905 | { |
---|
| 906 | (void) putc('>', mci->mci_out); |
---|
| 907 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 908 | mci->mci_contentlen++; |
---|
| 909 | if (TrafficLogFile != NULL) |
---|
| 910 | (void) putc('>', TrafficLogFile); |
---|
| 911 | } |
---|
| 912 | for ( ; l < p; ++l) |
---|
| 913 | { |
---|
| 914 | if (TrafficLogFile != NULL) |
---|
| 915 | (void) putc(*l, TrafficLogFile); |
---|
| 916 | (void) putc(*l, mci->mci_out); |
---|
| 917 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 918 | mci->mci_contentlen++; |
---|
| 919 | } |
---|
| 920 | if (TrafficLogFile != NULL) |
---|
| 921 | (void) putc('\n', TrafficLogFile); |
---|
| 922 | fputs(mci->mci_mailer->m_eol, mci->mci_out); |
---|
| 923 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 924 | mci->mci_contentlen += eol_len; |
---|
| 925 | if (l < end && *l == '\n') |
---|
| 926 | { |
---|
| 927 | if (*++l != ' ' && *l != '\t' && *l != '\0' && |
---|
| 928 | bitset(PXLF_HEADER, pxflags)) |
---|
| 929 | { |
---|
| 930 | (void) putc(' ', mci->mci_out); |
---|
| 931 | if (!bitset(MCIF_INHEADER, mci->mci_flags)) |
---|
| 932 | mci->mci_contentlen++; |
---|
| 933 | if (TrafficLogFile != NULL) |
---|
| 934 | (void) putc(' ', TrafficLogFile); |
---|
| 935 | } |
---|
| 936 | } |
---|
| 937 | } while (l < end); |
---|
| 938 | } |
---|
| 939 | /* |
---|
| 940 | ** XUNLINK -- unlink a file, doing logging as appropriate. |
---|
| 941 | ** |
---|
| 942 | ** Parameters: |
---|
| 943 | ** f -- name of file to unlink. |
---|
| 944 | ** |
---|
| 945 | ** Returns: |
---|
| 946 | ** none. |
---|
| 947 | ** |
---|
| 948 | ** Side Effects: |
---|
| 949 | ** f is unlinked. |
---|
| 950 | */ |
---|
| 951 | |
---|
| 952 | void |
---|
| 953 | xunlink(f) |
---|
| 954 | char *f; |
---|
| 955 | { |
---|
| 956 | register int i; |
---|
| 957 | |
---|
| 958 | if (LogLevel > 98) |
---|
| 959 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
| 960 | "unlink %s", |
---|
| 961 | f); |
---|
| 962 | |
---|
| 963 | i = unlink(f); |
---|
| 964 | if (i < 0 && LogLevel > 97) |
---|
| 965 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
| 966 | "%s: unlink-fail %d", |
---|
| 967 | f, errno); |
---|
| 968 | } |
---|
| 969 | /* |
---|
| 970 | ** XFCLOSE -- close a file, doing logging as appropriate. |
---|
| 971 | ** |
---|
| 972 | ** Parameters: |
---|
| 973 | ** fp -- file pointer for the file to close |
---|
| 974 | ** a, b -- miscellaneous crud to print for debugging |
---|
| 975 | ** |
---|
| 976 | ** Returns: |
---|
| 977 | ** none. |
---|
| 978 | ** |
---|
| 979 | ** Side Effects: |
---|
| 980 | ** fp is closed. |
---|
| 981 | */ |
---|
| 982 | |
---|
| 983 | void |
---|
| 984 | xfclose(fp, a, b) |
---|
| 985 | FILE *fp; |
---|
| 986 | char *a, *b; |
---|
| 987 | { |
---|
| 988 | if (tTd(53, 99)) |
---|
| 989 | printf("xfclose(%lx) %s %s\n", (u_long) fp, a, b); |
---|
| 990 | #if XDEBUG |
---|
| 991 | if (fileno(fp) == 1) |
---|
| 992 | syserr("xfclose(%s %s): fd = 1", a, b); |
---|
| 993 | #endif |
---|
| 994 | if (fclose(fp) < 0 && tTd(53, 99)) |
---|
| 995 | printf("xfclose FAILURE: %s\n", errstring(errno)); |
---|
| 996 | } |
---|
| 997 | /* |
---|
| 998 | ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. |
---|
| 999 | ** |
---|
| 1000 | ** Parameters: |
---|
| 1001 | ** buf -- place to put the input line. |
---|
| 1002 | ** siz -- size of buf. |
---|
| 1003 | ** fp -- file to read from. |
---|
| 1004 | ** timeout -- the timeout before error occurs. |
---|
| 1005 | ** during -- what we are trying to read (for error messages). |
---|
| 1006 | ** |
---|
| 1007 | ** Returns: |
---|
| 1008 | ** NULL on error (including timeout). This will also leave |
---|
| 1009 | ** buf containing a null string. |
---|
| 1010 | ** buf otherwise. |
---|
| 1011 | ** |
---|
| 1012 | ** Side Effects: |
---|
| 1013 | ** none. |
---|
| 1014 | */ |
---|
| 1015 | |
---|
| 1016 | static jmp_buf CtxReadTimeout; |
---|
| 1017 | static void readtimeout __P((time_t)); |
---|
| 1018 | |
---|
| 1019 | char * |
---|
| 1020 | sfgets(buf, siz, fp, timeout, during) |
---|
| 1021 | char *buf; |
---|
| 1022 | int siz; |
---|
| 1023 | FILE *fp; |
---|
| 1024 | time_t timeout; |
---|
| 1025 | char *during; |
---|
| 1026 | { |
---|
| 1027 | register EVENT *ev = NULL; |
---|
| 1028 | register char *p; |
---|
| 1029 | int save_errno; |
---|
| 1030 | |
---|
| 1031 | if (fp == NULL) |
---|
| 1032 | { |
---|
| 1033 | buf[0] = '\0'; |
---|
| 1034 | return NULL; |
---|
| 1035 | } |
---|
| 1036 | |
---|
| 1037 | /* set the timeout */ |
---|
| 1038 | if (timeout != 0) |
---|
| 1039 | { |
---|
| 1040 | if (setjmp(CtxReadTimeout) != 0) |
---|
| 1041 | { |
---|
| 1042 | if (LogLevel > 1) |
---|
| 1043 | sm_syslog(LOG_NOTICE, CurEnv->e_id, |
---|
| 1044 | "timeout waiting for input from %.100s during %s", |
---|
| 1045 | CurHostName ? CurHostName : "local", |
---|
| 1046 | during); |
---|
| 1047 | buf[0] = '\0'; |
---|
| 1048 | #if XDEBUG |
---|
| 1049 | checkfd012(during); |
---|
| 1050 | #endif |
---|
| 1051 | if (TrafficLogFile != NULL) |
---|
| 1052 | fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n", |
---|
| 1053 | (int) getpid()); |
---|
| 1054 | errno = 0; |
---|
| 1055 | return (NULL); |
---|
| 1056 | } |
---|
| 1057 | ev = setevent(timeout, readtimeout, 0); |
---|
| 1058 | } |
---|
| 1059 | |
---|
| 1060 | /* try to read */ |
---|
| 1061 | p = NULL; |
---|
| 1062 | errno = 0; |
---|
| 1063 | while (!feof(fp) && !ferror(fp)) |
---|
| 1064 | { |
---|
| 1065 | errno = 0; |
---|
| 1066 | p = fgets(buf, siz, fp); |
---|
| 1067 | if (p != NULL || errno != EINTR) |
---|
| 1068 | break; |
---|
| 1069 | clearerr(fp); |
---|
| 1070 | } |
---|
| 1071 | save_errno = errno; |
---|
| 1072 | |
---|
| 1073 | /* clear the event if it has not sprung */ |
---|
| 1074 | clrevent(ev); |
---|
| 1075 | |
---|
| 1076 | /* clean up the books and exit */ |
---|
| 1077 | LineNumber++; |
---|
| 1078 | if (p == NULL) |
---|
| 1079 | { |
---|
| 1080 | buf[0] = '\0'; |
---|
| 1081 | if (TrafficLogFile != NULL) |
---|
| 1082 | fprintf(TrafficLogFile, "%05d <<< [EOF]\n", (int) getpid()); |
---|
| 1083 | errno = save_errno; |
---|
| 1084 | return (NULL); |
---|
| 1085 | } |
---|
| 1086 | if (TrafficLogFile != NULL) |
---|
| 1087 | fprintf(TrafficLogFile, "%05d <<< %s", (int) getpid(), buf); |
---|
| 1088 | if (SevenBitInput) |
---|
| 1089 | { |
---|
| 1090 | for (p = buf; *p != '\0'; p++) |
---|
| 1091 | *p &= ~0200; |
---|
| 1092 | } |
---|
| 1093 | else if (!HasEightBits) |
---|
| 1094 | { |
---|
| 1095 | for (p = buf; *p != '\0'; p++) |
---|
| 1096 | { |
---|
| 1097 | if (bitset(0200, *p)) |
---|
| 1098 | { |
---|
| 1099 | HasEightBits = TRUE; |
---|
| 1100 | break; |
---|
| 1101 | } |
---|
| 1102 | } |
---|
| 1103 | } |
---|
| 1104 | return (buf); |
---|
| 1105 | } |
---|
| 1106 | |
---|
| 1107 | /* ARGSUSED */ |
---|
| 1108 | static void |
---|
| 1109 | readtimeout(timeout) |
---|
| 1110 | time_t timeout; |
---|
| 1111 | { |
---|
| 1112 | longjmp(CtxReadTimeout, 1); |
---|
| 1113 | } |
---|
| 1114 | /* |
---|
| 1115 | ** FGETFOLDED -- like fgets, but know about folded lines. |
---|
| 1116 | ** |
---|
| 1117 | ** Parameters: |
---|
| 1118 | ** buf -- place to put result. |
---|
| 1119 | ** n -- bytes available. |
---|
| 1120 | ** f -- file to read from. |
---|
| 1121 | ** |
---|
| 1122 | ** Returns: |
---|
| 1123 | ** input line(s) on success, NULL on error or EOF. |
---|
| 1124 | ** This will normally be buf -- unless the line is too |
---|
| 1125 | ** long, when it will be xalloc()ed. |
---|
| 1126 | ** |
---|
| 1127 | ** Side Effects: |
---|
| 1128 | ** buf gets lines from f, with continuation lines (lines |
---|
| 1129 | ** with leading white space) appended. CRLF's are mapped |
---|
| 1130 | ** into single newlines. Any trailing NL is stripped. |
---|
| 1131 | */ |
---|
| 1132 | |
---|
| 1133 | char * |
---|
| 1134 | fgetfolded(buf, n, f) |
---|
| 1135 | char *buf; |
---|
| 1136 | register int n; |
---|
| 1137 | FILE *f; |
---|
| 1138 | { |
---|
| 1139 | register char *p = buf; |
---|
| 1140 | char *bp = buf; |
---|
| 1141 | register int i; |
---|
| 1142 | |
---|
| 1143 | n--; |
---|
| 1144 | while ((i = getc(f)) != EOF) |
---|
| 1145 | { |
---|
| 1146 | if (i == '\r') |
---|
| 1147 | { |
---|
| 1148 | i = getc(f); |
---|
| 1149 | if (i != '\n') |
---|
| 1150 | { |
---|
| 1151 | if (i != EOF) |
---|
| 1152 | (void) ungetc(i, f); |
---|
| 1153 | i = '\r'; |
---|
| 1154 | } |
---|
| 1155 | } |
---|
| 1156 | if (--n <= 0) |
---|
| 1157 | { |
---|
| 1158 | /* allocate new space */ |
---|
| 1159 | char *nbp; |
---|
| 1160 | int nn; |
---|
| 1161 | |
---|
| 1162 | nn = (p - bp); |
---|
| 1163 | if (nn < MEMCHUNKSIZE) |
---|
| 1164 | nn *= 2; |
---|
| 1165 | else |
---|
| 1166 | nn += MEMCHUNKSIZE; |
---|
| 1167 | nbp = xalloc(nn); |
---|
| 1168 | bcopy(bp, nbp, p - bp); |
---|
| 1169 | p = &nbp[p - bp]; |
---|
| 1170 | if (bp != buf) |
---|
| 1171 | free(bp); |
---|
| 1172 | bp = nbp; |
---|
| 1173 | n = nn - (p - bp); |
---|
| 1174 | } |
---|
| 1175 | *p++ = i; |
---|
| 1176 | if (i == '\n') |
---|
| 1177 | { |
---|
| 1178 | LineNumber++; |
---|
| 1179 | i = getc(f); |
---|
| 1180 | if (i != EOF) |
---|
| 1181 | (void) ungetc(i, f); |
---|
| 1182 | if (i != ' ' && i != '\t') |
---|
| 1183 | break; |
---|
| 1184 | } |
---|
| 1185 | } |
---|
| 1186 | if (p == bp) |
---|
| 1187 | return (NULL); |
---|
| 1188 | if (p[-1] == '\n') |
---|
| 1189 | p--; |
---|
| 1190 | *p = '\0'; |
---|
| 1191 | return (bp); |
---|
| 1192 | } |
---|
| 1193 | /* |
---|
| 1194 | ** CURTIME -- return current time. |
---|
| 1195 | ** |
---|
| 1196 | ** Parameters: |
---|
| 1197 | ** none. |
---|
| 1198 | ** |
---|
| 1199 | ** Returns: |
---|
| 1200 | ** the current time. |
---|
| 1201 | ** |
---|
| 1202 | ** Side Effects: |
---|
| 1203 | ** none. |
---|
| 1204 | */ |
---|
| 1205 | |
---|
| 1206 | time_t |
---|
| 1207 | curtime() |
---|
| 1208 | { |
---|
| 1209 | auto time_t t; |
---|
| 1210 | |
---|
| 1211 | (void) time(&t); |
---|
| 1212 | return (t); |
---|
| 1213 | } |
---|
| 1214 | /* |
---|
| 1215 | ** ATOBOOL -- convert a string representation to boolean. |
---|
| 1216 | ** |
---|
| 1217 | ** Defaults to "TRUE" |
---|
| 1218 | ** |
---|
| 1219 | ** Parameters: |
---|
| 1220 | ** s -- string to convert. Takes "tTyY" as true, |
---|
| 1221 | ** others as false. |
---|
| 1222 | ** |
---|
| 1223 | ** Returns: |
---|
| 1224 | ** A boolean representation of the string. |
---|
| 1225 | ** |
---|
| 1226 | ** Side Effects: |
---|
| 1227 | ** none. |
---|
| 1228 | */ |
---|
| 1229 | |
---|
| 1230 | bool |
---|
| 1231 | atobool(s) |
---|
| 1232 | register char *s; |
---|
| 1233 | { |
---|
| 1234 | if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) |
---|
| 1235 | return (TRUE); |
---|
| 1236 | return (FALSE); |
---|
| 1237 | } |
---|
| 1238 | /* |
---|
| 1239 | ** ATOOCT -- convert a string representation to octal. |
---|
| 1240 | ** |
---|
| 1241 | ** Parameters: |
---|
| 1242 | ** s -- string to convert. |
---|
| 1243 | ** |
---|
| 1244 | ** Returns: |
---|
| 1245 | ** An integer representing the string interpreted as an |
---|
| 1246 | ** octal number. |
---|
| 1247 | ** |
---|
| 1248 | ** Side Effects: |
---|
| 1249 | ** none. |
---|
| 1250 | */ |
---|
| 1251 | |
---|
| 1252 | int |
---|
| 1253 | atooct(s) |
---|
| 1254 | register char *s; |
---|
| 1255 | { |
---|
| 1256 | register int i = 0; |
---|
| 1257 | |
---|
| 1258 | while (*s >= '0' && *s <= '7') |
---|
| 1259 | i = (i << 3) | (*s++ - '0'); |
---|
| 1260 | return (i); |
---|
| 1261 | } |
---|
| 1262 | /* |
---|
| 1263 | ** BITINTERSECT -- tell if two bitmaps intersect |
---|
| 1264 | ** |
---|
| 1265 | ** Parameters: |
---|
| 1266 | ** a, b -- the bitmaps in question |
---|
| 1267 | ** |
---|
| 1268 | ** Returns: |
---|
| 1269 | ** TRUE if they have a non-null intersection |
---|
| 1270 | ** FALSE otherwise |
---|
| 1271 | ** |
---|
| 1272 | ** Side Effects: |
---|
| 1273 | ** none. |
---|
| 1274 | */ |
---|
| 1275 | |
---|
| 1276 | bool |
---|
| 1277 | bitintersect(a, b) |
---|
| 1278 | BITMAP a; |
---|
| 1279 | BITMAP b; |
---|
| 1280 | { |
---|
| 1281 | int i; |
---|
| 1282 | |
---|
| 1283 | for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) |
---|
| 1284 | if ((a[i] & b[i]) != 0) |
---|
| 1285 | return (TRUE); |
---|
| 1286 | return (FALSE); |
---|
| 1287 | } |
---|
| 1288 | /* |
---|
| 1289 | ** BITZEROP -- tell if a bitmap is all zero |
---|
| 1290 | ** |
---|
| 1291 | ** Parameters: |
---|
| 1292 | ** map -- the bit map to check |
---|
| 1293 | ** |
---|
| 1294 | ** Returns: |
---|
| 1295 | ** TRUE if map is all zero. |
---|
| 1296 | ** FALSE if there are any bits set in map. |
---|
| 1297 | ** |
---|
| 1298 | ** Side Effects: |
---|
| 1299 | ** none. |
---|
| 1300 | */ |
---|
| 1301 | |
---|
| 1302 | bool |
---|
| 1303 | bitzerop(map) |
---|
| 1304 | BITMAP map; |
---|
| 1305 | { |
---|
| 1306 | int i; |
---|
| 1307 | |
---|
| 1308 | for (i = BITMAPBYTES / sizeof (int); --i >= 0; ) |
---|
| 1309 | if (map[i] != 0) |
---|
| 1310 | return (FALSE); |
---|
| 1311 | return (TRUE); |
---|
| 1312 | } |
---|
| 1313 | /* |
---|
| 1314 | ** STRCONTAINEDIN -- tell if one string is contained in another |
---|
| 1315 | ** |
---|
| 1316 | ** Parameters: |
---|
| 1317 | ** a -- possible substring. |
---|
| 1318 | ** b -- possible superstring. |
---|
| 1319 | ** |
---|
| 1320 | ** Returns: |
---|
| 1321 | ** TRUE if a is contained in b. |
---|
| 1322 | ** FALSE otherwise. |
---|
| 1323 | */ |
---|
| 1324 | |
---|
| 1325 | bool |
---|
| 1326 | strcontainedin(a, b) |
---|
| 1327 | register char *a; |
---|
| 1328 | register char *b; |
---|
| 1329 | { |
---|
| 1330 | int la; |
---|
| 1331 | int lb; |
---|
| 1332 | int c; |
---|
| 1333 | |
---|
| 1334 | la = strlen(a); |
---|
| 1335 | lb = strlen(b); |
---|
| 1336 | c = *a; |
---|
| 1337 | if (isascii(c) && isupper(c)) |
---|
| 1338 | c = tolower(c); |
---|
| 1339 | for (; lb-- >= la; b++) |
---|
| 1340 | { |
---|
| 1341 | if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c) |
---|
| 1342 | continue; |
---|
| 1343 | if (strncasecmp(a, b, la) == 0) |
---|
| 1344 | return TRUE; |
---|
| 1345 | } |
---|
| 1346 | return FALSE; |
---|
| 1347 | } |
---|
| 1348 | /* |
---|
| 1349 | ** CHECKFD012 -- check low numbered file descriptors |
---|
| 1350 | ** |
---|
| 1351 | ** File descriptors 0, 1, and 2 should be open at all times. |
---|
| 1352 | ** This routine verifies that, and fixes it if not true. |
---|
| 1353 | ** |
---|
| 1354 | ** Parameters: |
---|
| 1355 | ** where -- a tag printed if the assertion failed |
---|
| 1356 | ** |
---|
| 1357 | ** Returns: |
---|
| 1358 | ** none |
---|
| 1359 | */ |
---|
| 1360 | |
---|
| 1361 | void |
---|
| 1362 | checkfd012(where) |
---|
| 1363 | char *where; |
---|
| 1364 | { |
---|
| 1365 | #if XDEBUG |
---|
| 1366 | register int i; |
---|
| 1367 | |
---|
| 1368 | for (i = 0; i < 3; i++) |
---|
| 1369 | fill_fd(i, where); |
---|
| 1370 | #endif /* XDEBUG */ |
---|
| 1371 | } |
---|
| 1372 | /* |
---|
| 1373 | ** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging |
---|
| 1374 | ** |
---|
| 1375 | ** Parameters: |
---|
| 1376 | ** fd -- file descriptor to check. |
---|
| 1377 | ** where -- tag to print on failure. |
---|
| 1378 | ** |
---|
| 1379 | ** Returns: |
---|
| 1380 | ** none. |
---|
| 1381 | */ |
---|
| 1382 | |
---|
| 1383 | void |
---|
| 1384 | checkfdopen(fd, where) |
---|
| 1385 | int fd; |
---|
| 1386 | char *where; |
---|
| 1387 | { |
---|
| 1388 | #if XDEBUG |
---|
| 1389 | struct stat st; |
---|
| 1390 | |
---|
| 1391 | if (fstat(fd, &st) < 0 && errno == EBADF) |
---|
| 1392 | { |
---|
| 1393 | syserr("checkfdopen(%d): %s not open as expected!", fd, where); |
---|
| 1394 | printopenfds(TRUE); |
---|
| 1395 | } |
---|
| 1396 | #endif |
---|
| 1397 | } |
---|
| 1398 | /* |
---|
| 1399 | ** CHECKFDS -- check for new or missing file descriptors |
---|
| 1400 | ** |
---|
| 1401 | ** Parameters: |
---|
| 1402 | ** where -- tag for printing. If null, take a base line. |
---|
| 1403 | ** |
---|
| 1404 | ** Returns: |
---|
| 1405 | ** none |
---|
| 1406 | ** |
---|
| 1407 | ** Side Effects: |
---|
| 1408 | ** If where is set, shows changes since the last call. |
---|
| 1409 | */ |
---|
| 1410 | |
---|
| 1411 | void |
---|
| 1412 | checkfds(where) |
---|
| 1413 | char *where; |
---|
| 1414 | { |
---|
| 1415 | int maxfd; |
---|
| 1416 | register int fd; |
---|
| 1417 | bool printhdr = TRUE; |
---|
| 1418 | int save_errno = errno; |
---|
| 1419 | static BITMAP baseline; |
---|
| 1420 | extern int DtableSize; |
---|
| 1421 | |
---|
| 1422 | if (DtableSize > 256) |
---|
| 1423 | maxfd = 256; |
---|
| 1424 | else |
---|
| 1425 | maxfd = DtableSize; |
---|
| 1426 | if (where == NULL) |
---|
| 1427 | clrbitmap(baseline); |
---|
| 1428 | |
---|
| 1429 | for (fd = 0; fd < maxfd; fd++) |
---|
| 1430 | { |
---|
| 1431 | struct stat stbuf; |
---|
| 1432 | |
---|
| 1433 | if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) |
---|
| 1434 | { |
---|
| 1435 | if (!bitnset(fd, baseline)) |
---|
| 1436 | continue; |
---|
| 1437 | clrbitn(fd, baseline); |
---|
| 1438 | } |
---|
| 1439 | else if (!bitnset(fd, baseline)) |
---|
| 1440 | setbitn(fd, baseline); |
---|
| 1441 | else |
---|
| 1442 | continue; |
---|
| 1443 | |
---|
| 1444 | /* file state has changed */ |
---|
| 1445 | if (where == NULL) |
---|
| 1446 | continue; |
---|
| 1447 | if (printhdr) |
---|
| 1448 | { |
---|
| 1449 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
| 1450 | "%s: changed fds:", |
---|
| 1451 | where); |
---|
| 1452 | printhdr = FALSE; |
---|
| 1453 | } |
---|
| 1454 | dumpfd(fd, TRUE, TRUE); |
---|
| 1455 | } |
---|
| 1456 | errno = save_errno; |
---|
| 1457 | } |
---|
| 1458 | /* |
---|
| 1459 | ** PRINTOPENFDS -- print the open file descriptors (for debugging) |
---|
| 1460 | ** |
---|
| 1461 | ** Parameters: |
---|
| 1462 | ** logit -- if set, send output to syslog; otherwise |
---|
| 1463 | ** print for debugging. |
---|
| 1464 | ** |
---|
| 1465 | ** Returns: |
---|
| 1466 | ** none. |
---|
| 1467 | */ |
---|
| 1468 | |
---|
| 1469 | #include <arpa/inet.h> |
---|
| 1470 | |
---|
| 1471 | void |
---|
| 1472 | printopenfds(logit) |
---|
| 1473 | bool logit; |
---|
| 1474 | { |
---|
| 1475 | register int fd; |
---|
| 1476 | extern int DtableSize; |
---|
| 1477 | |
---|
| 1478 | for (fd = 0; fd < DtableSize; fd++) |
---|
| 1479 | dumpfd(fd, FALSE, logit); |
---|
| 1480 | } |
---|
| 1481 | /* |
---|
| 1482 | ** DUMPFD -- dump a file descriptor |
---|
| 1483 | ** |
---|
| 1484 | ** Parameters: |
---|
| 1485 | ** fd -- the file descriptor to dump. |
---|
| 1486 | ** printclosed -- if set, print a notification even if |
---|
| 1487 | ** it is closed; otherwise print nothing. |
---|
| 1488 | ** logit -- if set, send output to syslog instead of stdout. |
---|
| 1489 | */ |
---|
| 1490 | |
---|
| 1491 | void |
---|
| 1492 | dumpfd(fd, printclosed, logit) |
---|
| 1493 | int fd; |
---|
| 1494 | bool printclosed; |
---|
| 1495 | bool logit; |
---|
| 1496 | { |
---|
| 1497 | register char *p; |
---|
| 1498 | char *hp; |
---|
| 1499 | #ifdef S_IFSOCK |
---|
| 1500 | SOCKADDR sa; |
---|
| 1501 | #endif |
---|
| 1502 | auto SOCKADDR_LEN_T slen; |
---|
| 1503 | int i; |
---|
| 1504 | #if STAT64 > 0 |
---|
| 1505 | struct stat64 st; |
---|
| 1506 | #else |
---|
| 1507 | struct stat st; |
---|
| 1508 | #endif |
---|
| 1509 | char buf[200]; |
---|
| 1510 | |
---|
| 1511 | p = buf; |
---|
| 1512 | snprintf(p, SPACELEFT(buf, p), "%3d: ", fd); |
---|
| 1513 | p += strlen(p); |
---|
| 1514 | |
---|
| 1515 | if ( |
---|
| 1516 | #if STAT64 > 0 |
---|
| 1517 | fstat64(fd, &st) |
---|
| 1518 | #else |
---|
| 1519 | fstat(fd, &st) |
---|
| 1520 | #endif |
---|
| 1521 | < 0) |
---|
| 1522 | { |
---|
| 1523 | if (errno != EBADF) |
---|
| 1524 | { |
---|
| 1525 | snprintf(p, SPACELEFT(buf, p), "CANNOT STAT (%s)", |
---|
| 1526 | errstring(errno)); |
---|
| 1527 | goto printit; |
---|
| 1528 | } |
---|
| 1529 | else if (printclosed) |
---|
| 1530 | { |
---|
| 1531 | snprintf(p, SPACELEFT(buf, p), "CLOSED"); |
---|
| 1532 | goto printit; |
---|
| 1533 | } |
---|
| 1534 | return; |
---|
| 1535 | } |
---|
| 1536 | |
---|
| 1537 | i = fcntl(fd, F_GETFL, NULL); |
---|
| 1538 | if (i != -1) |
---|
| 1539 | { |
---|
| 1540 | snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i); |
---|
| 1541 | p += strlen(p); |
---|
| 1542 | } |
---|
| 1543 | |
---|
| 1544 | snprintf(p, SPACELEFT(buf, p), "mode=%o: ", st.st_mode); |
---|
| 1545 | p += strlen(p); |
---|
| 1546 | switch (st.st_mode & S_IFMT) |
---|
| 1547 | { |
---|
| 1548 | #ifdef S_IFSOCK |
---|
| 1549 | case S_IFSOCK: |
---|
| 1550 | snprintf(p, SPACELEFT(buf, p), "SOCK "); |
---|
| 1551 | p += strlen(p); |
---|
| 1552 | slen = sizeof sa; |
---|
| 1553 | if (getsockname(fd, &sa.sa, &slen) < 0) |
---|
| 1554 | snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno)); |
---|
| 1555 | else |
---|
| 1556 | { |
---|
| 1557 | hp = hostnamebyanyaddr(&sa); |
---|
| 1558 | if (sa.sa.sa_family == AF_INET) |
---|
| 1559 | snprintf(p, SPACELEFT(buf, p), "%s/%d", |
---|
| 1560 | hp, ntohs(sa.sin.sin_port)); |
---|
| 1561 | else |
---|
| 1562 | snprintf(p, SPACELEFT(buf, p), "%s", hp); |
---|
| 1563 | } |
---|
| 1564 | p += strlen(p); |
---|
| 1565 | snprintf(p, SPACELEFT(buf, p), "->"); |
---|
| 1566 | p += strlen(p); |
---|
| 1567 | slen = sizeof sa; |
---|
| 1568 | if (getpeername(fd, &sa.sa, &slen) < 0) |
---|
| 1569 | snprintf(p, SPACELEFT(buf, p), "(%s)", errstring(errno)); |
---|
| 1570 | else |
---|
| 1571 | { |
---|
| 1572 | hp = hostnamebyanyaddr(&sa); |
---|
| 1573 | if (sa.sa.sa_family == AF_INET) |
---|
| 1574 | snprintf(p, SPACELEFT(buf, p), "%s/%d", |
---|
| 1575 | hp, ntohs(sa.sin.sin_port)); |
---|
| 1576 | else |
---|
| 1577 | snprintf(p, SPACELEFT(buf, p), "%s", hp); |
---|
| 1578 | } |
---|
| 1579 | break; |
---|
| 1580 | #endif |
---|
| 1581 | |
---|
| 1582 | case S_IFCHR: |
---|
| 1583 | snprintf(p, SPACELEFT(buf, p), "CHR: "); |
---|
| 1584 | p += strlen(p); |
---|
| 1585 | goto defprint; |
---|
| 1586 | |
---|
| 1587 | case S_IFBLK: |
---|
| 1588 | snprintf(p, SPACELEFT(buf, p), "BLK: "); |
---|
| 1589 | p += strlen(p); |
---|
| 1590 | goto defprint; |
---|
| 1591 | |
---|
| 1592 | #if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) |
---|
| 1593 | case S_IFIFO: |
---|
| 1594 | snprintf(p, SPACELEFT(buf, p), "FIFO: "); |
---|
| 1595 | p += strlen(p); |
---|
| 1596 | goto defprint; |
---|
| 1597 | #endif |
---|
| 1598 | |
---|
| 1599 | #ifdef S_IFDIR |
---|
| 1600 | case S_IFDIR: |
---|
| 1601 | snprintf(p, SPACELEFT(buf, p), "DIR: "); |
---|
| 1602 | p += strlen(p); |
---|
| 1603 | goto defprint; |
---|
| 1604 | #endif |
---|
| 1605 | |
---|
| 1606 | #ifdef S_IFLNK |
---|
| 1607 | case S_IFLNK: |
---|
| 1608 | snprintf(p, SPACELEFT(buf, p), "LNK: "); |
---|
| 1609 | p += strlen(p); |
---|
| 1610 | goto defprint; |
---|
| 1611 | #endif |
---|
| 1612 | |
---|
| 1613 | default: |
---|
| 1614 | defprint: |
---|
| 1615 | if (sizeof st.st_ino > sizeof (long)) |
---|
| 1616 | snprintf(p, SPACELEFT(buf, p), |
---|
| 1617 | "dev=%d/%d, ino=%s, nlink=%d, u/gid=%d/%d, ", |
---|
| 1618 | major(st.st_dev), minor(st.st_dev), |
---|
| 1619 | quad_to_string(st.st_ino), |
---|
| 1620 | st.st_nlink, st.st_uid, st.st_gid); |
---|
| 1621 | else |
---|
| 1622 | snprintf(p, SPACELEFT(buf, p), |
---|
| 1623 | "dev=%d/%d, ino=%lu, nlink=%d, u/gid=%d/%d, ", |
---|
| 1624 | major(st.st_dev), minor(st.st_dev), |
---|
| 1625 | (unsigned long) st.st_ino, |
---|
| 1626 | st.st_nlink, st.st_uid, st.st_gid); |
---|
| 1627 | if (sizeof st.st_size > sizeof (long)) |
---|
| 1628 | snprintf(p, SPACELEFT(buf, p), "size=%s", |
---|
| 1629 | quad_to_string(st.st_size)); |
---|
| 1630 | else |
---|
| 1631 | snprintf(p, SPACELEFT(buf, p), "size=%lu", |
---|
| 1632 | (unsigned long) st.st_size); |
---|
| 1633 | break; |
---|
| 1634 | } |
---|
| 1635 | |
---|
| 1636 | printit: |
---|
| 1637 | if (logit) |
---|
| 1638 | sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL, |
---|
| 1639 | "%.800s", buf); |
---|
| 1640 | else |
---|
| 1641 | printf("%s\n", buf); |
---|
| 1642 | } |
---|
| 1643 | /* |
---|
| 1644 | ** SHORTEN_HOSTNAME -- strip local domain information off of hostname. |
---|
| 1645 | ** |
---|
| 1646 | ** Parameters: |
---|
| 1647 | ** host -- the host to shorten (stripped in place). |
---|
| 1648 | ** |
---|
| 1649 | ** Returns: |
---|
| 1650 | ** none. |
---|
| 1651 | */ |
---|
| 1652 | |
---|
| 1653 | void |
---|
| 1654 | shorten_hostname(host) |
---|
| 1655 | char host[]; |
---|
| 1656 | { |
---|
| 1657 | register char *p; |
---|
| 1658 | char *mydom; |
---|
| 1659 | int i; |
---|
| 1660 | bool canon = FALSE; |
---|
| 1661 | |
---|
| 1662 | /* strip off final dot */ |
---|
| 1663 | p = &host[strlen(host) - 1]; |
---|
| 1664 | if (*p == '.') |
---|
| 1665 | { |
---|
| 1666 | *p = '\0'; |
---|
| 1667 | canon = TRUE; |
---|
| 1668 | } |
---|
| 1669 | |
---|
| 1670 | /* see if there is any domain at all -- if not, we are done */ |
---|
| 1671 | p = strchr(host, '.'); |
---|
| 1672 | if (p == NULL) |
---|
| 1673 | return; |
---|
| 1674 | |
---|
| 1675 | /* yes, we have a domain -- see if it looks like us */ |
---|
| 1676 | mydom = macvalue('m', CurEnv); |
---|
| 1677 | if (mydom == NULL) |
---|
| 1678 | mydom = ""; |
---|
| 1679 | i = strlen(++p); |
---|
| 1680 | if ((canon ? strcasecmp(p, mydom) : strncasecmp(p, mydom, i)) == 0 && |
---|
| 1681 | (mydom[i] == '.' || mydom[i] == '\0')) |
---|
| 1682 | *--p = '\0'; |
---|
| 1683 | } |
---|
| 1684 | /* |
---|
| 1685 | ** PROG_OPEN -- open a program for reading |
---|
| 1686 | ** |
---|
| 1687 | ** Parameters: |
---|
| 1688 | ** argv -- the argument list. |
---|
| 1689 | ** pfd -- pointer to a place to store the file descriptor. |
---|
| 1690 | ** e -- the current envelope. |
---|
| 1691 | ** |
---|
| 1692 | ** Returns: |
---|
| 1693 | ** pid of the process -- -1 if it failed. |
---|
| 1694 | */ |
---|
| 1695 | |
---|
| 1696 | int |
---|
| 1697 | prog_open(argv, pfd, e) |
---|
| 1698 | char **argv; |
---|
| 1699 | int *pfd; |
---|
| 1700 | ENVELOPE *e; |
---|
| 1701 | { |
---|
| 1702 | int pid; |
---|
| 1703 | int i; |
---|
| 1704 | int saveerrno; |
---|
| 1705 | int fdv[2]; |
---|
| 1706 | char *p, *q; |
---|
| 1707 | char buf[MAXLINE + 1]; |
---|
| 1708 | extern int DtableSize; |
---|
| 1709 | |
---|
| 1710 | if (pipe(fdv) < 0) |
---|
| 1711 | { |
---|
| 1712 | syserr("%s: cannot create pipe for stdout", argv[0]); |
---|
| 1713 | return -1; |
---|
| 1714 | } |
---|
| 1715 | pid = fork(); |
---|
| 1716 | if (pid < 0) |
---|
| 1717 | { |
---|
| 1718 | syserr("%s: cannot fork", argv[0]); |
---|
| 1719 | close(fdv[0]); |
---|
| 1720 | close(fdv[1]); |
---|
| 1721 | return -1; |
---|
| 1722 | } |
---|
| 1723 | if (pid > 0) |
---|
| 1724 | { |
---|
| 1725 | /* parent */ |
---|
| 1726 | close(fdv[1]); |
---|
| 1727 | *pfd = fdv[0]; |
---|
| 1728 | return pid; |
---|
| 1729 | } |
---|
| 1730 | |
---|
| 1731 | /* child -- close stdin */ |
---|
| 1732 | close(0); |
---|
| 1733 | |
---|
| 1734 | /* stdout goes back to parent */ |
---|
| 1735 | close(fdv[0]); |
---|
| 1736 | if (dup2(fdv[1], 1) < 0) |
---|
| 1737 | { |
---|
| 1738 | syserr("%s: cannot dup2 for stdout", argv[0]); |
---|
| 1739 | _exit(EX_OSERR); |
---|
| 1740 | } |
---|
| 1741 | close(fdv[1]); |
---|
| 1742 | |
---|
| 1743 | /* stderr goes to transcript if available */ |
---|
| 1744 | if (e->e_xfp != NULL) |
---|
| 1745 | { |
---|
| 1746 | if (dup2(fileno(e->e_xfp), 2) < 0) |
---|
| 1747 | { |
---|
| 1748 | syserr("%s: cannot dup2 for stderr", argv[0]); |
---|
| 1749 | _exit(EX_OSERR); |
---|
| 1750 | } |
---|
| 1751 | } |
---|
| 1752 | |
---|
| 1753 | /* this process has no right to the queue file */ |
---|
| 1754 | if (e->e_lockfp != NULL) |
---|
| 1755 | close(fileno(e->e_lockfp)); |
---|
| 1756 | |
---|
| 1757 | /* run as default user */ |
---|
| 1758 | endpwent(); |
---|
| 1759 | if (setgid(DefGid) < 0 && geteuid() == 0) |
---|
| 1760 | syserr("prog_open: setgid(%ld) failed", (long) DefGid); |
---|
| 1761 | if (setuid(DefUid) < 0 && geteuid() == 0) |
---|
| 1762 | syserr("prog_open: setuid(%ld) failed", (long) DefUid); |
---|
| 1763 | |
---|
| 1764 | /* run in some directory */ |
---|
| 1765 | if (ProgMailer != NULL) |
---|
| 1766 | p = ProgMailer->m_execdir; |
---|
| 1767 | else |
---|
| 1768 | p = NULL; |
---|
| 1769 | for (; p != NULL; p = q) |
---|
| 1770 | { |
---|
| 1771 | q = strchr(p, ':'); |
---|
| 1772 | if (q != NULL) |
---|
| 1773 | *q = '\0'; |
---|
| 1774 | expand(p, buf, sizeof buf, e); |
---|
| 1775 | if (q != NULL) |
---|
| 1776 | *q++ = ':'; |
---|
| 1777 | if (buf[0] != '\0' && chdir(buf) >= 0) |
---|
| 1778 | break; |
---|
| 1779 | } |
---|
| 1780 | if (p == NULL) |
---|
| 1781 | { |
---|
| 1782 | /* backup directories */ |
---|
| 1783 | if (chdir("/tmp") < 0) |
---|
| 1784 | (void) chdir("/"); |
---|
| 1785 | } |
---|
| 1786 | |
---|
| 1787 | /* arrange for all the files to be closed */ |
---|
| 1788 | for (i = 3; i < DtableSize; i++) |
---|
| 1789 | { |
---|
| 1790 | register int j; |
---|
| 1791 | |
---|
| 1792 | if ((j = fcntl(i, F_GETFD, 0)) != -1) |
---|
| 1793 | (void) fcntl(i, F_SETFD, j | 1); |
---|
| 1794 | } |
---|
| 1795 | |
---|
| 1796 | /* now exec the process */ |
---|
| 1797 | execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron); |
---|
| 1798 | |
---|
| 1799 | /* woops! failed */ |
---|
| 1800 | saveerrno = errno; |
---|
| 1801 | syserr("%s: cannot exec", argv[0]); |
---|
| 1802 | if (transienterror(saveerrno)) |
---|
| 1803 | _exit(EX_OSERR); |
---|
| 1804 | _exit(EX_CONFIG); |
---|
| 1805 | return -1; /* avoid compiler warning on IRIX */ |
---|
| 1806 | } |
---|
| 1807 | /* |
---|
| 1808 | ** GET_COLUMN -- look up a Column in a line buffer |
---|
| 1809 | ** |
---|
| 1810 | ** Parameters: |
---|
| 1811 | ** line -- the raw text line to search. |
---|
| 1812 | ** col -- the column number to fetch. |
---|
| 1813 | ** delim -- the delimiter between columns. If null, |
---|
| 1814 | ** use white space. |
---|
| 1815 | ** buf -- the output buffer. |
---|
| 1816 | ** buflen -- the length of buf. |
---|
| 1817 | ** |
---|
| 1818 | ** Returns: |
---|
| 1819 | ** buf if successful. |
---|
| 1820 | ** NULL otherwise. |
---|
| 1821 | */ |
---|
| 1822 | |
---|
| 1823 | char * |
---|
| 1824 | get_column(line, col, delim, buf, buflen) |
---|
| 1825 | char line[]; |
---|
| 1826 | int col; |
---|
| 1827 | char delim; |
---|
| 1828 | char buf[]; |
---|
| 1829 | int buflen; |
---|
| 1830 | { |
---|
| 1831 | char *p; |
---|
| 1832 | char *begin, *end; |
---|
| 1833 | int i; |
---|
| 1834 | char delimbuf[4]; |
---|
| 1835 | |
---|
| 1836 | if (delim == '\0') |
---|
| 1837 | strcpy(delimbuf, "\n\t "); |
---|
| 1838 | else |
---|
| 1839 | { |
---|
| 1840 | delimbuf[0] = delim; |
---|
| 1841 | delimbuf[1] = '\0'; |
---|
| 1842 | } |
---|
| 1843 | |
---|
| 1844 | p = line; |
---|
| 1845 | if (*p == '\0') |
---|
| 1846 | return NULL; /* line empty */ |
---|
| 1847 | if (*p == delim && col == 0) |
---|
| 1848 | return NULL; /* first column empty */ |
---|
| 1849 | |
---|
| 1850 | begin = line; |
---|
| 1851 | |
---|
| 1852 | if (col == 0 && delim == '\0') |
---|
| 1853 | { |
---|
| 1854 | while (*begin != '\0' && isascii(*begin) && isspace(*begin)) |
---|
| 1855 | begin++; |
---|
| 1856 | } |
---|
| 1857 | |
---|
| 1858 | for (i = 0; i < col; i++) |
---|
| 1859 | { |
---|
| 1860 | if ((begin = strpbrk(begin, delimbuf)) == NULL) |
---|
| 1861 | return NULL; /* no such column */ |
---|
| 1862 | begin++; |
---|
| 1863 | if (delim == '\0') |
---|
| 1864 | { |
---|
| 1865 | while (*begin != '\0' && isascii(*begin) && isspace(*begin)) |
---|
| 1866 | begin++; |
---|
| 1867 | } |
---|
| 1868 | } |
---|
| 1869 | |
---|
| 1870 | end = strpbrk(begin, delimbuf); |
---|
| 1871 | if (end == NULL) |
---|
| 1872 | i = strlen(begin); |
---|
| 1873 | else |
---|
| 1874 | i = end - begin; |
---|
| 1875 | if (i >= buflen) |
---|
| 1876 | i = buflen - 1; |
---|
| 1877 | strncpy(buf, begin, i); |
---|
| 1878 | buf[i] = '\0'; |
---|
| 1879 | return buf; |
---|
| 1880 | } |
---|
| 1881 | /* |
---|
| 1882 | ** CLEANSTRCPY -- copy string keeping out bogus characters |
---|
| 1883 | ** |
---|
| 1884 | ** Parameters: |
---|
| 1885 | ** t -- "to" string. |
---|
| 1886 | ** f -- "from" string. |
---|
| 1887 | ** l -- length of space available in "to" string. |
---|
| 1888 | ** |
---|
| 1889 | ** Returns: |
---|
| 1890 | ** none. |
---|
| 1891 | */ |
---|
| 1892 | |
---|
| 1893 | void |
---|
| 1894 | cleanstrcpy(t, f, l) |
---|
| 1895 | register char *t; |
---|
| 1896 | register char *f; |
---|
| 1897 | int l; |
---|
| 1898 | { |
---|
| 1899 | /* check for newlines and log if necessary */ |
---|
| 1900 | (void) denlstring(f, TRUE, TRUE); |
---|
| 1901 | |
---|
| 1902 | l--; |
---|
| 1903 | while (l > 0 && *f != '\0') |
---|
| 1904 | { |
---|
| 1905 | if (isascii(*f) && |
---|
| 1906 | (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) |
---|
| 1907 | { |
---|
| 1908 | l--; |
---|
| 1909 | *t++ = *f; |
---|
| 1910 | } |
---|
| 1911 | f++; |
---|
| 1912 | } |
---|
| 1913 | *t = '\0'; |
---|
| 1914 | } |
---|
| 1915 | /* |
---|
| 1916 | ** DENLSTRING -- convert newlines in a string to spaces |
---|
| 1917 | ** |
---|
| 1918 | ** Parameters: |
---|
| 1919 | ** s -- the input string |
---|
| 1920 | ** strict -- if set, don't permit continuation lines. |
---|
| 1921 | ** logattacks -- if set, log attempted attacks. |
---|
| 1922 | ** |
---|
| 1923 | ** Returns: |
---|
| 1924 | ** A pointer to a version of the string with newlines |
---|
| 1925 | ** mapped to spaces. This should be copied. |
---|
| 1926 | */ |
---|
| 1927 | |
---|
| 1928 | char * |
---|
| 1929 | denlstring(s, strict, logattacks) |
---|
| 1930 | char *s; |
---|
| 1931 | bool strict; |
---|
| 1932 | bool logattacks; |
---|
| 1933 | { |
---|
| 1934 | register char *p; |
---|
| 1935 | int l; |
---|
| 1936 | static char *bp = NULL; |
---|
| 1937 | static int bl = 0; |
---|
| 1938 | |
---|
| 1939 | p = s; |
---|
| 1940 | while ((p = strchr(p, '\n')) != NULL) |
---|
| 1941 | if (strict || (*++p != ' ' && *p != '\t')) |
---|
| 1942 | break; |
---|
| 1943 | if (p == NULL) |
---|
| 1944 | return s; |
---|
| 1945 | |
---|
| 1946 | l = strlen(s) + 1; |
---|
| 1947 | if (bl < l) |
---|
| 1948 | { |
---|
| 1949 | /* allocate more space */ |
---|
| 1950 | if (bp != NULL) |
---|
| 1951 | free(bp); |
---|
| 1952 | bp = xalloc(l); |
---|
| 1953 | bl = l; |
---|
| 1954 | } |
---|
| 1955 | strcpy(bp, s); |
---|
| 1956 | for (p = bp; (p = strchr(p, '\n')) != NULL; ) |
---|
| 1957 | *p++ = ' '; |
---|
| 1958 | |
---|
| 1959 | if (logattacks) |
---|
| 1960 | { |
---|
| 1961 | sm_syslog(LOG_NOTICE, CurEnv->e_id, |
---|
| 1962 | "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", |
---|
| 1963 | RealHostName == NULL ? "[UNKNOWN]" : RealHostName, |
---|
| 1964 | shortenstring(bp, MAXSHORTSTR)); |
---|
| 1965 | } |
---|
| 1966 | |
---|
| 1967 | return bp; |
---|
| 1968 | } |
---|
| 1969 | /* |
---|
| 1970 | ** PATH_IS_DIR -- check to see if file exists and is a directory. |
---|
| 1971 | ** |
---|
| 1972 | ** There are some additional checks for security violations in |
---|
| 1973 | ** here. This routine is intended to be used for the host status |
---|
| 1974 | ** support. |
---|
| 1975 | ** |
---|
| 1976 | ** Parameters: |
---|
| 1977 | ** pathname -- pathname to check for directory-ness. |
---|
| 1978 | ** createflag -- if set, create directory if needed. |
---|
| 1979 | ** |
---|
| 1980 | ** Returns: |
---|
| 1981 | ** TRUE -- if the indicated pathname is a directory |
---|
| 1982 | ** FALSE -- otherwise |
---|
| 1983 | */ |
---|
| 1984 | |
---|
| 1985 | int |
---|
| 1986 | path_is_dir(pathname, createflag) |
---|
| 1987 | char *pathname; |
---|
| 1988 | bool createflag; |
---|
| 1989 | { |
---|
| 1990 | struct stat statbuf; |
---|
| 1991 | |
---|
| 1992 | #if HASLSTAT |
---|
| 1993 | if (lstat(pathname, &statbuf) < 0) |
---|
| 1994 | #else |
---|
| 1995 | if (stat(pathname, &statbuf) < 0) |
---|
| 1996 | #endif |
---|
| 1997 | { |
---|
| 1998 | if (errno != ENOENT || !createflag) |
---|
| 1999 | return FALSE; |
---|
| 2000 | if (mkdir(pathname, 0755) < 0) |
---|
| 2001 | return FALSE; |
---|
| 2002 | return TRUE; |
---|
| 2003 | } |
---|
| 2004 | if (!S_ISDIR(statbuf.st_mode)) |
---|
| 2005 | { |
---|
| 2006 | errno = ENOTDIR; |
---|
| 2007 | return FALSE; |
---|
| 2008 | } |
---|
| 2009 | |
---|
| 2010 | /* security: don't allow writable directories */ |
---|
| 2011 | if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) |
---|
| 2012 | { |
---|
| 2013 | errno = EACCES; |
---|
| 2014 | return FALSE; |
---|
| 2015 | } |
---|
| 2016 | |
---|
| 2017 | return TRUE; |
---|
| 2018 | } |
---|
| 2019 | /* |
---|
| 2020 | ** PROC_LIST_ADD -- add process id to list of our children |
---|
| 2021 | ** |
---|
| 2022 | ** Parameters: |
---|
| 2023 | ** pid -- pid to add to list. |
---|
| 2024 | ** |
---|
| 2025 | ** Returns: |
---|
| 2026 | ** none |
---|
| 2027 | */ |
---|
| 2028 | |
---|
| 2029 | struct procs |
---|
| 2030 | { |
---|
| 2031 | pid_t proc_pid; |
---|
| 2032 | char *proc_task; |
---|
| 2033 | }; |
---|
| 2034 | |
---|
| 2035 | static struct procs *ProcListVec = NULL; |
---|
| 2036 | static int ProcListSize = 0; |
---|
| 2037 | |
---|
| 2038 | #define NO_PID ((pid_t) 0) |
---|
| 2039 | #ifndef PROC_LIST_SEG |
---|
| 2040 | # define PROC_LIST_SEG 32 /* number of pids to alloc at a time */ |
---|
| 2041 | #endif |
---|
| 2042 | |
---|
| 2043 | void |
---|
| 2044 | proc_list_add(pid, task) |
---|
| 2045 | pid_t pid; |
---|
| 2046 | char *task; |
---|
| 2047 | { |
---|
| 2048 | int i; |
---|
| 2049 | |
---|
| 2050 | for (i = 0; i < ProcListSize; i++) |
---|
| 2051 | { |
---|
| 2052 | if (ProcListVec[i].proc_pid == NO_PID) |
---|
| 2053 | break; |
---|
| 2054 | } |
---|
| 2055 | if (i >= ProcListSize) |
---|
| 2056 | { |
---|
| 2057 | /* probe the existing vector to avoid growing infinitely */ |
---|
| 2058 | proc_list_probe(); |
---|
| 2059 | |
---|
| 2060 | /* now scan again */ |
---|
| 2061 | for (i = 0; i < ProcListSize; i++) |
---|
| 2062 | { |
---|
| 2063 | if (ProcListVec[i].proc_pid == NO_PID) |
---|
| 2064 | break; |
---|
| 2065 | } |
---|
| 2066 | } |
---|
| 2067 | if (i >= ProcListSize) |
---|
| 2068 | { |
---|
| 2069 | /* grow process list */ |
---|
| 2070 | struct procs *npv; |
---|
| 2071 | |
---|
| 2072 | npv = (struct procs *) xalloc(sizeof (struct procs) * (ProcListSize + PROC_LIST_SEG)); |
---|
| 2073 | if (ProcListSize > 0) |
---|
| 2074 | { |
---|
| 2075 | bcopy(ProcListVec, npv, ProcListSize * |
---|
| 2076 | sizeof (struct procs)); |
---|
| 2077 | free(ProcListVec); |
---|
| 2078 | } |
---|
| 2079 | for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) |
---|
| 2080 | { |
---|
| 2081 | npv[i].proc_pid = NO_PID; |
---|
| 2082 | npv[i].proc_task = NULL; |
---|
| 2083 | } |
---|
| 2084 | i = ProcListSize; |
---|
| 2085 | ProcListSize += PROC_LIST_SEG; |
---|
| 2086 | ProcListVec = npv; |
---|
| 2087 | } |
---|
| 2088 | ProcListVec[i].proc_pid = pid; |
---|
| 2089 | ProcListVec[i].proc_task = newstr(task); |
---|
| 2090 | |
---|
| 2091 | /* if process adding itself, it's not a child */ |
---|
| 2092 | if (pid != getpid()) |
---|
| 2093 | CurChildren++; |
---|
| 2094 | } |
---|
| 2095 | /* |
---|
| 2096 | ** PROC_LIST_SET -- set pid task in process list |
---|
| 2097 | ** |
---|
| 2098 | ** Parameters: |
---|
| 2099 | ** pid -- pid to set |
---|
| 2100 | ** task -- task of pid |
---|
| 2101 | ** |
---|
| 2102 | ** Returns: |
---|
| 2103 | ** none. |
---|
| 2104 | */ |
---|
| 2105 | |
---|
| 2106 | void |
---|
| 2107 | proc_list_set(pid, task) |
---|
| 2108 | pid_t pid; |
---|
| 2109 | char *task; |
---|
| 2110 | { |
---|
| 2111 | int i; |
---|
| 2112 | |
---|
| 2113 | for (i = 0; i < ProcListSize; i++) |
---|
| 2114 | { |
---|
| 2115 | if (ProcListVec[i].proc_pid == pid) |
---|
| 2116 | { |
---|
| 2117 | if (ProcListVec[i].proc_task != NULL) |
---|
| 2118 | free(ProcListVec[i].proc_task); |
---|
| 2119 | ProcListVec[i].proc_task = newstr(task); |
---|
| 2120 | break; |
---|
| 2121 | } |
---|
| 2122 | } |
---|
| 2123 | } |
---|
| 2124 | /* |
---|
| 2125 | ** PROC_LIST_DROP -- drop pid from process list |
---|
| 2126 | ** |
---|
| 2127 | ** Parameters: |
---|
| 2128 | ** pid -- pid to drop |
---|
| 2129 | ** |
---|
| 2130 | ** Returns: |
---|
| 2131 | ** none. |
---|
| 2132 | */ |
---|
| 2133 | |
---|
| 2134 | void |
---|
| 2135 | proc_list_drop(pid) |
---|
| 2136 | pid_t pid; |
---|
| 2137 | { |
---|
| 2138 | int i; |
---|
| 2139 | |
---|
| 2140 | for (i = 0; i < ProcListSize; i++) |
---|
| 2141 | { |
---|
| 2142 | if (ProcListVec[i].proc_pid == pid) |
---|
| 2143 | { |
---|
| 2144 | ProcListVec[i].proc_pid = NO_PID; |
---|
| 2145 | if (ProcListVec[i].proc_task != NULL) |
---|
| 2146 | { |
---|
| 2147 | free(ProcListVec[i].proc_task); |
---|
| 2148 | ProcListVec[i].proc_task = NULL; |
---|
| 2149 | } |
---|
| 2150 | break; |
---|
| 2151 | } |
---|
| 2152 | } |
---|
| 2153 | if (CurChildren > 0) |
---|
| 2154 | CurChildren--; |
---|
| 2155 | } |
---|
| 2156 | /* |
---|
| 2157 | ** PROC_LIST_CLEAR -- clear the process list |
---|
| 2158 | ** |
---|
| 2159 | ** Parameters: |
---|
| 2160 | ** none. |
---|
| 2161 | ** |
---|
| 2162 | ** Returns: |
---|
| 2163 | ** none. |
---|
| 2164 | */ |
---|
| 2165 | |
---|
| 2166 | void |
---|
| 2167 | proc_list_clear() |
---|
| 2168 | { |
---|
| 2169 | int i; |
---|
| 2170 | |
---|
| 2171 | /* start from 1 since 0 is the daemon itself */ |
---|
| 2172 | for (i = 1; i < ProcListSize; i++) |
---|
| 2173 | { |
---|
| 2174 | ProcListVec[i].proc_pid = NO_PID; |
---|
| 2175 | if (ProcListVec[i].proc_task != NULL) |
---|
| 2176 | { |
---|
| 2177 | free(ProcListVec[i].proc_task); |
---|
| 2178 | ProcListVec[i].proc_task = NULL; |
---|
| 2179 | } |
---|
| 2180 | } |
---|
| 2181 | CurChildren = 0; |
---|
| 2182 | } |
---|
| 2183 | /* |
---|
| 2184 | ** PROC_LIST_PROBE -- probe processes in the list to see if they still exist |
---|
| 2185 | ** |
---|
| 2186 | ** Parameters: |
---|
| 2187 | ** none |
---|
| 2188 | ** |
---|
| 2189 | ** Returns: |
---|
| 2190 | ** none |
---|
| 2191 | */ |
---|
| 2192 | |
---|
| 2193 | void |
---|
| 2194 | proc_list_probe() |
---|
| 2195 | { |
---|
| 2196 | int i; |
---|
| 2197 | |
---|
| 2198 | /* start from 1 since 0 is the daemon itself */ |
---|
| 2199 | for (i = 1; i < ProcListSize; i++) |
---|
| 2200 | { |
---|
| 2201 | if (ProcListVec[i].proc_pid == NO_PID) |
---|
| 2202 | continue; |
---|
| 2203 | if (kill(ProcListVec[i].proc_pid, 0) < 0) |
---|
| 2204 | { |
---|
| 2205 | if (LogLevel > 3) |
---|
| 2206 | sm_syslog(LOG_DEBUG, CurEnv->e_id, |
---|
| 2207 | "proc_list_probe: lost pid %d", |
---|
| 2208 | (int) ProcListVec[i].proc_pid); |
---|
| 2209 | ProcListVec[i].proc_pid = NO_PID; |
---|
| 2210 | if (ProcListVec[i].proc_task != NULL) |
---|
| 2211 | { |
---|
| 2212 | free(ProcListVec[i].proc_task); |
---|
| 2213 | ProcListVec[i].proc_task = NULL; |
---|
| 2214 | } |
---|
| 2215 | CurChildren--; |
---|
| 2216 | } |
---|
| 2217 | } |
---|
| 2218 | if (CurChildren < 0) |
---|
| 2219 | CurChildren = 0; |
---|
| 2220 | } |
---|
| 2221 | /* |
---|
| 2222 | ** PROC_LIST_DISPLAY -- display the process list |
---|
| 2223 | ** |
---|
| 2224 | ** Parameters: |
---|
| 2225 | ** out -- output file pointer |
---|
| 2226 | ** |
---|
| 2227 | ** Returns: |
---|
| 2228 | ** none. |
---|
| 2229 | */ |
---|
| 2230 | |
---|
| 2231 | void |
---|
| 2232 | proc_list_display(out) |
---|
| 2233 | FILE *out; |
---|
| 2234 | { |
---|
| 2235 | int i; |
---|
| 2236 | |
---|
| 2237 | for (i = 0; i < ProcListSize; i++) |
---|
| 2238 | { |
---|
| 2239 | if (ProcListVec[i].proc_pid == NO_PID) |
---|
| 2240 | continue; |
---|
| 2241 | |
---|
| 2242 | fprintf(out, "%d %s%s\n", (int) ProcListVec[i].proc_pid, |
---|
| 2243 | ProcListVec[i].proc_task != NULL ? |
---|
| 2244 | ProcListVec[i].proc_task : "(unknown)", |
---|
| 2245 | (OpMode == MD_SMTP || |
---|
| 2246 | OpMode == MD_DAEMON || |
---|
| 2247 | OpMode == MD_ARPAFTP) ? "\r" : ""); |
---|
| 2248 | } |
---|
| 2249 | } |
---|
| 2250 | /* |
---|
| 2251 | ** SM_STRCASECMP -- 8-bit clean version of strcasecmp |
---|
| 2252 | ** |
---|
| 2253 | ** Thank you, vendors, for making this all necessary. |
---|
| 2254 | */ |
---|
| 2255 | |
---|
| 2256 | /* |
---|
| 2257 | * Copyright (c) 1987, 1993 |
---|
| 2258 | * The Regents of the University of California. All rights reserved. |
---|
| 2259 | * |
---|
| 2260 | * Redistribution and use in source and binary forms, with or without |
---|
| 2261 | * modification, are permitted provided that the following conditions |
---|
| 2262 | * are met: |
---|
| 2263 | * 1. Redistributions of source code must retain the above copyright |
---|
| 2264 | * notice, this list of conditions and the following disclaimer. |
---|
| 2265 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 2266 | * notice, this list of conditions and the following disclaimer in the |
---|
| 2267 | * documentation and/or other materials provided with the distribution. |
---|
| 2268 | * 3. All advertising materials mentioning features or use of this software |
---|
| 2269 | * must display the following acknowledgement: |
---|
| 2270 | * This product includes software developed by the University of |
---|
| 2271 | * California, Berkeley and its contributors. |
---|
| 2272 | * 4. Neither the name of the University nor the names of its contributors |
---|
| 2273 | * may be used to endorse or promote products derived from this software |
---|
| 2274 | * without specific prior written permission. |
---|
| 2275 | * |
---|
| 2276 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
| 2277 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 2278 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 2279 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
| 2280 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
| 2281 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
| 2282 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
| 2283 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
| 2284 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
| 2285 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
| 2286 | * SUCH DAMAGE. |
---|
| 2287 | */ |
---|
| 2288 | |
---|
| 2289 | #if defined(LIBC_SCCS) && !defined(lint) |
---|
| 2290 | static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93"; |
---|
| 2291 | #endif /* LIBC_SCCS and not lint */ |
---|
| 2292 | |
---|
| 2293 | /* |
---|
| 2294 | * This array is designed for mapping upper and lower case letter |
---|
| 2295 | * together for a case independent comparison. The mappings are |
---|
| 2296 | * based upon ascii character sequences. |
---|
| 2297 | */ |
---|
| 2298 | static const u_char charmap[] = { |
---|
| 2299 | 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, |
---|
| 2300 | 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, |
---|
| 2301 | 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, |
---|
| 2302 | 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, |
---|
| 2303 | 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, |
---|
| 2304 | 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, |
---|
| 2305 | 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, |
---|
| 2306 | 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, |
---|
| 2307 | 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, |
---|
| 2308 | 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, |
---|
| 2309 | 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, |
---|
| 2310 | 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, |
---|
| 2311 | 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, |
---|
| 2312 | 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, |
---|
| 2313 | 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, |
---|
| 2314 | 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, |
---|
| 2315 | 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, |
---|
| 2316 | 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, |
---|
| 2317 | 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, |
---|
| 2318 | 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, |
---|
| 2319 | 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, |
---|
| 2320 | 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, |
---|
| 2321 | 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, |
---|
| 2322 | 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, |
---|
| 2323 | 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, |
---|
| 2324 | 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, |
---|
| 2325 | 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, |
---|
| 2326 | 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, |
---|
| 2327 | 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, |
---|
| 2328 | 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, |
---|
| 2329 | 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, |
---|
| 2330 | 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, |
---|
| 2331 | }; |
---|
| 2332 | |
---|
| 2333 | int |
---|
| 2334 | sm_strcasecmp(s1, s2) |
---|
| 2335 | const char *s1, *s2; |
---|
| 2336 | { |
---|
| 2337 | register const u_char *cm = charmap, |
---|
| 2338 | *us1 = (const u_char *)s1, |
---|
| 2339 | *us2 = (const u_char *)s2; |
---|
| 2340 | |
---|
| 2341 | while (cm[*us1] == cm[*us2++]) |
---|
| 2342 | if (*us1++ == '\0') |
---|
| 2343 | return (0); |
---|
| 2344 | return (cm[*us1] - cm[*--us2]); |
---|
| 2345 | } |
---|
| 2346 | |
---|
| 2347 | int |
---|
| 2348 | sm_strncasecmp(s1, s2, n) |
---|
| 2349 | const char *s1, *s2; |
---|
| 2350 | register size_t n; |
---|
| 2351 | { |
---|
| 2352 | if (n != 0) { |
---|
| 2353 | register const u_char *cm = charmap, |
---|
| 2354 | *us1 = (const u_char *)s1, |
---|
| 2355 | *us2 = (const u_char *)s2; |
---|
| 2356 | |
---|
| 2357 | do { |
---|
| 2358 | if (cm[*us1] != cm[*us2++]) |
---|
| 2359 | return (cm[*us1] - cm[*--us2]); |
---|
| 2360 | if (*us1++ == '\0') |
---|
| 2361 | break; |
---|
| 2362 | } while (--n != 0); |
---|
| 2363 | } |
---|
| 2364 | return (0); |
---|
| 2365 | } |
---|