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

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: parseaddr.c,v 8.231 1999/12/06 21:48:51 ca Exp $";
  15. #endif /* ! lint */
  16. #include <sendmail.h>
  17. static void allocaddr __P((ADDRESS *, int, char *));
  18. static int callsubr __P((char**, int, ENVELOPE *));
  19. static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
  20. static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
  21. /*
  22. **  PARSEADDR -- Parse an address
  23. **
  24. ** Parses an address and breaks it up into three parts: a
  25. ** net to transmit the message on, the host to transmit it
  26. ** to, and a user on that host.  These are loaded into an
  27. ** ADDRESS header with the values squirreled away if necessary.
  28. ** The "user" part may not be a real user; the process may
  29. ** just reoccur on that machine.  For example, on a machine
  30. ** with an arpanet connection, the address
  31. ** csvax.bill@berkeley
  32. ** will break up to a "user" of 'csvax.bill' and a host
  33. ** of 'berkeley' -- to be transmitted over the arpanet.
  34. **
  35. ** Parameters:
  36. ** addr -- the address to parse.
  37. ** a -- a pointer to the address descriptor buffer.
  38. ** If NULL, a header will be created.
  39. ** flags -- describe detail for parsing.  See RF_ definitions
  40. ** in sendmail.h.
  41. ** delim -- the character to terminate the address, passed
  42. ** to prescan.
  43. ** delimptr -- if non-NULL, set to the location of the
  44. ** delim character that was found.
  45. ** e -- the envelope that will contain this address.
  46. **
  47. ** Returns:
  48. ** A pointer to the address descriptor header (`a' if
  49. ** `a' is non-NULL).
  50. ** NULL on error.
  51. **
  52. ** Side Effects:
  53. ** none
  54. */
  55. /* following delimiters are inherent to the internal algorithms */
  56. #define DELIMCHARS "()<>,;rn" /* default word delimiters */
  57. ADDRESS *
  58. parseaddr(addr, a, flags, delim, delimptr, e)
  59. char *addr;
  60. register ADDRESS *a;
  61. int flags;
  62. int delim;
  63. char **delimptr;
  64. register ENVELOPE *e;
  65. {
  66. register char **pvp;
  67. auto char *delimptrbuf;
  68. bool qup;
  69. char pvpbuf[PSBUFSIZE];
  70. /*
  71. **  Initialize and prescan address.
  72. */
  73. e->e_to = addr;
  74. if (tTd(20, 1))
  75. dprintf("n--parseaddr(%s)n", addr);
  76. if (delimptr == NULL)
  77. delimptr = &delimptrbuf;
  78. pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
  79. if (pvp == NULL)
  80. {
  81. if (tTd(20, 1))
  82. dprintf("parseaddr-->NULLn");
  83. return NULL;
  84. }
  85. if (invalidaddr(addr, delim == '' ? NULL : *delimptr))
  86. {
  87. if (tTd(20, 1))
  88. dprintf("parseaddr-->bad addressn");
  89. return NULL;
  90. }
  91. /*
  92. **  Save addr if we are going to have to.
  93. **
  94. ** We have to do this early because there is a chance that
  95. ** the map lookups in the rewriting rules could clobber
  96. ** static memory somewhere.
  97. */
  98. if (bitset(RF_COPYPADDR, flags) && addr != NULL)
  99. {
  100. char savec = **delimptr;
  101. if (savec != '')
  102. **delimptr = '';
  103. e->e_to = addr = newstr(addr);
  104. if (savec != '')
  105. **delimptr = savec;
  106. }
  107. /*
  108. **  Apply rewriting rules.
  109. ** Ruleset 0 does basic parsing.  It must resolve.
  110. */
  111. qup = FALSE;
  112. if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
  113. qup = TRUE;
  114. if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
  115. qup = TRUE;
  116. /*
  117. **  Build canonical address from pvp.
  118. */
  119. a = buildaddr(pvp, a, flags, e);
  120. /*
  121. **  Make local copies of the host & user and then
  122. **  transport them out.
  123. */
  124. allocaddr(a, flags, addr);
  125. if (QS_IS_BADADDR(a->q_state))
  126. return a;
  127. /*
  128. **  If there was a parsing failure, mark it for queueing.
  129. */
  130. if (qup && OpMode != MD_INITALIAS)
  131. {
  132. char *msg = "Transient parse error -- message queued for future delivery";
  133. if (e->e_sendmode == SM_DEFER)
  134. msg = "Deferring message until queue run";
  135. if (tTd(20, 1))
  136. dprintf("parseaddr: queuing messagen");
  137. message(msg);
  138. if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
  139. e->e_message = newstr(msg);
  140. a->q_state = QS_QUEUEUP;
  141. a->q_status = "4.4.3";
  142. }
  143. /*
  144. **  Compute return value.
  145. */
  146. if (tTd(20, 1))
  147. {
  148. dprintf("parseaddr-->");
  149. printaddr(a, FALSE);
  150. }
  151. return a;
  152. }
  153. /*
  154. **  INVALIDADDR -- check for address containing meta-characters
  155. **
  156. ** Parameters:
  157. ** addr -- the address to check.
  158. **
  159. ** Returns:
  160. ** TRUE -- if the address has any "wierd" characters
  161. ** FALSE -- otherwise.
  162. */
  163. bool
  164. invalidaddr(addr, delimptr)
  165. register char *addr;
  166. char *delimptr;
  167. {
  168. char savedelim = '';
  169. if (delimptr != NULL)
  170. {
  171. savedelim = *delimptr;
  172. if (savedelim != '')
  173. *delimptr = '';
  174. }
  175. if (strlen(addr) > MAXNAME - 1)
  176. {
  177. usrerr("553 5.1.1 Address too long (%d bytes max)",
  178.        MAXNAME - 1);
  179. goto failure;
  180. }
  181. for (; *addr != ''; addr++)
  182. {
  183. if ((*addr & 0340) == 0200)
  184. break;
  185. }
  186. if (*addr == '')
  187. {
  188. if (delimptr != NULL && savedelim != '')
  189. *delimptr = savedelim;
  190. return FALSE;
  191. }
  192. setstat(EX_USAGE);
  193. usrerr("553 5.1.1 Address contained invalid control characters");
  194. failure:
  195. if (delimptr != NULL && savedelim != '')
  196. *delimptr = savedelim;
  197. return TRUE;
  198. }
  199. /*
  200. **  ALLOCADDR -- do local allocations of address on demand.
  201. **
  202. ** Also lowercases the host name if requested.
  203. **
  204. ** Parameters:
  205. ** a -- the address to reallocate.
  206. ** flags -- the copy flag (see RF_ definitions in sendmail.h
  207. ** for a description).
  208. ** paddr -- the printname of the address.
  209. **
  210. ** Returns:
  211. ** none.
  212. **
  213. ** Side Effects:
  214. ** Copies portions of a into local buffers as requested.
  215. */
  216. static void
  217. allocaddr(a, flags, paddr)
  218. register ADDRESS *a;
  219. int flags;
  220. char *paddr;
  221. {
  222. if (tTd(24, 4))
  223. dprintf("allocaddr(flags=%x, paddr=%s)n", flags, paddr);
  224. a->q_paddr = paddr;
  225. if (a->q_user == NULL)
  226. a->q_user = newstr("");
  227. if (a->q_host == NULL)
  228. a->q_host = newstr("");
  229. if (bitset(RF_COPYPARSE, flags))
  230. {
  231. a->q_host = newstr(a->q_host);
  232. if (a->q_user != a->q_paddr)
  233. a->q_user = newstr(a->q_user);
  234. }
  235. if (a->q_paddr == NULL)
  236. a->q_paddr = newstr(a->q_user);
  237. }
  238. /*
  239. **  PRESCAN -- Prescan name and make it canonical
  240. **
  241. ** Scans a name and turns it into a set of tokens.  This process
  242. ** deletes blanks and comments (in parentheses) (if the token type
  243. ** for left paren is SPC).
  244. **
  245. ** This routine knows about quoted strings and angle brackets.
  246. **
  247. ** There are certain subtleties to this routine.  The one that
  248. ** comes to mind now is that backslashes on the ends of names
  249. ** are silently stripped off; this is intentional.  The problem
  250. ** is that some versions of sndmsg (like at LBL) set the kill
  251. ** character to something other than @ when reading addresses;
  252. ** so people type "csvax.eric@berkeley" -- which screws up the
  253. ** berknet mailer.
  254. **
  255. ** Parameters:
  256. ** addr -- the name to chomp.
  257. ** delim -- the delimiter for the address, normally
  258. ** '' or ',';  is accepted in any case.
  259. ** If 't' then we are reading the .cf file.
  260. ** pvpbuf -- place to put the saved text -- note that
  261. ** the pointers are static.
  262. ** pvpbsize -- size of pvpbuf.
  263. ** delimptr -- if non-NULL, set to the location of the
  264. ** terminating delimiter.
  265. ** toktab -- if set, a token table to use for parsing.
  266. ** If NULL, use the default table.
  267. **
  268. ** Returns:
  269. ** A pointer to a vector of tokens.
  270. ** NULL on error.
  271. */
  272. /* states and character types */
  273. #define OPR 0 /* operator */
  274. #define ATM 1 /* atom */
  275. #define QST 2 /* in quoted string */
  276. #define SPC 3 /* chewing up spaces */
  277. #define ONE 4 /* pick up one character */
  278. #define ILL 5 /* illegal character */
  279. #define NSTATES 6 /* number of states */
  280. #define TYPE 017 /* mask to select state type */
  281. /* meta bits for table */
  282. #define M 020 /* meta character; don't pass through */
  283. #define B 040 /* cause a break */
  284. #define MB M|B /* meta-break */
  285. static short StateTab[NSTATES][NSTATES] =
  286. {
  287.    /* oldst chtype> OPR ATM QST SPC ONE ILL */
  288. /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB },
  289. /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB },
  290. /*QST*/ { QST, QST, OPR, QST, QST, QST },
  291. /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB },
  292. /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB },
  293. /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M },
  294. };
  295. /* token type table -- it gets modified with $o characters */
  296. static u_char TokTypeTab[256] =
  297. {
  298.     /* nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
  299. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
  300.     /* dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
  301. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  302.     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
  303. SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
  304.     /* 0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
  305. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  306.     /* @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
  307. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  308.     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [      ]   ^   _    */
  309. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  310.     /* `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
  311. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  312.     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
  313. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  314.     /* nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
  315. OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
  316.     /* dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
  317. OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
  318.     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
  319. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  320.     /* 0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
  321. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  322.     /* @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
  323. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  324.     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [      ]   ^   _    */
  325. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  326.     /* `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
  327. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  328.     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
  329. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  330. };
  331. /* token type table for MIME parsing */
  332. u_char MimeTokenTab[256] =
  333. {
  334.     /* nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
  335. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
  336.     /* dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
  337. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  338.     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
  339. SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
  340.     /* 0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
  341. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
  342.     /* @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
  343. OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  344.     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [      ]   ^   _    */
  345. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
  346.     /* `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
  347. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  348.     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
  349. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  350.     /* nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
  351. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  352.     /* dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
  353. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  354.     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
  355. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  356.     /* 0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
  357. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  358.     /* @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
  359. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  360.     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [      ]   ^   _    */
  361. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  362.     /* `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
  363. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  364.     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
  365. ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
  366. };
  367. /* token type table: don't strip comments */
  368. u_char TokTypeNoC[256] =
  369. {
  370.     /* nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
  371. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
  372.     /* dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
  373. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  374.     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
  375. SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM,
  376.     /* 0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
  377. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  378.     /* @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
  379. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  380.     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [      ]   ^   _    */
  381. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  382.     /* `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
  383. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  384.     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
  385. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  386.     /* nul soh stx etx eot enq ack bel  bs  ht  nl  vt  np  cr  so  si   */
  387. OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
  388.     /* dle dc1 dc2 dc3 dc4 nak syn etb  can em  sub esc fs  gs  rs  us   */
  389. OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
  390.     /*  sp  !   "   #   $   %   &   '    (   )   *   +   ,   -   .   /    */
  391. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  392.     /* 0   1   2   3   4   5   6   7    8   9   :   ;   <   =   >   ?    */
  393. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  394.     /* @   A   B   C   D   E   F   G    H   I   J   K   L   M   N   O    */
  395. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  396.     /*  P   Q   R   S   T   U   V   W    X   Y   Z   [      ]   ^   _    */
  397. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  398.     /* `   a   b   c   d   e   f   g    h   i   j   k   l   m   n   o    */
  399. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  400.     /*  p   q   r   s   t   u   v   w    x   y   z   {   |   }   ~   del  */
  401. ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
  402. };
  403. #define NOCHAR -1 /* signal nothing in lookahead token */
  404. char **
  405. prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
  406. char *addr;
  407. int delim;
  408. char pvpbuf[];
  409. int pvpbsize;
  410. char **delimptr;
  411. u_char *toktab;
  412. {
  413. register char *p;
  414. register char *q;
  415. register int c;
  416. char **avp;
  417. bool bslashmode;
  418. bool route_syntax;
  419. int cmntcnt;
  420. int anglecnt;
  421. char *tok;
  422. int state;
  423. int newstate;
  424. char *saveto = CurEnv->e_to;
  425. static char *av[MAXATOM + 1];
  426. static char firsttime = TRUE;
  427. extern int errno;
  428. if (firsttime)
  429. {
  430. /* initialize the token type table */
  431. char obuf[50];
  432. firsttime = FALSE;
  433. if (OperatorChars == NULL)
  434. {
  435. if (ConfigLevel < 7)
  436. OperatorChars = macvalue('o', CurEnv);
  437. if (OperatorChars == NULL)
  438. OperatorChars = ".:@[]";
  439. }
  440. expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS,
  441.        CurEnv);
  442. (void) strlcat(obuf, DELIMCHARS, sizeof obuf);
  443. for (p = obuf; *p != ''; p++)
  444. {
  445. if (TokTypeTab[*p & 0xff] == ATM)
  446. TokTypeTab[*p & 0xff] = OPR;
  447. if (TokTypeNoC[*p & 0xff] == ATM)
  448. TokTypeNoC[*p & 0xff] = OPR;
  449. }
  450. }
  451. if (toktab == NULL)
  452. toktab = TokTypeTab;
  453. /* make sure error messages don't have garbage on them */
  454. errno = 0;
  455. q = pvpbuf;
  456. bslashmode = FALSE;
  457. route_syntax = FALSE;
  458. cmntcnt = 0;
  459. anglecnt = 0;
  460. avp = av;
  461. state = ATM;
  462. c = NOCHAR;
  463. p = addr;
  464. CurEnv->e_to = p;
  465. if (tTd(22, 11))
  466. {
  467. dprintf("prescan: ");
  468. xputs(p);
  469. dprintf("n");
  470. }
  471. do
  472. {
  473. /* read a token */
  474. tok = q;
  475. for (;;)
  476. {
  477. /* store away any old lookahead character */
  478. if (c != NOCHAR && !bslashmode)
  479. {
  480. /* see if there is room */
  481. if (q >= &pvpbuf[pvpbsize - 5])
  482. {
  483. usrerr("553 5.1.1 Address too long");
  484. if (strlen(addr) > (SIZE_T) MAXNAME)
  485. addr[MAXNAME] = '';
  486. returnnull:
  487. if (delimptr != NULL)
  488. *delimptr = p;
  489. CurEnv->e_to = saveto;
  490. return NULL;
  491. }
  492. /* squirrel it away */
  493. *q++ = c;
  494. }
  495. /* read a new input character */
  496. c = *p++;
  497. if (c == '')
  498. {
  499. /* diagnose and patch up bad syntax */
  500. if (state == QST)
  501. {
  502. usrerr("653 Unbalanced '"'");
  503. c = '"';
  504. }
  505. else if (cmntcnt > 0)
  506. {
  507. usrerr("653 Unbalanced '('");
  508. c = ')';
  509. }
  510. else if (anglecnt > 0)
  511. {
  512. c = '>';
  513. usrerr("653 Unbalanced '<'");
  514. }
  515. else
  516. break;
  517. p--;
  518. }
  519. else if (c == delim && cmntcnt <= 0 && state != QST)
  520. {
  521. if (anglecnt <= 0)
  522. break;
  523. /* special case for better error management */
  524. if (delim == ',' && !route_syntax)
  525. {
  526. usrerr("653 Unbalanced '<'");
  527. c = '>';
  528. p--;
  529. }
  530. }
  531. if (tTd(22, 101))
  532. dprintf("c=%c, s=%d; ", c, state);
  533. /* chew up special characters */
  534. *q = '';
  535. if (bslashmode)
  536. {
  537. bslashmode = FALSE;
  538. /* kludge ! for naive users */
  539. if (cmntcnt > 0)
  540. {
  541. c = NOCHAR;
  542. continue;
  543. }
  544. else if (c != '!' || state == QST)
  545. {
  546. *q++ = '\';
  547. continue;
  548. }
  549. }
  550. if (c == '\')
  551. {
  552. bslashmode = TRUE;
  553. }
  554. else if (state == QST)
  555. {
  556. /* EMPTY */
  557. /* do nothing, just avoid next clauses */
  558. }
  559. else if (c == '(' && toktab['('] == SPC)
  560. {
  561. cmntcnt++;
  562. c = NOCHAR;
  563. }
  564. else if (c == ')' && toktab['('] == SPC)
  565. {
  566. if (cmntcnt <= 0)
  567. {
  568. usrerr("653 Unbalanced ')'");
  569. c = NOCHAR;
  570. }
  571. else
  572. cmntcnt--;
  573. }
  574. else if (cmntcnt > 0)
  575. {
  576. c = NOCHAR;
  577. }
  578. else if (c == '<')
  579. {
  580. char *ptr = p;
  581. anglecnt++;
  582. while (isascii(*ptr) && isspace(*ptr))
  583. ptr++;
  584. if (*ptr == '@')
  585. route_syntax = TRUE;
  586. }
  587. else if (c == '>')
  588. {
  589. if (anglecnt <= 0)
  590. {
  591. usrerr("653 Unbalanced '>'");
  592. c = NOCHAR;
  593. }
  594. else
  595. anglecnt--;
  596. route_syntax = FALSE;
  597. }
  598. else if (delim == ' ' && isascii(c) && isspace(c))
  599. c = ' ';
  600. if (c == NOCHAR)
  601. continue;
  602. /* see if this is end of input */
  603. if (c == delim && anglecnt <= 0 && state != QST)
  604. break;
  605. newstate = StateTab[state][toktab[c & 0xff]];
  606. if (tTd(22, 101))
  607. dprintf("ns=%02on", newstate);
  608. state = newstate & TYPE;
  609. if (state == ILL)
  610. {
  611. if (isascii(c) && isprint(c))
  612. usrerr("653 Illegal character %c", c);
  613. else
  614. usrerr("653 Illegal character 0x%02x", c);
  615. }
  616. if (bitset(M, newstate))
  617. c = NOCHAR;
  618. if (bitset(B, newstate))
  619. break;
  620. }
  621. /* new token */
  622. if (tok != q)
  623. {
  624. *q++ = '';
  625. if (tTd(22, 36))
  626. {
  627. dprintf("tok=");
  628. xputs(tok);
  629. dprintf("n");
  630. }
  631. if (avp >= &av[MAXATOM])
  632. {
  633. usrerr("553 5.1.0 prescan: too many tokens");
  634. goto returnnull;
  635. }
  636. if (q - tok > MAXNAME)
  637. {
  638. usrerr("553 5.1.0 prescan: token too long");
  639. goto returnnull;
  640. }
  641. *avp++ = tok;
  642. }
  643. } while (c != '' && (c != delim || anglecnt > 0));
  644. *avp = NULL;
  645. p--;
  646. if (delimptr != NULL)
  647. *delimptr = p;
  648. if (tTd(22, 12))
  649. {
  650. dprintf("prescan==>");
  651. printav(av);
  652. }
  653. CurEnv->e_to = saveto;
  654. if (av[0] == NULL)
  655. {
  656. if (tTd(22, 1))
  657. dprintf("prescan: null leading tokenn");
  658. return NULL;
  659. }
  660. return av;
  661. }
  662. /*
  663. **  REWRITE -- apply rewrite rules to token vector.
  664. **
  665. ** This routine is an ordered production system.  Each rewrite
  666. ** rule has a LHS (called the pattern) and a RHS (called the
  667. ** rewrite); 'rwr' points the the current rewrite rule.
  668. **
  669. ** For each rewrite rule, 'avp' points the address vector we
  670. ** are trying to match against, and 'pvp' points to the pattern.
  671. ** If pvp points to a special match value (MATCHZANY, MATCHANY,
  672. ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
  673. ** matched is saved away in the match vector (pointed to by 'mvp').
  674. **
  675. ** When a match between avp & pvp does not match, we try to
  676. ** back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
  677. ** we must also back out the match in mvp.  If we reach a
  678. ** MATCHANY or MATCHZANY we just extend the match and start
  679. ** over again.
  680. **
  681. ** When we finally match, we rewrite the address vector
  682. ** and try over again.
  683. **
  684. ** Parameters:
  685. ** pvp -- pointer to token vector.
  686. ** ruleset -- the ruleset to use for rewriting.
  687. ** reclevel -- recursion level (to catch loops).
  688. ** e -- the current envelope.
  689. **
  690. ** Returns:
  691. ** A status code.  If EX_TEMPFAIL, higher level code should
  692. ** attempt recovery.
  693. **
  694. ** Side Effects:
  695. ** pvp is modified.
  696. */
  697. struct match
  698. {
  699. char **match_first; /* first token matched */
  700. char **match_last; /* last token matched */
  701. char **match_pattern; /* pointer to pattern */
  702. };
  703. #define MAXMATCH 9 /* max params per rewrite */
  704. int
  705. rewrite(pvp, ruleset, reclevel, e)
  706. char **pvp;
  707. int ruleset;
  708. int reclevel;
  709. register ENVELOPE *e;
  710. {
  711. register char *ap; /* address pointer */
  712. register char *rp; /* rewrite pointer */
  713. register char *rulename; /* ruleset name */
  714. register char *prefix;
  715. register char **avp; /* address vector pointer */
  716. register char **rvp; /* rewrite vector pointer */
  717. register struct match *mlp; /* cur ptr into mlist */
  718. register struct rewrite *rwr; /* pointer to current rewrite rule */
  719. int ruleno; /* current rule number */
  720. int rstat = EX_OK; /* return status */
  721. int loopcount;
  722. struct match mlist[MAXMATCH]; /* stores match on LHS */
  723. char *npvp[MAXATOM + 1]; /* temporary space for rebuild */
  724. char buf[MAXLINE];
  725. char name[6];
  726. if (ruleset < 0 || ruleset >= MAXRWSETS)
  727. {
  728. syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset);
  729. return EX_CONFIG;
  730. }
  731. rulename = RuleSetNames[ruleset];
  732. if (rulename == NULL)
  733. {
  734. snprintf(name, sizeof name, "%d", ruleset);
  735. rulename = name;
  736. }
  737. if (OpMode == MD_TEST)
  738. prefix = "";
  739. else
  740. prefix = "rewrite: ruleset ";
  741. if (OpMode == MD_TEST)
  742. {
  743. printf("%s%-16.16s   input:", prefix, rulename);
  744. printav(pvp);
  745. }
  746. else if (tTd(21, 1))
  747. {
  748. dprintf("%s%-16.16s   input:", prefix, rulename);
  749. printav(pvp);
  750. }
  751. if (reclevel++ > MaxRuleRecursion)
  752. {
  753. syserr("rewrite: excessive recursion (max %d), ruleset %s",
  754. MaxRuleRecursion, rulename);
  755. return EX_CONFIG;
  756. }
  757. if (pvp == NULL)
  758. return EX_USAGE;
  759. /*
  760. **  Run through the list of rewrite rules, applying
  761. ** any that match.
  762. */
  763. ruleno = 1;
  764. loopcount = 0;
  765. for (rwr = RewriteRules[ruleset]; rwr != NULL; )
  766. {
  767. int status;
  768. /* if already canonical, quit now */
  769. if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET)
  770. break;
  771. if (tTd(21, 12))
  772. {
  773. if (tTd(21, 15))
  774. dprintf("-----trying rule (line %d):",
  775.        rwr->r_line);
  776. else
  777. dprintf("-----trying rule:");
  778. printav(rwr->r_lhs);
  779. }
  780. /* try to match on this rule */
  781. mlp = mlist;
  782. rvp = rwr->r_lhs;
  783. avp = pvp;
  784. if (++loopcount > 100)
  785. {
  786. syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
  787. rulename, ruleno);
  788. if (tTd(21, 1))
  789. {
  790. dprintf("workspace: ");
  791. printav(pvp);
  792. }
  793. break;
  794. }
  795. while ((ap = *avp) != NULL || *rvp != NULL)
  796. {
  797. rp = *rvp;
  798. if (tTd(21, 35))
  799. {
  800. dprintf("ADVANCE rp=");
  801. xputs(rp);
  802. dprintf(", ap=");
  803. xputs(ap);
  804. dprintf("n");
  805. }
  806. if (rp == NULL)
  807. {
  808. /* end-of-pattern before end-of-address */
  809. goto backup;
  810. }
  811. if (ap == NULL && (*rp & 0377) != MATCHZANY &&
  812.     (*rp & 0377) != MATCHZERO)
  813. {
  814. /* end-of-input with patterns left */
  815. goto backup;
  816. }
  817. switch (*rp & 0377)
  818. {
  819.   case MATCHCLASS:
  820. /* match any phrase in a class */
  821. mlp->match_pattern = rvp;
  822. mlp->match_first = avp;
  823. extendclass:
  824. ap = *avp;
  825. if (ap == NULL)
  826. goto backup;
  827. mlp->match_last = avp++;
  828. cataddr(mlp->match_first, mlp->match_last,
  829. buf, sizeof buf, '');
  830. if (!wordinclass(buf, rp[1]))
  831. {
  832. if (tTd(21, 36))
  833. {
  834. dprintf("EXTEND  rp=");
  835. xputs(rp);
  836. dprintf(", ap=");
  837. xputs(ap);
  838. dprintf("n");
  839. }
  840. goto extendclass;
  841. }
  842. if (tTd(21, 36))
  843. dprintf("CLMATCHn");
  844. mlp++;
  845. break;
  846.   case MATCHNCLASS:
  847. /* match any token not in a class */
  848. if (wordinclass(ap, rp[1]))
  849. goto backup;
  850. /* FALLTHROUGH */
  851.   case MATCHONE:
  852.   case MATCHANY:
  853. /* match exactly one token */
  854. mlp->match_pattern = rvp;
  855. mlp->match_first = avp;
  856. mlp->match_last = avp++;
  857. mlp++;
  858. break;
  859.   case MATCHZANY:
  860. /* match zero or more tokens */
  861. mlp->match_pattern = rvp;
  862. mlp->match_first = avp;
  863. mlp->match_last = avp - 1;
  864. mlp++;
  865. break;
  866.   case MATCHZERO:
  867. /* match zero tokens */
  868. break;
  869.   case MACRODEXPAND:
  870. /*
  871. **  Match against run-time macro.
  872. **  This algorithm is broken for the
  873. **  general case (no recursive macros,
  874. **  improper tokenization) but should
  875. **  work for the usual cases.
  876. */
  877. ap = macvalue(rp[1], e);
  878. mlp->match_first = avp;
  879. if (tTd(21, 2))
  880. dprintf("rewrite: LHS $&%s => "%s"n",
  881. macname(rp[1]),
  882. ap == NULL ? "(NULL)" : ap);
  883. if (ap == NULL)
  884. break;
  885. while (*ap != '')
  886. {
  887. if (*avp == NULL ||
  888.     strncasecmp(ap, *avp, strlen(*avp)) != 0)
  889. {
  890. /* no match */
  891. avp = mlp->match_first;
  892. goto backup;
  893. }
  894. ap += strlen(*avp++);
  895. }
  896. /* match */
  897. break;
  898.   default:
  899. /* must have exact match */
  900. if (sm_strcasecmp(rp, ap))
  901. goto backup;
  902. avp++;
  903. break;
  904. }
  905. /* successful match on this token */
  906. rvp++;
  907. continue;
  908.   backup:
  909. /* match failed -- back up */
  910. while (--mlp >= mlist)
  911. {
  912. rvp = mlp->match_pattern;
  913. rp = *rvp;
  914. avp = mlp->match_last + 1;
  915. ap = *avp;
  916. if (tTd(21, 36))
  917. {
  918. dprintf("BACKUP  rp=");
  919. xputs(rp);
  920. dprintf(", ap=");
  921. xputs(ap);
  922. dprintf("n");
  923. }
  924. if (ap == NULL)
  925. {
  926. /* run off the end -- back up again */
  927. continue;
  928. }
  929. if ((*rp & 0377) == MATCHANY ||
  930.     (*rp & 0377) == MATCHZANY)
  931. {
  932. /* extend binding and continue */
  933. mlp->match_last = avp++;
  934. rvp++;
  935. mlp++;
  936. break;
  937. }
  938. if ((*rp & 0377) == MATCHCLASS)
  939. {
  940. /* extend binding and try again */
  941. mlp->match_last = avp;
  942. goto extendclass;
  943. }
  944. }
  945. if (mlp < mlist)
  946. {
  947. /* total failure to match */
  948. break;
  949. }
  950. }
  951. /*
  952. **  See if we successfully matched
  953. */
  954. if (mlp < mlist || *rvp != NULL)
  955. {
  956. if (tTd(21, 10))
  957. dprintf("----- rule failsn");
  958. rwr = rwr->r_next;
  959. ruleno++;
  960. loopcount = 0;
  961. continue;
  962. }
  963. rvp = rwr->r_rhs;
  964. if (tTd(21, 12))
  965. {
  966. dprintf("-----rule matches:");
  967. printav(rvp);
  968. }
  969. rp = *rvp;
  970. if ((*rp & 0377) == CANONUSER)
  971. {
  972. rvp++;
  973. rwr = rwr->r_next;
  974. ruleno++;
  975. loopcount = 0;
  976. }
  977. else if ((*rp & 0377) == CANONHOST)
  978. {
  979. rvp++;
  980. rwr = NULL;
  981. }
  982. /* substitute */
  983. for (avp = npvp; *rvp != NULL; rvp++)
  984. {
  985. register struct match *m;
  986. register char **pp;
  987. rp = *rvp;
  988. if ((*rp & 0377) == MATCHREPL)
  989. {
  990. /* substitute from LHS */
  991. m = &mlist[rp[1] - '1'];
  992. if (m < mlist || m >= mlp)
  993. {
  994. syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
  995. rulename, rp[1]);
  996. return EX_CONFIG;
  997. }
  998. if (tTd(21, 15))
  999. {
  1000. dprintf("$%c:", rp[1]);
  1001. pp = m->match_first;
  1002. while (pp <= m->match_last)
  1003. {
  1004. dprintf(" %lx="",
  1005. (u_long) *pp);
  1006. (void) dflush();
  1007. dprintf("%s"", *pp++);
  1008. }
  1009. dprintf("n");
  1010. }
  1011. pp = m->match_first;
  1012. while (pp <= m->match_last)
  1013. {
  1014. if (avp >= &npvp[MAXATOM])
  1015. {
  1016. syserr("554 5.3.0 rewrite: expansion too long");
  1017. return EX_DATAERR;
  1018. }
  1019. *avp++ = *pp++;
  1020. }
  1021. }
  1022. else
  1023. {
  1024. /* some sort of replacement */
  1025. if (avp >= &npvp[MAXATOM])
  1026. {
  1027. toolong:
  1028. syserr("554 5.3.0 rewrite: expansion too long");
  1029. return EX_DATAERR;
  1030. }
  1031. if ((*rp & 0377) != MACRODEXPAND)
  1032. {
  1033. /* vanilla replacement */
  1034. *avp++ = rp;
  1035. }
  1036. else
  1037. {
  1038. /* $&x replacement */
  1039. char *mval = macvalue(rp[1], e);
  1040. char **xpvp;
  1041. int trsize = 0;
  1042. static size_t pvpb1_size = 0;
  1043. static char **pvpb1 = NULL;
  1044. char pvpbuf[PSBUFSIZE];
  1045. if (tTd(21, 2))
  1046. dprintf("rewrite: RHS $&%s => "%s"n",
  1047. macname(rp[1]),
  1048. mval == NULL ? "(NULL)" : mval);
  1049. if (mval == NULL || *mval == '')
  1050. continue;
  1051. /* save the remainder of the input */
  1052. for (xpvp = pvp; *xpvp != NULL; xpvp++)
  1053. trsize += sizeof *xpvp;
  1054. if (trsize > pvpb1_size)
  1055. {
  1056. if (pvpb1 != NULL)
  1057. free(pvpb1);
  1058. pvpb1 = (char **)xalloc(trsize);
  1059. pvpb1_size = trsize;
  1060. }
  1061. memmove((char *) pvpb1,
  1062. (char *) pvp,
  1063. trsize);
  1064. /* scan the new replacement */
  1065. xpvp = prescan(mval, '', pvpbuf,
  1066.        sizeof pvpbuf, NULL,
  1067.        NULL);
  1068. if (xpvp == NULL)
  1069. {
  1070. /* prescan pre-printed error */
  1071. return EX_DATAERR;
  1072. }
  1073. /* insert it into the output stream */
  1074. while (*xpvp != NULL)
  1075. {
  1076. if (tTd(21, 19))
  1077. dprintf(" ... %sn",
  1078. *xpvp);
  1079. *avp++ = newstr(*xpvp);
  1080. if (avp >= &npvp[MAXATOM])
  1081. goto toolong;
  1082. xpvp++;
  1083. }
  1084. if (tTd(21, 19))
  1085. dprintf(" ... DONEn");
  1086. /* restore the old trailing input */
  1087. memmove((char *) pvp,
  1088. (char *) pvpb1,
  1089. trsize);
  1090. }
  1091. }
  1092. }
  1093. *avp++ = NULL;
  1094. /*
  1095. **  Check for any hostname/keyword lookups.
  1096. */
  1097. for (rvp = npvp; *rvp != NULL; rvp++)
  1098. {
  1099. char **hbrvp;
  1100. char **xpvp;
  1101. int trsize;
  1102. char *replac;
  1103. int endtoken;
  1104. STAB *map;
  1105. char *mapname;
  1106. char **key_rvp;
  1107. char **arg_rvp;
  1108. char **default_rvp;
  1109. char cbuf[MAXNAME + 1];
  1110. char *pvpb1[MAXATOM + 1];
  1111. char *argvect[10];
  1112. char pvpbuf[PSBUFSIZE];
  1113. char *nullpvp[1];
  1114. if ((**rvp & 0377) != HOSTBEGIN &&
  1115.     (**rvp & 0377) != LOOKUPBEGIN)
  1116. continue;
  1117. /*
  1118. **  Got a hostname/keyword lookup.
  1119. **
  1120. ** This could be optimized fairly easily.
  1121. */
  1122. hbrvp = rvp;
  1123. if ((**rvp & 0377) == HOSTBEGIN)
  1124. {
  1125. endtoken = HOSTEND;
  1126. mapname = "host";
  1127. }
  1128. else
  1129. {
  1130. endtoken = LOOKUPEND;
  1131. mapname = *++rvp;
  1132. }
  1133. map = stab(mapname, ST_MAP, ST_FIND);
  1134. if (map == NULL)
  1135. syserr("554 5.3.0 rewrite: map %s not found", mapname);
  1136. /* extract the match part */
  1137. key_rvp = ++rvp;
  1138. default_rvp = NULL;
  1139. arg_rvp = argvect;
  1140. xpvp = NULL;
  1141. replac = pvpbuf;
  1142. while (*rvp != NULL && (**rvp & 0377) != endtoken)
  1143. {
  1144. int nodetype = **rvp & 0377;
  1145. if (nodetype != CANONHOST && nodetype != CANONUSER)
  1146. {
  1147. rvp++;
  1148. continue;
  1149. }
  1150. *rvp++ = NULL;
  1151. if (xpvp != NULL)
  1152. {
  1153. cataddr(xpvp, NULL, replac,
  1154. &pvpbuf[sizeof pvpbuf] - replac,
  1155. '');
  1156. *++arg_rvp = replac;
  1157. replac += strlen(replac) + 1;
  1158. xpvp = NULL;
  1159. }
  1160. switch (nodetype)
  1161. {
  1162.   case CANONHOST:
  1163. xpvp = rvp;
  1164. break;
  1165.   case CANONUSER:
  1166. default_rvp = rvp;
  1167. break;
  1168. }
  1169. }
  1170. if (*rvp != NULL)
  1171. *rvp++ = NULL;
  1172. if (xpvp != NULL)
  1173. {
  1174. cataddr(xpvp, NULL, replac,
  1175. &pvpbuf[sizeof pvpbuf] - replac,
  1176. '');
  1177. *++arg_rvp = replac;
  1178. }
  1179. *++arg_rvp = NULL;
  1180. /* save the remainder of the input string */
  1181. trsize = (int) (avp - rvp + 1) * sizeof *rvp;
  1182. memmove((char *) pvpb1, (char *) rvp, trsize);
  1183. /* look it up */
  1184. cataddr(key_rvp, NULL, cbuf, sizeof cbuf,
  1185. map == NULL ? '' : map->s_map.map_spacesub);
  1186. argvect[0] = cbuf;
  1187. replac = map_lookup(map, cbuf, argvect, &rstat, e);
  1188. /* if no replacement, use default */
  1189. if (replac == NULL && default_rvp != NULL)
  1190. {
  1191. /* create the default */
  1192. cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '');
  1193. replac = cbuf;
  1194. }
  1195. if (replac == NULL)
  1196. {
  1197. xpvp = key_rvp;
  1198. }
  1199. else if (*replac == '')
  1200. {
  1201. /* null replacement */
  1202. nullpvp[0] = NULL;
  1203. xpvp = nullpvp;
  1204. }
  1205. else
  1206. {
  1207. /* scan the new replacement */
  1208. xpvp = prescan(replac, '', pvpbuf,
  1209.        sizeof pvpbuf, NULL, NULL);
  1210. if (xpvp == NULL)
  1211. {
  1212. /* prescan already printed error */
  1213. return EX_DATAERR;
  1214. }
  1215. }
  1216. /* append it to the token list */
  1217. for (avp = hbrvp; *xpvp != NULL; xpvp++)
  1218. {
  1219. *avp++ = newstr(*xpvp);
  1220. if (avp >= &npvp[MAXATOM])
  1221. goto toolong;
  1222. }
  1223. /* restore the old trailing information */
  1224. rvp = avp - 1;
  1225. for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
  1226. if (avp >= &npvp[MAXATOM])
  1227. goto toolong;
  1228. }
  1229. /*
  1230. **  Check for subroutine calls.
  1231. */
  1232. status = callsubr(npvp, reclevel, e);
  1233. if (rstat == EX_OK || status == EX_TEMPFAIL)
  1234. rstat = status;
  1235. /* copy vector back into original space. */
  1236. for (avp = npvp; *avp++ != NULL;)
  1237. continue;
  1238. memmove((char *) pvp, (char *) npvp,
  1239.       (int) (avp - npvp) * sizeof *avp);
  1240. if (tTd(21, 4))
  1241. {
  1242. dprintf("rewritten as:");
  1243. printav(pvp);
  1244. }
  1245. }
  1246. if (OpMode == MD_TEST)
  1247. {
  1248. printf("%s%-16.16s returns:", prefix, rulename);
  1249. printav(pvp);
  1250. }
  1251. else if (tTd(21, 1))
  1252. {
  1253. dprintf("%s%-16.16s returns:", prefix, rulename);
  1254. printav(pvp);
  1255. }
  1256. return rstat;
  1257. }
  1258. /*
  1259. **  CALLSUBR -- call subroutines in rewrite vector
  1260. **
  1261. ** Parameters:
  1262. ** pvp -- pointer to token vector.
  1263. ** reclevel -- the current recursion level.
  1264. ** e -- the current envelope.
  1265. **
  1266. ** Returns:
  1267. ** The status from the subroutine call.
  1268. **
  1269. ** Side Effects:
  1270. ** pvp is modified.
  1271. */
  1272. static int
  1273. callsubr(pvp, reclevel, e)
  1274. char **pvp;
  1275. int reclevel;
  1276. ENVELOPE *e;
  1277. {
  1278. char **avp;
  1279. char **rvp;
  1280. register int i;
  1281. int subr;
  1282. int status;
  1283. int rstat = EX_OK;
  1284. char *tpvp[MAXATOM + 1];
  1285. for (avp = pvp; *avp != NULL; avp++)
  1286. {
  1287. if ((**avp & 0377) == CALLSUBR && avp[1] != NULL)
  1288. {
  1289. stripquotes(avp[1]);
  1290. subr = strtorwset(avp[1], NULL, ST_FIND);
  1291. if (subr < 0)
  1292. {
  1293. syserr("Unknown ruleset %s", avp[1]);
  1294. return EX_CONFIG;
  1295. }
  1296. if (tTd(21, 3))
  1297. dprintf("-----callsubr %s (%d)n",
  1298. avp[1], subr);
  1299. /*
  1300. **  Take care of possible inner calls first.
  1301. **  use a full size temporary buffer to avoid
  1302. **  overflows in rewrite, but strip off the
  1303. **  subroutine call.
  1304. */
  1305. for (i = 2; avp[i] != NULL; i++)
  1306. tpvp[i - 2] = avp[i];
  1307. tpvp[i - 2] = NULL;
  1308. status = callsubr(tpvp, reclevel, e);
  1309. if (rstat == EX_OK || status == EX_TEMPFAIL)
  1310. rstat = status;
  1311. /*
  1312. **  Now we need to call the ruleset specified for
  1313. **  the subroutine. we can do this with the
  1314. **  temporary buffer that we set up earlier,
  1315. **  since it has all the data we want to rewrite.
  1316. */
  1317. status = rewrite(tpvp, subr, reclevel, e);
  1318. if (rstat == EX_OK || status == EX_TEMPFAIL)
  1319. rstat = status;
  1320. /*
  1321. **  Find length of tpvp and current offset into
  1322. **  pvp, if the total is greater than MAXATOM,
  1323. **  then it would overflow the buffer if we copied
  1324. **  it back in to pvp, in which case we throw a
  1325. **  fit.
  1326. */
  1327. for (rvp = tpvp; *rvp != NULL; rvp++)
  1328. continue;
  1329. if (((rvp - tpvp) + (avp - pvp)) > MAXATOM)
  1330. {
  1331. syserr("554 5.3.0 callsubr: expansion too long");
  1332. return EX_DATAERR;
  1333. }
  1334. /*
  1335. **  Now we can copy the rewritten code over
  1336. **  the initial subroutine call in the buffer.
  1337. */
  1338. for (i = 0; tpvp[i] != NULL; i++)
  1339. avp[i] = tpvp[i];
  1340. avp[i] = NULL;
  1341. /*
  1342. **  If we got this far, we've processed the left
  1343. **  most subroutine, and recursively called ourselves
  1344. **  to handle any other subroutines.  We're done.
  1345. */
  1346. break;
  1347. }
  1348. }
  1349. return rstat;
  1350. }
  1351. /*
  1352. **  MAP_LOOKUP -- do lookup in map
  1353. **
  1354. ** Parameters:
  1355. ** map -- the map to use for the lookup.
  1356. ** key -- the key to look up.
  1357. ** argvect -- arguments to pass to the map lookup.
  1358. ** pstat -- a pointer to an integer in which to store the
  1359. ** status from the lookup.
  1360. ** e -- the current envelope.
  1361. **
  1362. ** Returns:
  1363. ** The result of the lookup.
  1364. ** NULL -- if there was no data for the given key.
  1365. */
  1366. static char *
  1367. map_lookup(smap, key, argvect, pstat, e)
  1368. STAB *smap;
  1369. char key[];
  1370. char **argvect;
  1371. int *pstat;
  1372. ENVELOPE *e;
  1373. {
  1374. auto int status = EX_OK;
  1375. MAP *map;
  1376. char *replac;
  1377. if (smap == NULL)
  1378. return NULL;
  1379. map = &smap->s_map;
  1380. DYNOPENMAP(map);
  1381. if (e->e_sendmode == SM_DEFER &&
  1382.     bitset(MF_DEFER, map->map_mflags))
  1383. {
  1384. /* don't do any map lookups */
  1385. if (tTd(60, 1))
  1386. dprintf("map_lookup(%s, %s) => DEFERREDn",
  1387. smap->s_name, key);
  1388. *pstat = EX_TEMPFAIL;
  1389. return NULL;
  1390. }
  1391. if (!bitset(MF_KEEPQUOTES, map->map_mflags))
  1392. stripquotes(key);
  1393. if (tTd(60, 1))
  1394. {
  1395. dprintf("map_lookup(%s, %s", smap->s_name, key);
  1396. if (tTd(60, 5))
  1397. {
  1398. int i;
  1399. for (i = 0; argvect[i] != NULL; i++)
  1400. dprintf(", %%%d=%s", i, argvect[i]);
  1401. }
  1402. dprintf(") => ");
  1403. }
  1404. replac = (*map->map_class->map_lookup)(map, key, argvect, &status);
  1405. if (tTd(60, 1))
  1406. dprintf("%s (%d)n",
  1407. replac != NULL ? replac : "NOT FOUND",
  1408. status);
  1409. /* should recover if status == EX_TEMPFAIL */
  1410. if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags))
  1411. {
  1412. *pstat = EX_TEMPFAIL;
  1413. if (tTd(60, 1))
  1414. dprintf("map_lookup(%s, %s) tempfail: errno=%dn",
  1415. smap->s_name, key, errno);
  1416. if (e->e_message == NULL)
  1417. {
  1418. char mbuf[320];
  1419. snprintf(mbuf, sizeof mbuf,
  1420. "%.80s map: lookup (%s): deferred",
  1421. smap->s_name,
  1422. shortenstring(key, MAXSHORTSTR));
  1423. e->e_message = newstr(mbuf);
  1424. }
  1425. }
  1426. if (status == EX_TEMPFAIL && map->map_tapp != NULL)
  1427. {
  1428. size_t i = strlen(key) + strlen(map->map_tapp) + 1;
  1429. static char *rwbuf = NULL;
  1430. static size_t rwbuflen = 0;
  1431. if (i > rwbuflen)
  1432. {
  1433. if (rwbuf != NULL)
  1434. free(rwbuf);
  1435. rwbuflen = i;
  1436. rwbuf = (char *) xalloc(rwbuflen);
  1437. }
  1438. snprintf(rwbuf, rwbuflen, "%s%s", key, map->map_tapp);
  1439. if (tTd(60, 4))
  1440. dprintf("map_lookup tempfail: returning "%s"n",
  1441. rwbuf);
  1442. return rwbuf;
  1443. }
  1444. return replac;
  1445. }
  1446. /*
  1447. **  INITERRMAILERS -- initialize error and discard mailers
  1448. **
  1449. ** Parameters:
  1450. ** none.
  1451. **
  1452. ** Returns:
  1453. ** none.
  1454. **
  1455. ** Side Effects:
  1456. ** initializes error and discard mailers.
  1457. */
  1458. static MAILER discardmailer;
  1459. static MAILER errormailer;
  1460. static char *discardargv[] = { "DISCARD", NULL };
  1461. static char *errorargv[] = { "ERROR", NULL };
  1462. void
  1463. initerrmailers()
  1464. {
  1465. if (discardmailer.m_name == NULL)
  1466. {
  1467. /* initialize the discard mailer */
  1468. discardmailer.m_name = "*discard*";
  1469. discardmailer.m_mailer = "DISCARD";
  1470. discardmailer.m_argv = discardargv;
  1471. }
  1472. if (errormailer.m_name == NULL)
  1473. {
  1474. /* initialize the bogus mailer */
  1475. errormailer.m_name = "*error*";
  1476. errormailer.m_mailer = "ERROR";
  1477. errormailer.m_argv = errorargv;
  1478. }
  1479. }
  1480. /*
  1481. **  BUILDADDR -- build address from token vector.
  1482. **
  1483. ** Parameters:
  1484. ** tv -- token vector.
  1485. ** a -- pointer to address descriptor to fill.
  1486. ** If NULL, one will be allocated.
  1487. ** flags -- info regarding whether this is a sender or
  1488. ** a recipient.
  1489. ** e -- the current envelope.
  1490. **
  1491. ** Returns:
  1492. ** NULL if there was an error.
  1493. ** 'a' otherwise.
  1494. **
  1495. ** Side Effects:
  1496. ** fills in 'a'
  1497. */
  1498. static struct errcodes
  1499. {
  1500. char *ec_name; /* name of error code */
  1501. int ec_code; /* numeric code */
  1502. } ErrorCodes[] =
  1503. {
  1504. { "usage", EX_USAGE },
  1505. { "nouser", EX_NOUSER },
  1506. { "nohost", EX_NOHOST },
  1507. { "unavailable", EX_UNAVAILABLE },
  1508. { "software", EX_SOFTWARE },
  1509. { "tempfail", EX_TEMPFAIL },
  1510. { "protocol", EX_PROTOCOL },
  1511. #ifdef EX_CONFIG
  1512. { "config", EX_CONFIG },
  1513. #endif /* EX_CONFIG */
  1514. { NULL, EX_UNAVAILABLE }
  1515. };
  1516. static ADDRESS *
  1517. buildaddr(tv, a, flags, e)
  1518. register char **tv;
  1519. register ADDRESS *a;
  1520. int flags;
  1521. register ENVELOPE *e;
  1522. {
  1523. struct mailer **mp;
  1524. register struct mailer *m;
  1525. register char *p;
  1526. char *mname;
  1527. char **hostp;
  1528. char hbuf[MAXNAME + 1];
  1529. static char ubuf[MAXNAME + 2];
  1530. if (tTd(24, 5))
  1531. {
  1532. dprintf("buildaddr, flags=%x, tv=", flags);
  1533. printav(tv);
  1534. }
  1535. if (a == NULL)
  1536. a = (ADDRESS *) xalloc(sizeof *a);
  1537. memset((char *) a, '', sizeof *a);
  1538. hbuf[0] = '';
  1539. /* set up default error return flags */
  1540. a->q_flags |= DefaultNotify;
  1541. /* figure out what net/mailer to use */
  1542. if (*tv == NULL || (**tv & 0377) != CANONNET)
  1543. {
  1544. syserr("554 5.3.5 buildaddr: no mailer in parsed address");
  1545. badaddr:
  1546. if (ExitStat == EX_TEMPFAIL)
  1547. a->q_state = QS_QUEUEUP;
  1548. else
  1549. {
  1550. a->q_state = QS_BADADDR;
  1551. a->q_mailer = &errormailer;
  1552. }
  1553. return a;
  1554. }
  1555. mname = *++tv;
  1556. /* extract host and user portions */
  1557. if (*++tv != NULL && (**tv & 0377) == CANONHOST)
  1558. hostp = ++tv;
  1559. else
  1560. hostp = NULL;
  1561. while (*tv != NULL && (**tv & 0377) != CANONUSER)
  1562. tv++;
  1563. if (*tv == NULL)
  1564. {
  1565. syserr("554 5.3.5 buildaddr: no user");
  1566. goto badaddr;
  1567. }
  1568. if (tv == hostp)
  1569. hostp = NULL;
  1570. else if (hostp != NULL)
  1571. cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '');
  1572. cataddr(++tv, NULL, ubuf, sizeof ubuf, ' ');
  1573. /* save away the host name */
  1574. if (strcasecmp(mname, "error") == 0)
  1575. {
  1576. /* Set up triplet for use by -bv */
  1577. a->q_mailer = &errormailer;
  1578. a->q_user = newstr(ubuf);
  1579. if (hostp != NULL)
  1580. {
  1581. register struct errcodes *ep;
  1582. a->q_host = newstr(hbuf);
  1583. if (strchr(hbuf, '.') != NULL)
  1584. {
  1585. a->q_status = newstr(hbuf);
  1586. setstat(dsntoexitstat(hbuf));
  1587. }
  1588. else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
  1589. {
  1590. setstat(atoi(hbuf));
  1591. }
  1592. else
  1593. {
  1594. for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
  1595. if (strcasecmp(ep->ec_name, hbuf) == 0)
  1596. break;
  1597. setstat(ep->ec_code);
  1598. }
  1599. }
  1600. else
  1601. {
  1602. a->q_host = NULL;
  1603. setstat(EX_UNAVAILABLE);
  1604. }
  1605. stripquotes(ubuf);
  1606. if (ISSMTPCODE(ubuf) && ubuf[3] == ' ')
  1607. {
  1608. char fmt[16];
  1609. int off;
  1610. if ((off = isenhsc(ubuf + 4, ' ')) > 0)
  1611. {
  1612. ubuf[off + 4] = '';
  1613. off += 5;
  1614. }
  1615. else
  1616. {
  1617. off = 4;
  1618. ubuf[3] = '';
  1619. }
  1620. (void) snprintf(fmt, sizeof fmt, "%s %%s", ubuf);
  1621. if (off > 4)
  1622. usrerr(fmt, ubuf + off);
  1623. else if (isenhsc(hbuf, '') > 0)
  1624. usrerrenh(hbuf, fmt, ubuf + off);
  1625. else
  1626. usrerr(fmt, ubuf + off);
  1627. /* XXX ubuf[off - 1] = ' '; */
  1628. }
  1629. else
  1630. {
  1631. usrerr("553 5.3.0 %s", ubuf);
  1632. }
  1633. goto badaddr;
  1634. }
  1635. for (mp = Mailer; (m = *mp++) != NULL; )
  1636. {
  1637. if (strcasecmp(m->m_name, mname) == 0)
  1638. break;
  1639. }
  1640. if (m == NULL)
  1641. {
  1642. syserr("554 5.3.5 buildaddr: unknown mailer %s", mname);
  1643. goto badaddr;
  1644. }
  1645. a->q_mailer = m;
  1646. /* figure out what host (if any) */
  1647. if (hostp == NULL)
  1648. {
  1649. if (!bitnset(M_LOCALMAILER, m->m_flags))
  1650. {
  1651. syserr("554 5.3.5 buildaddr: no host");
  1652. goto badaddr;
  1653. }
  1654. a->q_host = NULL;
  1655. }
  1656. else
  1657. a->q_host = newstr(hbuf);
  1658. /* figure out the user */
  1659. p = ubuf;
  1660. if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
  1661. {
  1662. p++;
  1663. tv++;
  1664. a->q_flags |= QNOTREMOTE;
  1665. }
  1666. /* do special mapping for local mailer */
  1667. if (*p == '"')
  1668. p++;
  1669. if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
  1670. a->q_mailer = m = ProgMailer;
  1671. else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
  1672. a->q_mailer = m = FileMailer;
  1673. else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
  1674. {
  1675. /* may be :include: */
  1676. stripquotes(ubuf);
  1677. if (strncasecmp(ubuf, ":include:", 9) == 0)
  1678. {
  1679. /* if :include:, don't need further rewriting */
  1680. a->q_mailer = m = InclMailer;
  1681. a->q_user = newstr(&ubuf[9]);
  1682. return a;
  1683. }
  1684. }
  1685. /* rewrite according recipient mailer rewriting rules */
  1686. define('h', a->q_host, e);
  1687. #if _FFR_ADDR_TYPE
  1688. /*
  1689. **  Note, change the 9 to a 10 before removing #if FFR check
  1690. **  in a future version.
  1691. */
  1692. if (ConfigLevel >= 9 ||
  1693.     !bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
  1694. #else /* _FFR_ADDR_TYPE */
  1695. if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
  1696. #endif /* _FFR_ADDR_TYPE */
  1697. {
  1698. /* sender addresses done later */
  1699. (void) rewrite(tv, 2, 0, e);
  1700. if (m->m_re_rwset > 0)
  1701.        (void) rewrite(tv, m->m_re_rwset, 0, e);
  1702. }
  1703. (void) rewrite(tv, 4, 0, e);
  1704. /* save the result for the command line/RCPT argument */
  1705. cataddr(tv, NULL, ubuf, sizeof ubuf, '');
  1706. a->q_user = newstr(ubuf);
  1707. /*
  1708. **  Do mapping to lower case as requested by mailer
  1709. */
  1710. if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
  1711. makelower(a->q_host);
  1712. if (!bitnset(M_USR_UPPER, m->m_flags))
  1713. makelower(a->q_user);
  1714. if (tTd(24, 6))
  1715. {
  1716. dprintf("buildaddr => ");
  1717. printaddr(a, FALSE);
  1718. }
  1719. return a;
  1720. }
  1721. /*
  1722. **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
  1723. **
  1724. ** Parameters:
  1725. ** pvp -- parameter vector to rebuild.
  1726. ** evp -- last parameter to include.  Can be NULL to
  1727. ** use entire pvp.
  1728. ** buf -- buffer to build the string into.
  1729. ** sz -- size of buf.
  1730. ** spacesub -- the space separator character; if null,
  1731. ** use SpaceSub.
  1732. **
  1733. ** Returns:
  1734. ** none.
  1735. **
  1736. ** Side Effects:
  1737. ** Destroys buf.
  1738. */
  1739. void
  1740. cataddr(pvp, evp, buf, sz, spacesub)
  1741. char **pvp;
  1742. char **evp;
  1743. char *buf;
  1744. register int sz;
  1745. int spacesub;
  1746. {
  1747. bool oatomtok = FALSE;
  1748. bool natomtok = FALSE;
  1749. register int i;
  1750. register char *p;
  1751. if (sz <= 0)
  1752. return;
  1753. if (spacesub == '')
  1754. spacesub = SpaceSub;
  1755. if (pvp == NULL)
  1756. {
  1757. *buf = '';
  1758. return;
  1759. }
  1760. p = buf;
  1761. sz -= 2;
  1762. while (*pvp != NULL && (i = strlen(*pvp)) < sz - 1)
  1763. {
  1764. natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
  1765. if (oatomtok && natomtok)
  1766. {
  1767. *p++ = spacesub;
  1768. --sz;
  1769. }
  1770. (void) strlcpy(p, *pvp, sz);
  1771. oatomtok = natomtok;
  1772. p += i;
  1773. sz -= i;
  1774. if (pvp++ == evp)
  1775. break;
  1776. }
  1777. *p = '';
  1778. }
  1779. /*
  1780. **  SAMEADDR -- Determine if two addresses are the same
  1781. **
  1782. ** This is not just a straight comparison -- if the mailer doesn't
  1783. ** care about the host we just ignore it, etc.
  1784. **
  1785. ** Parameters:
  1786. ** a, b -- pointers to the internal forms to compare.
  1787. **
  1788. ** Returns:
  1789. ** TRUE -- they represent the same mailbox.
  1790. ** FALSE -- they don't.
  1791. **
  1792. ** Side Effects:
  1793. ** none.
  1794. */
  1795. bool
  1796. sameaddr(a, b)
  1797. register ADDRESS *a;
  1798. register ADDRESS *b;
  1799. {
  1800. register ADDRESS *ca, *cb;
  1801. /* if they don't have the same mailer, forget it */
  1802. if (a->q_mailer != b->q_mailer)
  1803. return FALSE;
  1804. /* if the user isn't the same, we can drop out */
  1805. if (strcmp(a->q_user, b->q_user) != 0)
  1806. return FALSE;
  1807. /* if we have good uids for both but they differ, these are different */
  1808. if (a->q_mailer == ProgMailer)
  1809. {
  1810. ca = getctladdr(a);
  1811. cb = getctladdr(b);
  1812. if (ca != NULL && cb != NULL &&
  1813.     bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
  1814.     ca->q_uid != cb->q_uid)
  1815. return FALSE;
  1816. }
  1817. /* otherwise compare hosts (but be careful for NULL ptrs) */
  1818. if (a->q_host == b->q_host)
  1819. {
  1820. /* probably both null pointers */
  1821. return TRUE;
  1822. }
  1823. if (a->q_host == NULL || b->q_host == NULL)
  1824. {
  1825. /* only one is a null pointer */
  1826. return FALSE;
  1827. }
  1828. if (strcmp(a->q_host, b->q_host) != 0)
  1829. return FALSE;
  1830. return TRUE;
  1831. }
  1832. /*
  1833. **  PRINTADDR -- print address (for debugging)
  1834. **
  1835. ** Parameters:
  1836. ** a -- the address to print
  1837. ** follow -- follow the q_next chain.
  1838. **
  1839. ** Returns:
  1840. ** none.
  1841. **
  1842. ** Side Effects:
  1843. ** none.
  1844. */
  1845. struct qflags
  1846. {
  1847. char *qf_name;
  1848. u_long qf_bit;
  1849. };
  1850. static struct qflags AddressFlags[] =
  1851. {
  1852. { "QGOODUID", QGOODUID },
  1853. { "QPRIMARY", QPRIMARY },
  1854. { "QNOTREMOTE", QNOTREMOTE },
  1855. { "QSELFREF", QSELFREF },
  1856. { "QBOGUSSHELL", QBOGUSSHELL },
  1857. { "QUNSAFEADDR", QUNSAFEADDR },
  1858. { "QPINGONSUCCESS", QPINGONSUCCESS },
  1859. { "QPINGONFAILURE", QPINGONFAILURE },
  1860. { "QPINGONDELAY", QPINGONDELAY },
  1861. { "QHASNOTIFY", QHASNOTIFY },
  1862. { "QRELAYED", QRELAYED },
  1863. { "QEXPANDED", QEXPANDED },
  1864. { "QDELIVERED", QDELIVERED },
  1865. { "QDELAYED", QDELAYED },
  1866. { "QTHISPASS", QTHISPASS },
  1867. { "QRCPTOK", QRCPTOK },
  1868. { NULL }
  1869. };
  1870. void
  1871. printaddr(a, follow)
  1872. register ADDRESS *a;
  1873. bool follow;
  1874. {
  1875. register MAILER *m;
  1876. MAILER pseudomailer;
  1877. register struct qflags *qfp;
  1878. bool firstone;
  1879. if (a == NULL)
  1880. {
  1881. printf("[NULL]n");
  1882. return;
  1883. }
  1884. while (a != NULL)
  1885. {
  1886. printf("%lx=", (u_long) a);
  1887. (void) fflush(stdout);
  1888. /* find the mailer -- carefully */
  1889. m = a->q_mailer;
  1890. if (m == NULL)
  1891. {
  1892. m = &pseudomailer;
  1893. m->m_mno = -1;
  1894. m->m_name = "NULL";
  1895. }
  1896. printf("%s:ntmailer %d (%s), host `%s'n",
  1897.        a->q_paddr == NULL ? "<null>" : a->q_paddr,
  1898.        m->m_mno, m->m_name,
  1899.        a->q_host == NULL ? "<null>" : a->q_host);
  1900. printf("tuser `%s', ruser `%s'n",
  1901.        a->q_user,
  1902.        a->q_ruser == NULL ? "<null>" : a->q_ruser);
  1903. printf("tstate=");
  1904. switch (a->q_state)
  1905. {
  1906.   case QS_OK:
  1907. printf("OK");
  1908. break;
  1909.   case QS_DONTSEND:
  1910. printf("DONTSEND");
  1911. break;
  1912.   case QS_BADADDR:
  1913. printf("BADADDR");
  1914. break;
  1915.   case QS_QUEUEUP:
  1916. printf("QUEUEUP");
  1917. break;
  1918.   case QS_SENT:
  1919. printf("SENT");
  1920. break;
  1921.   case QS_VERIFIED:
  1922. printf("VERIFIED");
  1923. break;
  1924.   case QS_EXPANDED:
  1925. printf("EXPANDED");
  1926. break;
  1927.   case QS_SENDER:
  1928. printf("SENDER");
  1929. break;
  1930.   case QS_CLONED:
  1931. printf("CLONED");
  1932. break;
  1933.   case QS_DISCARDED:
  1934. printf("DISCARDED");
  1935. break;
  1936.   case QS_REPLACED:
  1937. printf("REPLACED");
  1938. break;
  1939.   case QS_REMOVED:
  1940. printf("REMOVED");
  1941. break;
  1942.   case QS_DUPLICATE:
  1943. printf("DUPLICATE");
  1944. break;
  1945.   case QS_INCLUDED:
  1946. printf("INCLUDED");
  1947. break;
  1948.   default:
  1949. printf("%d", a->q_state);
  1950. break;
  1951. }
  1952. printf(", next=%lx, alias %lx, uid %d, gid %dn",
  1953.        (u_long) a->q_next, (u_long) a->q_alias,
  1954.        (int) a->q_uid, (int) a->q_gid);
  1955. printf("tflags=%lx<", a->q_flags);
  1956. firstone = TRUE;
  1957. for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
  1958. {
  1959. if (!bitset(qfp->qf_bit, a->q_flags))
  1960. continue;
  1961. if (!firstone)
  1962. printf(",");
  1963. firstone = FALSE;
  1964. printf("%s", qfp->qf_name);
  1965. }
  1966. printf(">n");
  1967. printf("towner=%s, home="%s", fullname="%s"n",
  1968.        a->q_owner == NULL ? "(none)" : a->q_owner,
  1969.        a->q_home == NULL ? "(none)" : a->q_home,
  1970.        a->q_fullname == NULL ? "(none)" : a->q_fullname);
  1971. printf("torcpt="%s", statmta=%s, status=%sn",
  1972.        a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
  1973.        a->q_statmta == NULL ? "(none)" : a->q_statmta,
  1974.        a->q_status == NULL ? "(none)" : a->q_status);
  1975. printf("trstatus="%s"n",
  1976.        a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
  1977. printf("tspecificity=%d, statdate=%sn",
  1978.        a->q_specificity,
  1979.        a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate));
  1980. if (!follow)
  1981. return;
  1982. a = a->q_next;
  1983. }
  1984. }
  1985. /*
  1986. **  EMPTYADDR -- return TRUE if this address is empty (``<>'')
  1987. **
  1988. ** Parameters:
  1989. ** a -- pointer to the address
  1990. **
  1991. ** Returns:
  1992. ** TRUE -- if this address is "empty" (i.e., no one should
  1993. ** ever generate replies to it.
  1994. ** FALSE -- if it is a "regular" (read: replyable) address.
  1995. */
  1996. bool
  1997. emptyaddr(a)
  1998. register ADDRESS *a;
  1999. {
  2000. return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
  2001.        a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
  2002. }
  2003. /*
  2004. **  REMOTENAME -- return the name relative to the current mailer
  2005. **
  2006. ** Parameters:
  2007. ** name -- the name to translate.
  2008. ** m -- the mailer that we want to do rewriting relative
  2009. ** to.
  2010. ** flags -- fine tune operations.
  2011. ** pstat -- pointer to status word.
  2012. ** e -- the current envelope.
  2013. **
  2014. ** Returns:
  2015. ** the text string representing this address relative to
  2016. ** the receiving mailer.
  2017. **
  2018. ** Side Effects:
  2019. ** none.
  2020. **
  2021. ** Warnings:
  2022. ** The text string returned is tucked away locally;
  2023. ** copy it if you intend to save it.
  2024. */
  2025. char *
  2026. remotename(name, m, flags, pstat, e)
  2027. char *name;
  2028. struct mailer *m;
  2029. int flags;
  2030. int *pstat;
  2031. register ENVELOPE *e;
  2032. {
  2033. register char **pvp;
  2034. char *fancy;
  2035. char *oldg = macvalue('g', e);
  2036. int rwset;
  2037. static char buf[MAXNAME + 1];
  2038. char lbuf[MAXNAME + 1];
  2039. char pvpbuf[PSBUFSIZE];
  2040. #if _FFR_ADDR_TYPE
  2041. char addrtype[4];
  2042. #endif /* _FFR_ADDR_TYPE */
  2043. if (tTd(12, 1))
  2044. dprintf("remotename(%s)n", name);
  2045. /* don't do anything if we are tagging it as special */
  2046. if (bitset(RF_SENDERADDR, flags))
  2047. {
  2048. rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
  2049.      : m->m_se_rwset;
  2050. #if _FFR_ADDR_TYPE
  2051. addrtype[2] = 's';
  2052. #endif /* _FFR_ADDR_TYPE */
  2053. }
  2054. else
  2055. {
  2056. rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
  2057.      : m->m_re_rwset;
  2058. #if _FFR_ADDR_TYPE
  2059. addrtype[2] = 'r';
  2060. #endif /* _FFR_ADDR_TYPE */
  2061. }
  2062. if (rwset < 0)
  2063. return name;
  2064. #if _FFR_ADDR_TYPE
  2065. addrtype[1] = ' ';
  2066. addrtype[3] = '';
  2067. addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e';
  2068. define(macid("{addr_type}", NULL), addrtype, e);
  2069. #endif /* _FFR_ADDR_TYPE */
  2070. /*
  2071. **  Do a heuristic crack of this name to extract any comment info.
  2072. ** This will leave the name as a comment and a $g macro.
  2073. */
  2074. if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
  2075. fancy = "201g";
  2076. else
  2077. fancy = crackaddr(name);
  2078. /*
  2079. **  Turn the name into canonical form.
  2080. ** Normally this will be RFC 822 style, i.e., "user@domain".
  2081. ** If this only resolves to "user", and the "C" flag is
  2082. ** specified in the sending mailer, then the sender's
  2083. ** domain will be appended.
  2084. */
  2085. pvp = prescan(name, '', pvpbuf, sizeof pvpbuf, NULL, NULL);
  2086. if (pvp == NULL)
  2087. return name;
  2088. if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
  2089. *pstat = EX_TEMPFAIL;
  2090. if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
  2091. {
  2092. /* append from domain to this address */
  2093. register char **pxp = pvp;
  2094. int l = MAXATOM; /* size of buffer for pvp */
  2095. /* see if there is an "@domain" in the current name */
  2096. while (*pxp != NULL && strcmp(*pxp, "@") != 0)
  2097. {
  2098. pxp++;
  2099. --l;
  2100. }
  2101. if (*pxp == NULL)
  2102. {
  2103. /* no.... append the "@domain" from the sender */
  2104. register char **qxq = e->e_fromdomain;
  2105. while ((*pxp++ = *qxq++) != NULL)
  2106. {
  2107. if (--l <= 0)
  2108. {
  2109. *--pxp = NULL;
  2110. usrerr("553 5.1.0 remotename: too many tokens");
  2111. *pstat = EX_UNAVAILABLE;
  2112. break;
  2113. }
  2114. }
  2115. if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
  2116. *pstat = EX_TEMPFAIL;
  2117. }
  2118. }
  2119. /*
  2120. **  Do more specific rewriting.
  2121. ** Rewrite using ruleset 1 or 2 depending on whether this is
  2122. ** a sender address or not.
  2123. ** Then run it through any receiving-mailer-specific rulesets.
  2124. */
  2125. if (bitset(RF_SENDERADDR, flags))
  2126. {
  2127. if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
  2128. *pstat = EX_TEMPFAIL;
  2129. }
  2130. else
  2131. {
  2132. if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
  2133. *pstat = EX_TEMPFAIL;
  2134. }
  2135. if (rwset > 0)
  2136. {
  2137. if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
  2138. *pstat = EX_TEMPFAIL;
  2139. }
  2140. /*
  2141. **  Do any final sanitation the address may require.
  2142. ** This will normally be used to turn internal forms
  2143. ** (e.g., user@host.LOCAL) into external form.  This
  2144. ** may be used as a default to the above rules.
  2145. */
  2146. if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
  2147. *pstat = EX_TEMPFAIL;
  2148. /*
  2149. **  Now restore the comment information we had at the beginning.
  2150. */
  2151. cataddr(pvp, NULL, lbuf, sizeof lbuf, '');
  2152. define('g', lbuf, e);
  2153. /* need to make sure route-addrs have <angle brackets> */
  2154. if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
  2155. expand("<201g>", buf, sizeof buf, e);
  2156. else
  2157. expand(fancy, buf, sizeof buf, e);
  2158. define('g', oldg, e);
  2159. if (tTd(12, 1))
  2160. dprintf("remotename => `%s'n", buf);
  2161. return buf;
  2162. }
  2163. /*
  2164. **  MAPLOCALUSER -- run local username through ruleset 5 for final redirection
  2165. **
  2166. ** Parameters:
  2167. ** a -- the address to map (but just the user name part).
  2168. ** sendq -- the sendq in which to install any replacement
  2169. ** addresses.
  2170. ** aliaslevel -- the alias nesting depth.
  2171. ** e -- the envelope.
  2172. **
  2173. ** Returns:
  2174. ** none.
  2175. */
  2176. #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|
  2177.  Q_PINGFLAGS|QHASNOTIFY|
  2178.  QRELAYED|QEXPANDED|QDELIVERED|QDELAYED)
  2179. void
  2180. maplocaluser(a, sendq, aliaslevel, e)
  2181. register ADDRESS *a;
  2182. ADDRESS **sendq;
  2183. int aliaslevel;
  2184. ENVELOPE *e;
  2185. {
  2186. register char **pvp;
  2187. register ADDRESS *a1 = NULL;
  2188. auto char *delimptr;
  2189. char pvpbuf[PSBUFSIZE];
  2190. if (tTd(29, 1))
  2191. {
  2192. dprintf("maplocaluser: ");
  2193. printaddr(a, FALSE);
  2194. }
  2195. pvp = prescan(a->q_user, '', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
  2196. if (pvp == NULL)
  2197. {
  2198. if (tTd(29, 9))
  2199. dprintf("maplocaluser: cannot prescan %sn",
  2200. a->q_user);
  2201. return;
  2202. }
  2203. define('h', a->q_host, e);
  2204. define('u', a->q_user, e);
  2205. define('z', a->q_home, e);
  2206. #if _FFR_ADDR_TYPE
  2207. define(macid("{addr_type}", NULL), "e r", e);
  2208. #endif /* _FFR_ADDR_TYPE */
  2209. if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL)
  2210. {
  2211. if (tTd(29, 9))
  2212. dprintf("maplocaluser: rewrite tempfailn");
  2213. a->q_state = QS_QUEUEUP;
  2214. a->q_status = "4.4.3";
  2215. return;
  2216. }
  2217. if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
  2218. {
  2219. if (tTd(29, 9))
  2220. dprintf("maplocaluser: doesn't resolven");
  2221. return;
  2222. }
  2223. /* if non-null, mailer destination specified -- has it changed? */
  2224. a1 = buildaddr(pvp, NULL, 0, e);
  2225. if (a1 == NULL || sameaddr(a, a1))
  2226. {
  2227. if (tTd(29, 9))
  2228. dprintf("maplocaluser: address unchangedn");
  2229. if (a1 != NULL)
  2230. free(a1);
  2231. return;
  2232. }
  2233. /* make new address take on flags and print attributes of old */
  2234. a1->q_flags &= ~Q_COPYFLAGS;
  2235. a1->q_flags |= a->q_flags & Q_COPYFLAGS;
  2236. a1->q_paddr = newstr(a->q_paddr);
  2237. a1->q_orcpt = a->q_orcpt;
  2238. /* mark old address as dead; insert new address */
  2239. a->q_state = QS_REPLACED;
  2240. if (tTd(29, 5))
  2241. {
  2242. dprintf("maplocaluser: QS_REPLACED ");
  2243. printaddr(a, FALSE);
  2244. }
  2245. a1->q_alias = a;
  2246. allocaddr(a1, RF_COPYALL, newstr(a->q_paddr));
  2247. (void) recipient(a1, sendq, aliaslevel, e);
  2248. }
  2249. /*
  2250. **  DEQUOTE_INIT -- initialize dequote map
  2251. **
  2252. ** This is a no-op.
  2253. **
  2254. ** Parameters:
  2255. ** map -- the internal map structure.
  2256. ** args -- arguments.
  2257. **
  2258. ** Returns:
  2259. ** TRUE.
  2260. */
  2261. bool
  2262. dequote_init(map, args)
  2263. MAP *map;
  2264. char *args;
  2265. {
  2266. register char *p = args;
  2267. /* there is no check whether there is really an argument */
  2268. map->map_mflags |= MF_KEEPQUOTES;
  2269. for (;;)
  2270. {
  2271. while (isascii(*p) && isspace(*p))
  2272. p++;
  2273. if (*p != '-')
  2274. break;
  2275. switch (*++p)
  2276. {
  2277.   case 'a':
  2278. map->map_app = ++p;
  2279. break;
  2280.   case 'D':
  2281. map->map_mflags |= MF_DEFER;
  2282. break;
  2283.   case 'S':
  2284.   case 's':
  2285. map->map_spacesub = *++p;
  2286. break;
  2287. }
  2288. while (*p != '' && !(isascii(*p) && isspace(*p)))
  2289. p++;
  2290. if (*p != '')
  2291. *p = '';
  2292. }
  2293. if (map->map_app != NULL)
  2294. map->map_app = newstr(map->map_app);
  2295. return TRUE;
  2296. }
  2297. /*
  2298. **  DEQUOTE_MAP -- unquote an address
  2299. **
  2300. ** Parameters:
  2301. ** map -- the internal map structure (ignored).
  2302. ** name -- the name to dequote.
  2303. ** av -- arguments (ignored).
  2304. ** statp -- pointer to status out-parameter.
  2305. **
  2306. ** Returns:
  2307. ** NULL -- if there were no quotes, or if the resulting
  2308. ** unquoted buffer would not be acceptable to prescan.
  2309. ** else -- The dequoted buffer.
  2310. */
  2311. /* ARGSUSED2 */
  2312. char *
  2313. dequote_map(map, name, av, statp)
  2314. MAP *map;
  2315. char *name;
  2316. char **av;
  2317. int *statp;
  2318. {
  2319. register char *p;
  2320. register char *q;
  2321. register char c;
  2322. int anglecnt = 0;
  2323. int cmntcnt = 0;
  2324. int quotecnt = 0;
  2325. int spacecnt = 0;
  2326. bool quotemode = FALSE;
  2327. bool bslashmode = FALSE;
  2328. char spacesub = map->map_spacesub;
  2329. for (p = q = name; (c = *p++) != ''; )
  2330. {
  2331. if (bslashmode)
  2332. {
  2333. bslashmode = FALSE;
  2334. *q++ = c;
  2335. continue;
  2336. }
  2337. if (c == ' ' && spacesub != '')
  2338. c = spacesub;
  2339. switch (c)
  2340. {
  2341.   case '\':
  2342. bslashmode = TRUE;
  2343. break;
  2344.   case '(':
  2345. cmntcnt++;
  2346. break;
  2347.   case ')':
  2348. if (cmntcnt-- <= 0)
  2349. return NULL;
  2350. break;
  2351.   case ' ':
  2352.   case 't':
  2353. spacecnt++;
  2354. break;
  2355. }
  2356. if (cmntcnt > 0)
  2357. {
  2358. *q++ = c;
  2359. continue;
  2360. }
  2361. switch (c)
  2362. {
  2363.   case '"':
  2364. quotemode = !quotemode;
  2365. quotecnt++;
  2366. continue;
  2367.   case '<':
  2368. anglecnt++;
  2369. break;
  2370.   case '>':
  2371. if (anglecnt-- <= 0)
  2372. return NULL;
  2373. break;
  2374. }
  2375. *q++ = c;
  2376. }
  2377. if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
  2378.     quotemode || quotecnt <= 0 || spacecnt != 0)
  2379. return NULL;
  2380. *q++ = '';
  2381. return map_rewrite(map, name, strlen(name), NULL);
  2382. }
  2383. /*
  2384. **  RSCHECK -- check string(s) for validity using rewriting sets
  2385. **
  2386. ** Parameters:
  2387. ** rwset -- the rewriting set to use.
  2388. ** p1 -- the first string to check.
  2389. ** p2 -- the second string to check -- may be null.
  2390. ** e -- the current envelope.
  2391. ** rmcomm -- remove comments?
  2392. ** cnt -- count rejections (statistics)?
  2393. **
  2394. ** Returns:
  2395. ** EX_OK -- if the rwset doesn't resolve to $#error
  2396. ** else -- the failure status (message printed)
  2397. */
  2398. int
  2399. rscheck(rwset, p1, p2, e, rmcomm, cnt)
  2400. char *rwset;
  2401. char *p1;
  2402. char *p2;
  2403. ENVELOPE *e;
  2404. bool rmcomm, cnt;
  2405. {
  2406. char *buf;
  2407. int bufsize;
  2408. int saveexitstat;
  2409. int rstat = EX_OK;
  2410. char **pvp;
  2411. int rsno;
  2412. bool discard = FALSE;
  2413. auto ADDRESS a1;
  2414. bool saveQuickAbort = QuickAbort;
  2415. bool saveSuprErrs = SuprErrs;
  2416. char buf0[MAXLINE];
  2417. char pvpbuf[PSBUFSIZE];
  2418. extern char MsgBuf[];
  2419. if (tTd(48, 2))
  2420. dprintf("rscheck(%s, %s, %s)n", rwset, p1,
  2421. p2 == NULL ? "(NULL)" : p2);
  2422. rsno = strtorwset(rwset, NULL, ST_FIND);
  2423. if (rsno < 0)
  2424. return EX_OK;
  2425. if (p2 != NULL)
  2426. {
  2427. bufsize = strlen(p1) + strlen(p2) + 2;
  2428. if (bufsize > sizeof buf0)
  2429. buf = xalloc(bufsize);
  2430. else
  2431. {
  2432. buf = buf0;
  2433. bufsize = sizeof buf0;
  2434. }
  2435. (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
  2436. }
  2437. else
  2438. {
  2439. bufsize = strlen(p1) + 1;
  2440. if (bufsize > sizeof buf0)
  2441. buf = xalloc(bufsize);
  2442. else
  2443. {
  2444. buf = buf0;
  2445. bufsize = sizeof buf0;
  2446. }
  2447. (void) snprintf(buf, bufsize, "%s", p1);
  2448. }
  2449. SuprErrs = TRUE;
  2450. QuickAbort = FALSE;
  2451. pvp = prescan(buf, '', pvpbuf, sizeof pvpbuf, NULL,
  2452.       rmcomm ? NULL : TokTypeNoC);
  2453. SuprErrs = saveSuprErrs;
  2454. if (pvp == NULL)
  2455. {
  2456. if (tTd(48, 2))
  2457. dprintf("rscheck: cannot prescan inputn");
  2458. /*
  2459. syserr("rscheck: cannot prescan input: "%s"",
  2460. shortenstring(buf, MAXSHORTSTR));
  2461. rstat = EX_DATAERR;
  2462. */
  2463. goto finis;
  2464. }
  2465. (void) rewrite(pvp, rsno, 0, e);
  2466. if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
  2467.     pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
  2468.        strcmp(pvp[1], "discard") != 0))
  2469. {
  2470. goto finis;
  2471. }
  2472. if (strcmp(pvp[1], "discard") == 0)
  2473. {
  2474. if (tTd(48, 2))
  2475. dprintf("rscheck: discard mailer selectedn");
  2476. e->e_flags |= EF_DISCARD;
  2477. discard = TRUE;
  2478. }
  2479. else
  2480. {
  2481. int savelogusrerrs = LogUsrErrs;
  2482. static bool logged = FALSE;
  2483. /* got an error -- process it */
  2484. saveexitstat = ExitStat;
  2485. LogUsrErrs = FALSE;
  2486. (void) buildaddr(pvp, &a1, 0, e);
  2487. LogUsrErrs = savelogusrerrs;
  2488. rstat = ExitStat;
  2489. ExitStat = saveexitstat;
  2490. if (!logged)
  2491. {
  2492. if (cnt)
  2493. markstats(e, &a1, TRUE);
  2494. logged = TRUE;
  2495. }
  2496. }
  2497. if (LogLevel >= 4)
  2498. {
  2499. char *relay;
  2500. char *p;
  2501. char lbuf[MAXLINE];
  2502. p = lbuf;
  2503. if (p2 != NULL)
  2504. {
  2505. snprintf(p, SPACELEFT(lbuf, p),
  2506. ", arg2=%s",
  2507. p2);
  2508. p += strlen(p);
  2509. }
  2510. if ((relay = macvalue('_', e)) != NULL)
  2511. {
  2512. snprintf(p, SPACELEFT(lbuf, p),
  2513. ", relay=%s", relay);
  2514. p += strlen(p);
  2515. }
  2516. *p = '';
  2517. if (discard)
  2518. sm_syslog(LOG_NOTICE, e->e_id,
  2519.   "ruleset=%s, arg1=%s%s, discard",
  2520.   rwset, p1, lbuf);
  2521. else
  2522. sm_syslog(LOG_NOTICE, e->e_id,
  2523.   "ruleset=%s, arg1=%s%s, reject=%s",
  2524.   rwset, p1, lbuf, MsgBuf);
  2525. }
  2526.  finis:
  2527. /* clean up */
  2528. QuickAbort = saveQuickAbort;
  2529. setstat(rstat);
  2530. if (buf != buf0)
  2531. free(buf);
  2532. if (rstat != EX_OK && QuickAbort)
  2533. longjmp(TopFrame, 2);
  2534. return rstat;
  2535. }