2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
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.
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.
12 * $DragonFly: src/contrib/sendmail/src/Attic/parseaddr.c,v 1.2 2003/09/17 15:58:48 drhodus Exp $
17 SM_RCSID("@(#)$Id: parseaddr.c,v 8.359.2.6 2003/03/27 02:39:53 ca Exp $")
19 static void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *));
20 static int callsubr __P((char**, int, ENVELOPE *));
21 static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
22 static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
23 static bool hasctrlchar __P((register char *, bool, bool));
25 /* replacement for illegal characters in addresses */
26 #define BAD_CHAR_REPLACEMENT '?'
29 ** PARSEADDR -- Parse an address
31 ** Parses an address and breaks it up into three parts: a
32 ** net to transmit the message on, the host to transmit it
33 ** to, and a user on that host. These are loaded into an
34 ** ADDRESS header with the values squirreled away if necessary.
35 ** The "user" part may not be a real user; the process may
36 ** just reoccur on that machine. For example, on a machine
37 ** with an arpanet connection, the address
38 ** csvax.bill@berkeley
39 ** will break up to a "user" of 'csvax.bill' and a host
40 ** of 'berkeley' -- to be transmitted over the arpanet.
43 ** addr -- the address to parse.
44 ** a -- a pointer to the address descriptor buffer.
45 ** If NULL, an address will be created.
46 ** flags -- describe detail for parsing. See RF_ definitions
48 ** delim -- the character to terminate the address, passed
50 ** delimptr -- if non-NULL, set to the location of the
51 ** delim character that was found.
52 ** e -- the envelope that will contain this address.
53 ** isrcpt -- true if the address denotes a recipient; false
54 ** indicates a sender.
57 ** A pointer to the address descriptor header (`a' if
65 /* following delimiters are inherent to the internal algorithms */
66 #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
69 parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
79 auto char *delimptrbuf;
81 char pvpbuf[PSBUFSIZE];
84 ** Initialize and prescan address.
89 sm_dprintf("\n--parseaddr(%s)\n", addr);
92 delimptr = &delimptrbuf;
94 pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
98 sm_dprintf("parseaddr-->NULL\n");
102 if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt))
105 sm_dprintf("parseaddr-->bad address\n");
110 ** Save addr if we are going to have to.
112 ** We have to do this early because there is a chance that
113 ** the map lookups in the rewriting rules could clobber
114 ** static memory somewhere.
117 if (bitset(RF_COPYPADDR, flags) && addr != NULL)
119 char savec = **delimptr;
123 e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr);
129 ** Apply rewriting rules.
130 ** Ruleset 0 does basic parsing. It must resolve.
134 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
136 if (REWRITE(pvp, 0, e) == EX_TEMPFAIL)
140 ** Build canonical address from pvp.
143 a = buildaddr(pvp, a, flags, e);
145 if (hasctrlchar(a->q_user, isrcpt, true))
148 sm_dprintf("parseaddr-->bad q_user\n");
151 ** Just mark the address as bad so DSNs work.
152 ** hasctrlchar() has to make sure that the address
153 ** has been sanitized, e.g., shortened.
156 a->q_state = QS_BADADDR;
160 ** Make local copies of the host & user and then
161 ** transport them out.
164 allocaddr(a, flags, addr, e);
165 if (QS_IS_BADADDR(a->q_state))
167 /* weed out bad characters in the printable address too */
168 (void) hasctrlchar(a->q_paddr, isrcpt, false);
173 ** Select a queue directory for recipient addresses.
174 ** This is done here and in split_across_queue_groups(),
175 ** but the latter applies to addresses after aliasing,
176 ** and only if splitting is done.
179 if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) &&
180 !bitset(RF_SENDERADDR|RF_HEADERADDR, flags) &&
181 OpMode != MD_INITALIAS)
185 /* call ruleset which should return a queue group name */
186 r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf,
189 pvp != NULL && pvp[0] != NULL &&
190 (pvp[0][0] & 0377) == CANONNET &&
191 pvp[1] != NULL && pvp[1][0] != '\0')
193 r = name2qid(pvp[1]);
194 if (r == NOQGRP && LogLevel > 10)
195 sm_syslog(LOG_INFO, NOQID,
196 "can't find queue group name %s, selection ignored",
198 if (tTd(20, 4) && r != NOQGRP)
199 sm_syslog(LOG_INFO, NOQID,
200 "queue group name %s -> %d",
202 a->q_qgrp = r == NOQGRP ? ENVQGRP : r;
207 ** If there was a parsing failure, mark it for queueing.
210 if (qup && OpMode != MD_INITALIAS)
212 char *msg = "Transient parse error -- message queued for future delivery";
214 if (e->e_sendmode == SM_DEFER)
215 msg = "Deferring message until queue run";
217 sm_dprintf("parseaddr: queuing message\n");
219 if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
220 e->e_message = sm_rpool_strdup_x(e->e_rpool, msg);
221 a->q_state = QS_QUEUEUP;
222 a->q_status = "4.4.3";
226 ** Compute return value.
231 sm_dprintf("parseaddr-->");
238 ** INVALIDADDR -- check for address containing characters used for macros
241 ** addr -- the address to check.
242 ** delimptr -- if non-NULL: end of address to check, i.e.,
243 ** a pointer in the address string.
244 ** isrcpt -- true iff the address is for a recipient.
247 ** true -- if the address has characters that are reservered
248 ** for macros or is too long.
249 ** false -- otherwise.
253 invalidaddr(addr, delimptr, isrcpt)
259 char savedelim = '\0';
263 if (delimptr != NULL)
265 /* delimptr points to the end of the address to test */
266 savedelim = *delimptr;
267 if (savedelim != '\0') /* if that isn't '\0' already: */
268 *delimptr = '\0'; /* set it */
270 for (; *addr != '\0'; addr++)
272 if ((*addr & 0340) == 0200)
276 *addr = BAD_CHAR_REPLACEMENT;
278 if (++len > MAXNAME - 1)
283 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
293 usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"",
296 usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"",
300 if (delimptr != NULL && savedelim != '\0')
301 *delimptr = savedelim; /* restore old character at delimptr */
305 ** HASCTRLCHAR -- check for address containing meta-characters
307 ** Checks that the address contains no meta-characters, and contains
308 ** no "non-printable" characters unless they are quoted or escaped.
309 ** Quoted or escaped characters are literals.
312 ** addr -- the address to check.
313 ** isrcpt -- true if the address is for a recipient; false
315 ** complain -- true if an error should issued if the address
316 ** is invalid and should be "repaired".
319 ** true -- if the address has any "wierd" characters or
320 ** non-printable characters or if a quote is unbalanced.
321 ** false -- otherwise.
325 hasctrlchar(addr, isrcpt, complain)
327 bool isrcpt, complain;
336 for (; *addr != '\0'; addr++)
338 if (++len > MAXNAME - 1)
342 (void) shorten_rfc822_string(b, MAXNAME - 1);
343 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
349 if (!quoted && (*addr < 32 || *addr == 127))
351 result = "non-printable character";
352 *addr = BAD_CHAR_REPLACEMENT;
357 else if (*addr == '\\')
359 /* XXX Generic problem: no '\0' in strings. */
362 result = "trailing \\ character";
363 *--addr = BAD_CHAR_REPLACEMENT;
367 if ((*addr & 0340) == 0200)
370 result = "8-bit character";
371 *addr = BAD_CHAR_REPLACEMENT;
376 result = "unbalanced quote"; /* unbalanced quote */
377 if (result != NULL && complain)
380 usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)",
383 usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)",
386 return result != NULL;
389 ** ALLOCADDR -- do local allocations of address on demand.
391 ** Also lowercases the host name if requested.
394 ** a -- the address to reallocate.
395 ** flags -- the copy flag (see RF_ definitions in sendmail.h
396 ** for a description).
397 ** paddr -- the printname of the address.
404 ** Copies portions of a into local buffers as requested.
408 allocaddr(a, flags, paddr, e)
415 sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
419 if (a->q_user == NULL)
421 if (a->q_host == NULL)
424 if (bitset(RF_COPYPARSE, flags))
426 a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host);
427 if (a->q_user != a->q_paddr)
428 a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user);
431 if (a->q_paddr == NULL)
432 a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
436 ** PRESCAN -- Prescan name and make it canonical
438 ** Scans a name and turns it into a set of tokens. This process
439 ** deletes blanks and comments (in parentheses) (if the token type
440 ** for left paren is SPC).
442 ** This routine knows about quoted strings and angle brackets.
444 ** There are certain subtleties to this routine. The one that
445 ** comes to mind now is that backslashes on the ends of names
446 ** are silently stripped off; this is intentional. The problem
447 ** is that some versions of sndmsg (like at LBL) set the kill
448 ** character to something other than @ when reading addresses;
449 ** so people type "csvax.eric\@berkeley" -- which screws up the
453 ** addr -- the name to chomp.
454 ** delim -- the delimiter for the address, normally
455 ** '\0' or ','; \0 is accepted in any case.
456 ** If '\t' then we are reading the .cf file.
457 ** pvpbuf -- place to put the saved text -- note that
458 ** the pointers are static.
459 ** pvpbsize -- size of pvpbuf.
460 ** delimptr -- if non-NULL, set to the location of the
461 ** terminating delimiter.
462 ** toktab -- if set, a token table to use for parsing.
463 ** If NULL, use the default table.
466 ** A pointer to a vector of tokens.
470 /* states and character types */
471 #define OPR 0 /* operator */
472 #define ATM 1 /* atom */
473 #define QST 2 /* in quoted string */
474 #define SPC 3 /* chewing up spaces */
475 #define ONE 4 /* pick up one character */
476 #define ILL 5 /* illegal character */
478 #define NSTATES 6 /* number of states */
479 #define TYPE 017 /* mask to select state type */
481 /* meta bits for table */
482 #define M 020 /* meta character; don't pass through */
483 #define B 040 /* cause a break */
484 #define MB M|B /* meta-break */
486 static short StateTab[NSTATES][NSTATES] =
488 /* oldst chtype> OPR ATM QST SPC ONE ILL */
489 /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB },
490 /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB },
491 /*QST*/ { QST, QST, OPR, QST, QST, QST },
492 /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB },
493 /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB },
494 /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M },
497 /* token type table -- it gets modified with $o characters */
498 static unsigned char TokTypeTab[256] =
500 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
501 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
502 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
503 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
504 /* sp ! " # $ % & ' ( ) * + , - . / */
505 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
506 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
507 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
508 /* @ A B C D E F G H I J K L M N O */
509 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
510 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
511 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
512 /* ` a b c d e f g h i j k l m n o */
513 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
514 /* p q r s t u v w x y z { | } ~ del */
515 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
517 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
518 OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
519 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
520 OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
521 /* sp ! " # $ % & ' ( ) * + , - . / */
522 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
523 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
524 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
525 /* @ A B C D E F G H I J K L M N O */
526 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
527 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
528 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
529 /* ` a b c d e f g h i j k l m n o */
530 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
531 /* p q r s t u v w x y z { | } ~ del */
532 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
535 /* token type table for MIME parsing */
536 unsigned char MimeTokenTab[256] =
538 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
539 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
540 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
541 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
542 /* sp ! " # $ % & ' ( ) * + , - . / */
543 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
544 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
545 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
546 /* @ A B C D E F G H I J K L M N O */
547 OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
548 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
549 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
550 /* ` a b c d e f g h i j k l m n o */
551 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
552 /* p q r s t u v w x y z { | } ~ del */
553 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
555 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
556 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
557 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
558 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
559 /* sp ! " # $ % & ' ( ) * + , - . / */
560 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
561 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
562 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
563 /* @ A B C D E F G H I J K L M N O */
564 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
565 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
566 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
567 /* ` a b c d e f g h i j k l m n o */
568 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
569 /* p q r s t u v w x y z { | } ~ del */
570 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
573 /* token type table: don't strip comments */
574 unsigned char TokTypeNoC[256] =
576 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
577 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
578 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
579 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
580 /* sp ! " # $ % & ' ( ) * + , - . / */
581 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM,
582 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
583 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
584 /* @ A B C D E F G H I J K L M N O */
585 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
586 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
587 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
588 /* ` a b c d e f g h i j k l m n o */
589 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
590 /* p q r s t u v w x y z { | } ~ del */
591 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
593 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
594 OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
595 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
596 OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
597 /* sp ! " # $ % & ' ( ) * + , - . / */
598 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
599 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
600 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
601 /* @ A B C D E F G H I J K L M N O */
602 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
603 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
604 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
605 /* ` a b c d e f g h i j k l m n o */
606 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
607 /* p q r s t u v w x y z { | } ~ del */
608 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
612 #define NOCHAR (-1) /* signal nothing in lookahead token */
615 prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
621 unsigned char *toktab;
634 char *saveto = CurEnv->e_to;
635 static char *av[MAXATOM + 1];
636 static bool firsttime = true;
641 /* initialize the token type table */
645 if (OperatorChars == NULL)
648 OperatorChars = macvalue('o', CurEnv);
649 if (OperatorChars == NULL)
650 OperatorChars = ".:@[]";
652 expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS,
654 (void) sm_strlcat(obuf, DELIMCHARS, sizeof obuf);
655 for (p = obuf; *p != '\0'; p++)
657 if (TokTypeTab[*p & 0xff] == ATM)
658 TokTypeTab[*p & 0xff] = OPR;
659 if (TokTypeNoC[*p & 0xff] == ATM)
660 TokTypeNoC[*p & 0xff] = OPR;
666 /* make sure error messages don't have garbage on them */
671 route_syntax = false;
681 sm_dprintf("prescan: ");
692 /* store away any old lookahead character */
693 if (c != NOCHAR && !bslashmode)
695 /* see if there is room */
696 if (q >= &pvpbuf[pvpbsize - 5])
699 usrerr("553 5.1.1 Address too long");
700 if (strlen(addr) > MAXNAME)
701 addr[MAXNAME] = '\0';
703 if (delimptr != NULL)
709 CurEnv->e_to = saveto;
713 /* squirrel it away */
715 if ((char) c == (char) -1 && !tTd(82, 101))
717 #endif /* !ALLOW_255 */
721 /* read a new input character */
725 /* diagnose and patch up bad syntax */
728 usrerr("553 Unbalanced '\"'");
731 else if (cmntcnt > 0)
733 usrerr("553 Unbalanced '('");
736 else if (anglecnt > 0)
739 usrerr("553 Unbalanced '<'");
746 else if (c == delim && cmntcnt <= 0 && state != QST)
751 /* special case for better error management */
752 if (delim == ',' && !route_syntax)
754 usrerr("553 Unbalanced '<'");
761 sm_dprintf("c=%c, s=%d; ", c, state);
763 /* chew up special characters */
769 /* kludge \! for naive users */
775 else if (c != '!' || state == QST)
777 /* see if there is room */
778 if (q >= &pvpbuf[pvpbsize - 5])
789 else if (state == QST)
792 /* do nothing, just avoid next clauses */
794 else if (c == '(' && toktab['('] == SPC)
799 else if (c == ')' && toktab['('] == SPC)
803 usrerr("553 Unbalanced ')'");
809 else if (cmntcnt > 0)
818 while (isascii(*ptr) && isspace(*ptr))
827 usrerr("553 Unbalanced '>'");
832 route_syntax = false;
834 else if (delim == ' ' && isascii(c) && isspace(c))
840 /* see if this is end of input */
841 if (c == delim && anglecnt <= 0 && state != QST)
844 newstate = StateTab[state][toktab[c & 0xff]];
846 sm_dprintf("ns=%02o\n", newstate);
847 state = newstate & TYPE;
850 if (isascii(c) && isprint(c))
851 usrerr("553 Illegal character %c", c);
853 usrerr("553 Illegal character 0x%02x",
856 if (bitset(M, newstate))
858 if (bitset(B, newstate))
865 /* see if there is room */
866 if (q >= &pvpbuf[pvpbsize - 5])
875 if (avp >= &av[MAXATOM])
877 usrerr("553 5.1.0 prescan: too many tokens");
880 if (q - tok > MAXNAME)
882 usrerr("553 5.1.0 prescan: token too long");
887 } while (c != '\0' && (c != delim || anglecnt > 0));
890 if (delimptr != NULL)
894 sm_dprintf("prescan==>");
897 CurEnv->e_to = saveto;
901 sm_dprintf("prescan: null leading token\n");
907 ** REWRITE -- apply rewrite rules to token vector.
909 ** This routine is an ordered production system. Each rewrite
910 ** rule has a LHS (called the pattern) and a RHS (called the
911 ** rewrite); 'rwr' points the the current rewrite rule.
913 ** For each rewrite rule, 'avp' points the address vector we
914 ** are trying to match against, and 'pvp' points to the pattern.
915 ** If pvp points to a special match value (MATCHZANY, MATCHANY,
916 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
917 ** matched is saved away in the match vector (pointed to by 'mvp').
919 ** When a match between avp & pvp does not match, we try to
920 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
921 ** we must also back out the match in mvp. If we reach a
922 ** MATCHANY or MATCHZANY we just extend the match and start
925 ** When we finally match, we rewrite the address vector
926 ** and try over again.
929 ** pvp -- pointer to token vector.
930 ** ruleset -- the ruleset to use for rewriting.
931 ** reclevel -- recursion level (to catch loops).
932 ** e -- the current envelope.
933 ** maxatom -- maximum length of buffer (usually MAXATOM)
936 ** A status code. If EX_TEMPFAIL, higher level code should
945 char **match_first; /* first token matched */
946 char **match_last; /* last token matched */
947 char **match_pattern; /* pointer to pattern */
951 rewrite(pvp, ruleset, reclevel, e, maxatom)
955 register ENVELOPE *e;
958 register char *ap; /* address pointer */
959 register char *rp; /* rewrite pointer */
960 register char *rulename; /* ruleset name */
961 register char *prefix;
962 register char **avp; /* address vector pointer */
963 register char **rvp; /* rewrite vector pointer */
964 register struct match *mlp; /* cur ptr into mlist */
965 register struct rewrite *rwr; /* pointer to current rewrite rule */
966 int ruleno; /* current rule number */
967 int rstat = EX_OK; /* return status */
969 struct match mlist[MAXMATCH]; /* stores match on LHS */
970 char *npvp[MAXATOM + 1]; /* temporary space for rebuild */
974 if (ruleset < 0 || ruleset >= MAXRWSETS)
976 syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset);
979 rulename = RuleSetNames[ruleset];
980 if (rulename == NULL)
982 (void) sm_snprintf(name, sizeof name, "%d", ruleset);
985 if (OpMode == MD_TEST)
988 prefix = "rewrite: ruleset ";
989 if (OpMode == MD_TEST)
991 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
992 "%s%-16.16s input:", prefix, rulename);
997 sm_dprintf("%s%-16.16s input:", prefix, rulename);
1000 if (reclevel++ > MaxRuleRecursion)
1002 syserr("rewrite: excessive recursion (max %d), ruleset %s",
1003 MaxRuleRecursion, rulename);
1010 ** Run through the list of rewrite rules, applying
1016 for (rwr = RewriteRules[ruleset]; rwr != NULL; )
1020 /* if already canonical, quit now */
1021 if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET)
1027 sm_dprintf("-----trying rule (line %d):",
1030 sm_dprintf("-----trying rule:");
1031 printav(rwr->r_lhs);
1034 /* try to match on this rule */
1038 if (++loopcount > 100)
1040 syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
1044 sm_dprintf("workspace: ");
1050 while ((ap = *avp) != NULL || *rvp != NULL)
1055 sm_dprintf("ADVANCE rp=");
1057 sm_dprintf(", ap=");
1063 /* end-of-pattern before end-of-address */
1066 if (ap == NULL && (*rp & 0377) != MATCHZANY &&
1067 (*rp & 0377) != MATCHZERO)
1069 /* end-of-input with patterns left */
1076 /* match any phrase in a class */
1077 mlp->match_pattern = rvp;
1078 mlp->match_first = avp;
1083 mlp->match_last = avp++;
1084 cataddr(mlp->match_first, mlp->match_last,
1085 buf, sizeof buf, '\0');
1086 if (!wordinclass(buf, rp[1]))
1090 sm_dprintf("EXTEND rp=");
1092 sm_dprintf(", ap=");
1099 sm_dprintf("CLMATCH\n");
1104 /* match any token not in a class */
1105 if (wordinclass(ap, rp[1]))
1112 /* match exactly one token */
1113 mlp->match_pattern = rvp;
1114 mlp->match_first = avp;
1115 mlp->match_last = avp++;
1120 /* match zero or more tokens */
1121 mlp->match_pattern = rvp;
1122 mlp->match_first = avp;
1123 mlp->match_last = avp - 1;
1128 /* match zero tokens */
1133 ** Match against run-time macro.
1134 ** This algorithm is broken for the
1135 ** general case (no recursive macros,
1136 ** improper tokenization) but should
1137 ** work for the usual cases.
1140 ap = macvalue(rp[1], e);
1141 mlp->match_first = avp;
1143 sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n",
1145 ap == NULL ? "(NULL)" : ap);
1152 sm_strncasecmp(ap, *avp,
1156 avp = mlp->match_first;
1159 ap += strlen(*avp++);
1166 /* must have exact match */
1167 if (sm_strcasecmp(rp, ap))
1173 /* successful match on this token */
1178 /* match failed -- back up */
1179 while (--mlp >= mlist)
1181 rvp = mlp->match_pattern;
1183 avp = mlp->match_last + 1;
1188 sm_dprintf("BACKUP rp=");
1190 sm_dprintf(", ap=");
1197 /* run off the end -- back up again */
1200 if ((*rp & 0377) == MATCHANY ||
1201 (*rp & 0377) == MATCHZANY)
1203 /* extend binding and continue */
1204 mlp->match_last = avp++;
1209 if ((*rp & 0377) == MATCHCLASS)
1211 /* extend binding and try again */
1212 mlp->match_last = avp;
1219 /* total failure to match */
1225 ** See if we successfully matched
1228 if (mlp < mlist || *rvp != NULL)
1231 sm_dprintf("----- rule fails\n");
1241 sm_dprintf("-----rule matches:");
1248 if ((*rp & 0377) == CANONUSER)
1255 else if ((*rp & 0377) == CANONHOST)
1263 for (avp = npvp; *rvp != NULL; rvp++)
1265 register struct match *m;
1269 if ((*rp & 0377) == MATCHREPL)
1271 /* substitute from LHS */
1272 m = &mlist[rp[1] - '1'];
1273 if (m < mlist || m >= mlp)
1275 syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
1281 sm_dprintf("$%c:", rp[1]);
1282 pp = m->match_first;
1283 while (pp <= m->match_last)
1285 sm_dprintf(" %p=\"", *pp);
1287 sm_dprintf("%s\"", *pp++);
1291 pp = m->match_first;
1292 while (pp <= m->match_last)
1294 if (avp >= &npvp[maxatom])
1296 syserr("554 5.3.0 rewrite: expansion too long");
1300 "rewrite: expansion too long, ruleset=%s, ruleno=%d",
1310 /* some sort of replacement */
1311 if (avp >= &npvp[maxatom])
1314 syserr("554 5.3.0 rewrite: expansion too long");
1316 sm_syslog(LOG_ERR, e->e_id,
1317 "rewrite: expansion too long, ruleset=%s, ruleno=%d",
1321 if ((*rp & 0377) != MACRODEXPAND)
1323 /* vanilla replacement */
1328 /* $&{x} replacement */
1329 char *mval = macvalue(rp[1], e);
1332 static size_t pvpb1_size = 0;
1333 static char **pvpb1 = NULL;
1334 char pvpbuf[PSBUFSIZE];
1337 sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n",
1339 mval == NULL ? "(NULL)" : mval);
1340 if (mval == NULL || *mval == '\0')
1343 /* save the remainder of the input */
1344 for (xpvp = pvp; *xpvp != NULL; xpvp++)
1345 trsize += sizeof *xpvp;
1346 if ((size_t) trsize > pvpb1_size)
1351 sm_pmalloc_x(trsize);
1352 pvpb1_size = trsize;
1355 memmove((char *) pvpb1,
1359 /* scan the new replacement */
1360 xpvp = prescan(mval, '\0', pvpbuf,
1361 sizeof pvpbuf, NULL,
1365 /* prescan pre-printed error */
1369 /* insert it into the output stream */
1370 while (*xpvp != NULL)
1373 sm_dprintf(" ... %s\n",
1375 *avp++ = sm_rpool_strdup_x(
1377 if (avp >= &npvp[maxatom])
1382 sm_dprintf(" ... DONE\n");
1384 /* restore the old trailing input */
1385 memmove((char *) pvp,
1394 ** Check for any hostname/keyword lookups.
1397 for (rvp = npvp; *rvp != NULL; rvp++)
1409 char cbuf[MAXNAME + 1];
1410 char *pvpb1[MAXATOM + 1];
1412 char pvpbuf[PSBUFSIZE];
1415 if ((**rvp & 0377) != HOSTBEGIN &&
1416 (**rvp & 0377) != LOOKUPBEGIN)
1420 ** Got a hostname/keyword lookup.
1422 ** This could be optimized fairly easily.
1426 if ((**rvp & 0377) == HOSTBEGIN)
1433 endtoken = LOOKUPEND;
1436 map = stab(mapname, ST_MAP, ST_FIND);
1438 syserr("554 5.3.0 rewrite: map %s not found", mapname);
1440 /* extract the match part */
1446 while (*rvp != NULL && (**rvp & 0377) != endtoken)
1448 int nodetype = **rvp & 0377;
1450 if (nodetype != CANONHOST && nodetype != CANONUSER)
1460 cataddr(xpvp, NULL, replac,
1461 &pvpbuf[sizeof pvpbuf] - replac,
1463 *++arg_rvp = replac;
1464 replac += strlen(replac) + 1;
1482 cataddr(xpvp, NULL, replac,
1483 &pvpbuf[sizeof pvpbuf] - replac,
1485 *++arg_rvp = replac;
1489 /* save the remainder of the input string */
1490 trsize = (int) (avp - rvp + 1) * sizeof *rvp;
1491 memmove((char *) pvpb1, (char *) rvp, trsize);
1494 cataddr(key_rvp, NULL, cbuf, sizeof cbuf,
1495 map == NULL ? '\0' : map->s_map.map_spacesub);
1497 replac = map_lookup(map, cbuf, argvect, &rstat, e);
1499 /* if no replacement, use default */
1500 if (replac == NULL && default_rvp != NULL)
1502 /* create the default */
1503 cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0');
1511 else if (*replac == '\0')
1513 /* null replacement */
1519 /* scan the new replacement */
1520 xpvp = prescan(replac, '\0', pvpbuf,
1521 sizeof pvpbuf, NULL, NULL);
1524 /* prescan already printed error */
1529 /* append it to the token list */
1530 for (avp = hbrvp; *xpvp != NULL; xpvp++)
1532 *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp);
1533 if (avp >= &npvp[maxatom])
1537 /* restore the old trailing information */
1539 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
1540 if (avp >= &npvp[maxatom])
1545 ** Check for subroutine calls.
1548 status = callsubr(npvp, reclevel, e);
1549 if (rstat == EX_OK || status == EX_TEMPFAIL)
1552 /* copy vector back into original space. */
1553 for (avp = npvp; *avp++ != NULL;)
1555 memmove((char *) pvp, (char *) npvp,
1556 (int) (avp - npvp) * sizeof *avp);
1560 sm_dprintf("rewritten as:");
1565 if (OpMode == MD_TEST)
1567 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1568 "%s%-16.16s returns:", prefix, rulename);
1571 else if (tTd(21, 1))
1573 sm_dprintf("%s%-16.16s returns:", prefix, rulename);
1579 ** CALLSUBR -- call subroutines in rewrite vector
1582 ** pvp -- pointer to token vector.
1583 ** reclevel -- the current recursion level.
1584 ** e -- the current envelope.
1587 ** The status from the subroutine call.
1594 callsubr(pvp, reclevel, e)
1606 int subrnumber[MAX_SUBR];
1607 int subrindex[MAX_SUBR];
1612 ** Look for subroutine calls in pvp, collect them into subr*[]
1613 ** We will perform the calls in the next loop, because we will
1614 ** call the "last" subroutine first to avoid recursive calls
1615 ** and too much copying.
1618 for (avp = pvp, j = 0; *avp != NULL; avp++, j++)
1620 if ((**avp & 0377) == CALLSUBR && avp[1] != NULL)
1622 stripquotes(avp[1]);
1623 subr = strtorwset(avp[1], NULL, ST_FIND);
1626 syserr("554 5.3.5 Unknown ruleset %s", avp[1]);
1631 ** XXX instead of doing this we could optimize
1632 ** the rules after reading them: just remove
1633 ** calls to empty rulesets
1636 /* subroutine is an empty ruleset? don't call it */
1637 if (RewriteRules[subr] == NULL)
1640 sm_dprintf("-----skip subr %s (%d)\n",
1642 for (i = 2; avp[i] != NULL; i++)
1643 avp[i - 2] = avp[i];
1647 if (++nsubr >= MAX_SUBR)
1649 syserr("554 5.3.0 Too many subroutine calls (%d max)",
1653 subrnumber[nsubr] = subr;
1654 subrindex[nsubr] = j;
1659 ** Perform the actual subroutines calls, "last" one first, i.e.,
1660 ** go from the right to the left through all calls,
1661 ** do the rewriting in place.
1664 for (; nsubr > 0; nsubr--)
1666 subr = subrnumber[nsubr];
1667 avp = pvp + subrindex[nsubr];
1669 /* remove the subroutine call and name */
1670 for (i = 2; avp[i] != NULL; i++)
1671 avp[i - 2] = avp[i];
1675 ** Now we need to call the ruleset specified for
1676 ** the subroutine. we can do this inplace since
1677 ** we call the "last" subroutine first.
1680 status = rewrite(avp, subr, reclevel, e,
1681 MAXATOM - subrindex[nsubr]);
1682 if (status != EX_OK && status != EX_TEMPFAIL)
1684 if (rstat == EX_OK || status == EX_TEMPFAIL)
1690 ** MAP_LOOKUP -- do lookup in map
1693 ** smap -- the map to use for the lookup.
1694 ** key -- the key to look up.
1695 ** argvect -- arguments to pass to the map lookup.
1696 ** pstat -- a pointer to an integer in which to store the
1697 ** status from the lookup.
1698 ** e -- the current envelope.
1701 ** The result of the lookup.
1702 ** NULL -- if there was no data for the given key.
1706 map_lookup(smap, key, argvect, pstat, e)
1713 auto int status = EX_OK;
1723 if (e->e_sendmode == SM_DEFER &&
1724 bitset(MF_DEFER, map->map_mflags))
1726 /* don't do any map lookups */
1728 sm_dprintf("map_lookup(%s, %s) => DEFERRED\n",
1730 *pstat = EX_TEMPFAIL;
1734 if (!bitset(MF_KEEPQUOTES, map->map_mflags))
1739 sm_dprintf("map_lookup(%s, %s", smap->s_name, key);
1744 for (i = 0; argvect[i] != NULL; i++)
1745 sm_dprintf(", %%%d=%s", i, argvect[i]);
1747 sm_dprintf(") => ");
1749 replac = (*map->map_class->map_lookup)(map, key, argvect, &status);
1751 sm_dprintf("%s (%d)\n",
1752 replac != NULL ? replac : "NOT FOUND",
1755 /* should recover if status == EX_TEMPFAIL */
1756 if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags))
1758 *pstat = EX_TEMPFAIL;
1760 sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
1761 smap->s_name, key, errno);
1762 if (e->e_message == NULL)
1766 (void) sm_snprintf(mbuf, sizeof mbuf,
1767 "%.80s map: lookup (%s): deferred",
1769 shortenstring(key, MAXSHORTSTR));
1770 e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf);
1773 if (status == EX_TEMPFAIL && map->map_tapp != NULL)
1775 size_t i = strlen(key) + strlen(map->map_tapp) + 1;
1776 static char *rwbuf = NULL;
1777 static size_t rwbuflen = 0;
1784 rwbuf = (char *) sm_pmalloc_x(rwbuflen);
1786 (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp);
1788 sm_dprintf("map_lookup tempfail: returning \"%s\"\n",
1795 ** INITERRMAILERS -- initialize error and discard mailers
1804 ** initializes error and discard mailers.
1807 static MAILER discardmailer;
1808 static MAILER errormailer;
1809 static char *discardargv[] = { "DISCARD", NULL };
1810 static char *errorargv[] = { "ERROR", NULL };
1815 if (discardmailer.m_name == NULL)
1817 /* initialize the discard mailer */
1818 discardmailer.m_name = "*discard*";
1819 discardmailer.m_mailer = "DISCARD";
1820 discardmailer.m_argv = discardargv;
1822 if (errormailer.m_name == NULL)
1824 /* initialize the bogus mailer */
1825 errormailer.m_name = "*error*";
1826 errormailer.m_mailer = "ERROR";
1827 errormailer.m_argv = errorargv;
1831 ** BUILDADDR -- build address from token vector.
1834 ** tv -- token vector.
1835 ** a -- pointer to address descriptor to fill.
1836 ** If NULL, one will be allocated.
1837 ** flags -- info regarding whether this is a sender or
1839 ** e -- the current envelope.
1842 ** NULL if there was an error.
1849 static struct errcodes
1851 char *ec_name; /* name of error code */
1852 int ec_code; /* numeric code */
1855 { "usage", EX_USAGE },
1856 { "nouser", EX_NOUSER },
1857 { "nohost", EX_NOHOST },
1858 { "unavailable", EX_UNAVAILABLE },
1859 { "software", EX_SOFTWARE },
1860 { "tempfail", EX_TEMPFAIL },
1861 { "protocol", EX_PROTOCOL },
1862 { "config", EX_CONFIG },
1863 { NULL, EX_UNAVAILABLE }
1867 buildaddr(tv, a, flags, e)
1869 register ADDRESS *a;
1871 register ENVELOPE *e;
1873 bool tempfail = false;
1875 register struct mailer *m;
1879 char hbuf[MAXNAME + 1];
1880 static char ubuf[MAXNAME + 2];
1884 sm_dprintf("buildaddr, flags=%x, tv=", flags);
1889 a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a);
1890 memset((char *) a, '\0', sizeof *a);
1893 /* set up default error return flags */
1894 a->q_flags |= DefaultNotify;
1896 /* figure out what net/mailer to use */
1897 if (*tv == NULL || (**tv & 0377) != CANONNET)
1899 syserr("554 5.3.5 buildaddr: no mailer in parsed address");
1901 #if _FFR_ALLOW_S0_ERROR_4XX
1903 ** ExitStat may have been set by an earlier map open
1904 ** failure (to a permanent error (EX_OSERR) in syserr())
1905 ** so we also need to check if this particular $#error
1906 ** return wanted a 4XX failure.
1908 ** XXX the real fix is probably to set ExitStat correctly,
1909 ** i.e., to EX_TEMPFAIL if the map open is just a temporary
1912 ** tempfail is tested here even if _FFR_ALLOW_S0_ERROR_4XX
1913 ** is not set; that's ok because it is initialized to false.
1915 #endif /* _FFR_ALLOW_S0_ERROR_4XX */
1917 if (ExitStat == EX_TEMPFAIL || tempfail)
1918 a->q_state = QS_QUEUEUP;
1921 a->q_state = QS_BADADDR;
1922 a->q_mailer = &errormailer;
1928 /* extract host and user portions */
1929 if (*++tv != NULL && (**tv & 0377) == CANONHOST)
1933 while (*tv != NULL && (**tv & 0377) != CANONUSER)
1937 syserr("554 5.3.5 buildaddr: no user");
1942 else if (hostp != NULL)
1943 cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
1944 cataddr(++tv, NULL, ubuf, sizeof ubuf, ' ');
1946 /* save away the host name */
1947 if (sm_strcasecmp(mname, "error") == 0)
1949 /* Set up triplet for use by -bv */
1950 a->q_mailer = &errormailer;
1951 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
1952 /* XXX wrong place? */
1956 register struct errcodes *ep;
1958 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
1959 if (strchr(hbuf, '.') != NULL)
1961 a->q_status = sm_rpool_strdup_x(e->e_rpool,
1963 setstat(dsntoexitstat(hbuf));
1965 else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
1967 setstat(atoi(hbuf));
1971 for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
1972 if (sm_strcasecmp(ep->ec_name, hbuf) == 0)
1974 setstat(ep->ec_code);
1980 setstat(EX_UNAVAILABLE);
1983 if (ISSMTPCODE(ubuf) && ubuf[3] == ' ')
1988 if ((off = isenhsc(ubuf + 4, ' ')) > 0)
1990 ubuf[off + 4] = '\0';
1998 (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s");
2000 usrerr(fmt, ubuf + off);
2001 else if (isenhsc(hbuf, '\0') > 0)
2002 usrerrenh(hbuf, fmt, ubuf + off);
2004 usrerr(fmt, ubuf + off);
2005 /* XXX ubuf[off - 1] = ' '; */
2006 #if _FFR_ALLOW_S0_ERROR_4XX
2009 #endif /* _FFR_ALLOW_S0_ERROR_4XX */
2013 usrerr("553 5.3.0 %s", ubuf);
2018 for (mp = Mailer; (m = *mp++) != NULL; )
2020 if (sm_strcasecmp(m->m_name, mname) == 0)
2025 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname);
2030 /* figure out what host (if any) */
2033 if (!bitnset(M_LOCALMAILER, m->m_flags))
2035 syserr("554 5.3.5 buildaddr: no host");
2041 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
2043 /* figure out the user */
2045 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
2049 a->q_flags |= QNOTREMOTE;
2052 /* do special mapping for local mailer */
2055 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
2056 a->q_mailer = m = ProgMailer;
2057 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
2058 a->q_mailer = m = FileMailer;
2059 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
2061 /* may be :include: */
2063 if (sm_strncasecmp(ubuf, ":include:", 9) == 0)
2065 /* if :include:, don't need further rewriting */
2066 a->q_mailer = m = InclMailer;
2067 a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]);
2072 /* rewrite according recipient mailer rewriting rules */
2073 macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
2075 if (ConfigLevel >= 10 ||
2076 !bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
2078 /* sender addresses done later */
2079 (void) REWRITE(tv, 2, e);
2080 if (m->m_re_rwset > 0)
2081 (void) REWRITE(tv, m->m_re_rwset, e);
2083 (void) REWRITE(tv, 4, e);
2085 /* save the result for the command line/RCPT argument */
2086 cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
2087 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
2090 ** Do mapping to lower case as requested by mailer
2093 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
2094 makelower(a->q_host);
2095 if (!bitnset(M_USR_UPPER, m->m_flags))
2096 makelower(a->q_user);
2100 sm_dprintf("buildaddr => ");
2101 printaddr(a, false);
2107 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
2110 ** pvp -- parameter vector to rebuild.
2111 ** evp -- last parameter to include. Can be NULL to
2113 ** buf -- buffer to build the string into.
2114 ** sz -- size of buf.
2115 ** spacesub -- the space separator character; if '\0',
2126 cataddr(pvp, evp, buf, sz, spacesub)
2133 bool oatomtok = false;
2134 bool natomtok = false;
2141 if (spacesub == '\0')
2142 spacesub = SpaceSub;
2151 while (*pvp != NULL && sz > 0)
2153 natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
2154 if (oatomtok && natomtok)
2160 if ((i = sm_strlcpy(p, *pvp, sz)) >= sz)
2162 oatomtok = natomtok;
2168 #if _FFR_CATCH_LONG_STRINGS
2169 /* Don't silently truncate long strings */
2171 syserr("cataddr: string too long");
2172 #endif /* _FFR_CATCH_LONG_STRINGS */
2176 ** SAMEADDR -- Determine if two addresses are the same
2178 ** This is not just a straight comparison -- if the mailer doesn't
2179 ** care about the host we just ignore it, etc.
2182 ** a, b -- pointers to the internal forms to compare.
2185 ** true -- they represent the same mailbox.
2186 ** false -- they don't.
2194 register ADDRESS *a;
2195 register ADDRESS *b;
2197 register ADDRESS *ca, *cb;
2199 /* if they don't have the same mailer, forget it */
2200 if (a->q_mailer != b->q_mailer)
2203 /* if the user isn't the same, we can drop out */
2204 if (strcmp(a->q_user, b->q_user) != 0)
2207 /* if we have good uids for both but they differ, these are different */
2208 if (a->q_mailer == ProgMailer)
2212 if (ca != NULL && cb != NULL &&
2213 bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
2214 ca->q_uid != cb->q_uid)
2218 /* otherwise compare hosts (but be careful for NULL ptrs) */
2219 if (a->q_host == b->q_host)
2221 /* probably both null pointers */
2224 if (a->q_host == NULL || b->q_host == NULL)
2226 /* only one is a null pointer */
2229 if (strcmp(a->q_host, b->q_host) != 0)
2235 ** PRINTADDR -- print address (for debugging)
2238 ** a -- the address to print
2239 ** follow -- follow the q_next chain.
2251 unsigned long qf_bit;
2254 static struct qflags AddressFlags[] =
2256 { "QGOODUID", QGOODUID },
2257 { "QPRIMARY", QPRIMARY },
2258 { "QNOTREMOTE", QNOTREMOTE },
2259 { "QSELFREF", QSELFREF },
2260 { "QBOGUSSHELL", QBOGUSSHELL },
2261 { "QUNSAFEADDR", QUNSAFEADDR },
2262 { "QPINGONSUCCESS", QPINGONSUCCESS },
2263 { "QPINGONFAILURE", QPINGONFAILURE },
2264 { "QPINGONDELAY", QPINGONDELAY },
2265 { "QHASNOTIFY", QHASNOTIFY },
2266 { "QRELAYED", QRELAYED },
2267 { "QEXPANDED", QEXPANDED },
2268 { "QDELIVERED", QDELIVERED },
2269 { "QDELAYED", QDELAYED },
2270 { "QTHISPASS", QTHISPASS },
2271 { "QRCPTOK", QRCPTOK },
2276 printaddr(a, follow)
2277 register ADDRESS *a;
2281 MAILER pseudomailer;
2282 register struct qflags *qfp;
2287 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "[NULL]\n");
2293 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%p=", a);
2294 (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
2296 /* find the mailer -- carefully */
2305 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2306 "%s:\n\tmailer %d (%s), host `%s'\n",
2307 a->q_paddr == NULL ? "<null>" : a->q_paddr,
2308 m->m_mno, m->m_name,
2309 a->q_host == NULL ? "<null>" : a->q_host);
2310 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2311 "\tuser `%s', ruser `%s'\n",
2313 a->q_ruser == NULL ? "<null>" : a->q_ruser);
2314 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tstate=");
2318 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK");
2322 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2327 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2332 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2337 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "RETRY");
2341 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "SENT");
2345 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2350 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2355 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2360 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2365 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2370 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2375 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2380 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2385 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2390 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2394 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2395 ", next=%p, alias %p, uid %d, gid %d\n",
2396 a->q_next, a->q_alias,
2397 (int) a->q_uid, (int) a->q_gid);
2398 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tflags=%lx<",
2401 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
2403 if (!bitset(qfp->qf_bit, a->q_flags))
2406 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2409 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s",
2412 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">\n");
2413 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2414 "\towner=%s, home=\"%s\", fullname=\"%s\"\n",
2415 a->q_owner == NULL ? "(none)" : a->q_owner,
2416 a->q_home == NULL ? "(none)" : a->q_home,
2417 a->q_fullname == NULL ? "(none)" : a->q_fullname);
2418 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2419 "\torcpt=\"%s\", statmta=%s, status=%s\n",
2420 a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
2421 a->q_statmta == NULL ? "(none)" : a->q_statmta,
2422 a->q_status == NULL ? "(none)" : a->q_status);
2423 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2424 "\tfinalrcpt=\"%s\"\n",
2425 a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt);
2426 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2427 "\trstatus=\"%s\"\n",
2428 a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
2429 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2431 a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate));
2439 ** EMPTYADDR -- return true if this address is empty (``<>'')
2442 ** a -- pointer to the address
2445 ** true -- if this address is "empty" (i.e., no one should
2446 ** ever generate replies to it.
2447 ** false -- if it is a "regular" (read: replyable) address.
2452 register ADDRESS *a;
2454 return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
2455 a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
2458 ** REMOTENAME -- return the name relative to the current mailer
2461 ** name -- the name to translate.
2462 ** m -- the mailer that we want to do rewriting relative
2464 ** flags -- fine tune operations.
2465 ** pstat -- pointer to status word.
2466 ** e -- the current envelope.
2469 ** the text string representing this address relative to
2470 ** the receiving mailer.
2476 ** The text string returned is tucked away locally;
2477 ** copy it if you intend to save it.
2481 remotename(name, m, flags, pstat, e)
2486 register ENVELOPE *e;
2488 register char **pvp;
2489 char *SM_NONVOLATILE fancy;
2492 static char buf[MAXNAME + 1];
2493 char lbuf[MAXNAME + 1];
2494 char pvpbuf[PSBUFSIZE];
2498 sm_dprintf("remotename(%s)\n", name);
2500 /* don't do anything if we are tagging it as special */
2501 if (bitset(RF_SENDERADDR, flags))
2503 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
2509 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
2517 addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e';
2518 macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype);
2521 ** Do a heuristic crack of this name to extract any comment info.
2522 ** This will leave the name as a comment and a $g macro.
2525 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
2528 fancy = crackaddr(name, e);
2531 ** Turn the name into canonical form.
2532 ** Normally this will be RFC 822 style, i.e., "user@domain".
2533 ** If this only resolves to "user", and the "C" flag is
2534 ** specified in the sending mailer, then the sender's
2535 ** domain will be appended.
2538 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
2541 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
2542 *pstat = EX_TEMPFAIL;
2543 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
2545 /* append from domain to this address */
2546 register char **pxp = pvp;
2547 int l = MAXATOM; /* size of buffer for pvp */
2549 /* see if there is an "@domain" in the current name */
2550 while (*pxp != NULL && strcmp(*pxp, "@") != 0)
2557 /* no.... append the "@domain" from the sender */
2558 register char **qxq = e->e_fromdomain;
2560 while ((*pxp++ = *qxq++) != NULL)
2565 usrerr("553 5.1.0 remotename: too many tokens");
2566 *pstat = EX_UNAVAILABLE;
2570 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
2571 *pstat = EX_TEMPFAIL;
2576 ** Do more specific rewriting.
2577 ** Rewrite using ruleset 1 or 2 depending on whether this is
2578 ** a sender address or not.
2579 ** Then run it through any receiving-mailer-specific rulesets.
2582 if (bitset(RF_SENDERADDR, flags))
2584 if (REWRITE(pvp, 1, e) == EX_TEMPFAIL)
2585 *pstat = EX_TEMPFAIL;
2589 if (REWRITE(pvp, 2, e) == EX_TEMPFAIL)
2590 *pstat = EX_TEMPFAIL;
2594 if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL)
2595 *pstat = EX_TEMPFAIL;
2599 ** Do any final sanitation the address may require.
2600 ** This will normally be used to turn internal forms
2601 ** (e.g., user@host.LOCAL) into external form. This
2602 ** may be used as a default to the above rules.
2605 if (REWRITE(pvp, 4, e) == EX_TEMPFAIL)
2606 *pstat = EX_TEMPFAIL;
2609 ** Now restore the comment information we had at the beginning.
2612 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
2613 oldg = macget(&e->e_macro, 'g');
2614 macset(&e->e_macro, 'g', lbuf);
2617 /* need to make sure route-addrs have <angle brackets> */
2618 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
2619 expand("<\201g>", buf, sizeof buf, e);
2621 expand(fancy, buf, sizeof buf, e);
2623 macset(&e->e_macro, 'g', oldg);
2627 sm_dprintf("remotename => `%s'\n", buf);
2631 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
2634 ** a -- the address to map (but just the user name part).
2635 ** sendq -- the sendq in which to install any replacement
2637 ** aliaslevel -- the alias nesting depth.
2638 ** e -- the envelope.
2644 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
2645 Q_PINGFLAGS|QHASNOTIFY|\
2646 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\
2647 QBYTRACE|QBYNDELAY|QBYNRELAY)
2650 maplocaluser(a, sendq, aliaslevel, e)
2651 register ADDRESS *a;
2656 register char **pvp;
2657 register ADDRESS *SM_NONVOLATILE a1 = NULL;
2658 auto char *delimptr;
2659 char pvpbuf[PSBUFSIZE];
2663 sm_dprintf("maplocaluser: ");
2664 printaddr(a, false);
2666 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
2670 sm_dprintf("maplocaluser: cannot prescan %s\n",
2675 macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
2676 macdefine(&e->e_macro, A_PERM, 'u', a->q_user);
2677 macdefine(&e->e_macro, A_PERM, 'z', a->q_home);
2679 macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
2680 if (REWRITE(pvp, 5, e) == EX_TEMPFAIL)
2683 sm_dprintf("maplocaluser: rewrite tempfail\n");
2684 a->q_state = QS_QUEUEUP;
2685 a->q_status = "4.4.3";
2688 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
2691 sm_dprintf("maplocaluser: doesn't resolve\n");
2696 a1 = buildaddr(pvp, NULL, 0, e);
2697 SM_EXCEPT(exc, "E:mta.quickabort")
2700 ** mark address as bad, S5 returned an error
2701 ** and we gave that back to the SMTP client.
2704 a->q_state = QS_DONTSEND;
2705 sm_exc_raisenew_x(&EtypeQuickAbort, 2);
2708 /* if non-null, mailer destination specified -- has it changed? */
2709 if (a1 == NULL || sameaddr(a, a1))
2712 sm_dprintf("maplocaluser: address unchanged\n");
2716 /* make new address take on flags and print attributes of old */
2717 a1->q_flags &= ~Q_COPYFLAGS;
2718 a1->q_flags |= a->q_flags & Q_COPYFLAGS;
2719 a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr);
2720 a1->q_finalrcpt = a->q_finalrcpt;
2721 a1->q_orcpt = a->q_orcpt;
2723 /* mark old address as dead; insert new address */
2724 a->q_state = QS_REPLACED;
2727 sm_dprintf("maplocaluser: QS_REPLACED ");
2728 printaddr(a, false);
2731 allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e);
2732 (void) recipient(a1, sendq, aliaslevel, e);
2735 ** DEQUOTE_INIT -- initialize dequote map
2738 ** map -- the internal map structure.
2739 ** args -- arguments.
2746 dequote_init(map, args)
2750 register char *p = args;
2752 /* there is no check whether there is really an argument */
2753 map->map_mflags |= MF_KEEPQUOTES;
2756 while (isascii(*p) && isspace(*p))
2767 map->map_mflags |= MF_DEFER;
2772 map->map_spacesub = *++p;
2775 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2780 if (map->map_app != NULL)
2781 map->map_app = newstr(map->map_app);
2786 ** DEQUOTE_MAP -- unquote an address
2789 ** map -- the internal map structure (ignored).
2790 ** name -- the name to dequote.
2791 ** av -- arguments (ignored).
2792 ** statp -- pointer to status out-parameter.
2795 ** NULL -- if there were no quotes, or if the resulting
2796 ** unquoted buffer would not be acceptable to prescan.
2797 ** else -- The dequoted buffer.
2802 dequote_map(map, name, av, statp)
2815 bool quotemode = false;
2816 bool bslashmode = false;
2817 char spacesub = map->map_spacesub;
2819 for (p = q = name; (c = *p++) != '\0'; )
2828 if (c == ' ' && spacesub != '\0')
2861 quotemode = !quotemode;
2870 if (anglecnt-- <= 0)
2877 if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
2878 quotemode || quotecnt <= 0 || spacecnt != 0)
2881 return map_rewrite(map, name, strlen(name), NULL);
2884 ** RSCHECK -- check string(s) for validity using rewriting sets
2887 ** rwset -- the rewriting set to use.
2888 ** p1 -- the first string to check.
2889 ** p2 -- the second string to check -- may be null.
2890 ** e -- the current envelope.
2891 ** flags -- control some behavior, see RSF_ in sendmail.h
2892 ** logl -- logging level.
2893 ** host -- NULL or relay host.
2894 ** logid -- id for sm_syslog.
2897 ** EX_OK -- if the rwset doesn't resolve to $#error
2898 ** else -- the failure status (message printed)
2902 rscheck(rwset, p1, p2, e, flags, logl, host, logid)
2915 int volatile rstat = EX_OK;
2918 bool volatile discard = false;
2920 bool saveQuickAbort = QuickAbort;
2921 bool saveSuprErrs = SuprErrs;
2923 bool quarantine = false;
2924 char ubuf[BUFSIZ * 2];
2925 #endif /* _FFR_QUARANTINE */
2927 char pvpbuf[PSBUFSIZE];
2928 extern char MsgBuf[];
2931 sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1,
2932 p2 == NULL ? "(NULL)" : p2);
2934 rsno = strtorwset(rwset, NULL, ST_FIND);
2940 bufsize = strlen(p1) + strlen(p2) + 2;
2941 if (bufsize > sizeof buf0)
2942 buf = sm_malloc_x(bufsize);
2946 bufsize = sizeof buf0;
2948 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
2952 bufsize = strlen(p1) + 1;
2953 if (bufsize > sizeof buf0)
2954 buf = sm_malloc_x(bufsize);
2958 bufsize = sizeof buf0;
2960 (void) sm_strlcpy(buf, p1, bufsize);
2966 pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL,
2967 bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC);
2968 SuprErrs = saveSuprErrs;
2972 sm_dprintf("rscheck: cannot prescan input\n");
2974 syserr("rscheck: cannot prescan input: \"%s\"",
2975 shortenstring(buf, MAXSHORTSTR));
2980 if (bitset(RSF_UNSTRUCTURED, flags))
2982 (void) REWRITE(pvp, rsno, e);
2983 if (bitset(RSF_UNSTRUCTURED, flags))
2984 SuprErrs = saveSuprErrs;
2985 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
2986 pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
2987 strcmp(pvp[1], "discard") != 0))
2992 if (strcmp(pvp[1], "discard") == 0)
2995 sm_dprintf("rscheck: discard mailer selected\n");
2996 e->e_flags |= EF_DISCARD;
3000 else if (strcmp(pvp[1], "error") == 0 &&
3001 pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST &&
3002 pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0)
3004 if (pvp[4] == NULL ||
3005 (pvp[4][0] & 0377) != CANONUSER ||
3007 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
3011 cataddr(&(pvp[5]), NULL, ubuf,
3013 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
3016 macdefine(&e->e_macro, A_PERM,
3017 macid("{quarantine}"), e->e_quarmsg);
3020 #endif /* _FFR_QUARANTINE */
3023 int savelogusrerrs = LogUsrErrs;
3024 static bool logged = false;
3026 /* got an error -- process it */
3027 saveexitstat = ExitStat;
3029 (void) buildaddr(pvp, &a1, 0, e);
3030 LogUsrErrs = savelogusrerrs;
3032 ExitStat = saveexitstat;
3035 if (bitset(RSF_COUNT, flags))
3036 markstats(e, &a1, STATS_REJECT);
3041 if (LogLevel > logl)
3050 (void) sm_snprintf(p, SPACELEFT(lbuf, p),
3059 relay = macvalue('_', e);
3062 (void) sm_snprintf(p, SPACELEFT(lbuf, p),
3063 ", relay=%s", relay);
3068 sm_syslog(LOG_NOTICE, logid,
3069 "ruleset=%s, arg1=%s%s, discard",
3072 else if (quarantine)
3073 sm_syslog(LOG_NOTICE, logid,
3074 "ruleset=%s, arg1=%s%s, quarantine=%s",
3075 rwset, p1, lbuf, ubuf);
3076 #endif /* _FFR_QUARANTINE */
3078 sm_syslog(LOG_NOTICE, logid,
3079 "ruleset=%s, arg1=%s%s, reject=%s",
3080 rwset, p1, lbuf, MsgBuf);
3090 QuickAbort = saveQuickAbort;
3096 /* rulesets don't set errno */
3098 if (rstat != EX_OK && QuickAbort)
3099 sm_exc_raisenew_x(&EtypeQuickAbort, 2);
3103 ** RSCAP -- call rewriting set to return capabilities
3106 ** rwset -- the rewriting set to use.
3107 ** p1 -- the first string to check.
3108 ** p2 -- the second string to check -- may be null.
3109 ** e -- the current envelope.
3110 ** pvp -- pointer to token vector.
3111 ** pvpbuf -- buffer space.
3114 ** EX_UNAVAILABLE -- ruleset doesn't exist.
3115 ** EX_DATAERR -- prescan() failed.
3116 ** EX_OK -- rewrite() was successful.
3117 ** else -- return status from rewrite().
3121 rscap(rwset, p1, p2, e, pvp, pvpbuf, size)
3132 int volatile rstat = EX_OK;
3134 bool saveQuickAbort = QuickAbort;
3135 bool saveSuprErrs = SuprErrs;
3137 extern char MsgBuf[];
3140 sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1,
3141 p2 == NULL ? "(NULL)" : p2);
3145 rsno = strtorwset(rwset, NULL, ST_FIND);
3147 return EX_UNAVAILABLE;
3151 bufsize = strlen(p1) + strlen(p2) + 2;
3152 if (bufsize > sizeof buf0)
3153 buf = sm_malloc_x(bufsize);
3157 bufsize = sizeof buf0;
3159 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
3163 bufsize = strlen(p1) + 1;
3164 if (bufsize > sizeof buf0)
3165 buf = sm_malloc_x(bufsize);
3169 bufsize = sizeof buf0;
3171 (void) sm_strlcpy(buf, p1, bufsize);
3177 *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL);
3179 rstat = REWRITE(*pvp, rsno, e);
3183 sm_dprintf("rscap: cannot prescan input\n");
3192 SuprErrs = saveSuprErrs;
3193 QuickAbort = saveQuickAbort;
3195 /* prevent information leak, this may contain rewrite error */