util.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:46k
源码类别:

Email客户端

开发平台:

Unix_Linux

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