2 * Copyright (c) 1998-2005 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.
16 SM_RCSID("@(#)$Id: parseaddr.c,v 8.381 2005/02/04 22:01:45 ca Exp $")
18 static void allocaddr
__P((ADDRESS
*, int, char *, ENVELOPE
*));
19 static int callsubr
__P((char**, int, ENVELOPE
*));
20 static char *map_lookup
__P((STAB
*, char *, char **, int *, ENVELOPE
*));
21 static ADDRESS
*buildaddr
__P((char **, ADDRESS
*, int, ENVELOPE
*));
22 static bool hasctrlchar
__P((register char *, bool, bool));
24 /* replacement for illegal characters in addresses */
25 #define BAD_CHAR_REPLACEMENT '?'
28 ** PARSEADDR -- Parse an address
30 ** Parses an address and breaks it up into three parts: a
31 ** net to transmit the message on, the host to transmit it
32 ** to, and a user on that host. These are loaded into an
33 ** ADDRESS header with the values squirreled away if necessary.
34 ** The "user" part may not be a real user; the process may
35 ** just reoccur on that machine. For example, on a machine
36 ** with an arpanet connection, the address
37 ** csvax.bill@berkeley
38 ** will break up to a "user" of 'csvax.bill' and a host
39 ** of 'berkeley' -- to be transmitted over the arpanet.
42 ** addr -- the address to parse.
43 ** a -- a pointer to the address descriptor buffer.
44 ** If NULL, an address will be created.
45 ** flags -- describe detail for parsing. See RF_ definitions
47 ** delim -- the character to terminate the address, passed
49 ** delimptr -- if non-NULL, set to the location of the
50 ** delim character that was found.
51 ** e -- the envelope that will contain this address.
52 ** isrcpt -- true if the address denotes a recipient; false
53 ** indicates a sender.
56 ** A pointer to the address descriptor header (`a' if
64 /* following delimiters are inherent to the internal algorithms */
65 #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
68 parseaddr(addr
, a
, flags
, delim
, delimptr
, e
, isrcpt
)
78 auto char *delimptrbuf
;
80 char pvpbuf
[PSBUFSIZE
];
83 ** Initialize and prescan address.
88 sm_dprintf("\n--parseaddr(%s)\n", addr
);
91 delimptr
= &delimptrbuf
;
93 pvp
= prescan(addr
, delim
, pvpbuf
, sizeof pvpbuf
, delimptr
, NULL
, false);
97 sm_dprintf("parseaddr-->NULL\n");
101 if (invalidaddr(addr
, delim
== '\0' ? NULL
: *delimptr
, isrcpt
))
104 sm_dprintf("parseaddr-->bad address\n");
109 ** Save addr if we are going to have to.
111 ** We have to do this early because there is a chance that
112 ** the map lookups in the rewriting rules could clobber
113 ** static memory somewhere.
116 if (bitset(RF_COPYPADDR
, flags
) && addr
!= NULL
)
118 char savec
= **delimptr
;
122 e
->e_to
= addr
= sm_rpool_strdup_x(e
->e_rpool
, addr
);
128 ** Apply rewriting rules.
129 ** Ruleset 0 does basic parsing. It must resolve.
133 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
135 if (REWRITE(pvp
, 0, e
) == EX_TEMPFAIL
)
139 ** Build canonical address from pvp.
142 a
= buildaddr(pvp
, a
, flags
, e
);
144 if (hasctrlchar(a
->q_user
, isrcpt
, true))
147 sm_dprintf("parseaddr-->bad q_user\n");
150 ** Just mark the address as bad so DSNs work.
151 ** hasctrlchar() has to make sure that the address
152 ** has been sanitized, e.g., shortened.
155 a
->q_state
= QS_BADADDR
;
159 ** Make local copies of the host & user and then
160 ** transport them out.
163 allocaddr(a
, flags
, addr
, e
);
164 if (QS_IS_BADADDR(a
->q_state
))
166 /* weed out bad characters in the printable address too */
167 (void) hasctrlchar(a
->q_paddr
, isrcpt
, false);
172 ** Select a queue directory for recipient addresses.
173 ** This is done here and in split_across_queue_groups(),
174 ** but the latter applies to addresses after aliasing,
175 ** and only if splitting is done.
178 if ((a
->q_qgrp
== NOAQGRP
|| a
->q_qgrp
== ENVQGRP
) &&
179 !bitset(RF_SENDERADDR
|RF_HEADERADDR
, flags
) &&
180 OpMode
!= MD_INITALIAS
)
184 /* call ruleset which should return a queue group name */
185 r
= rscap(RS_QUEUEGROUP
, a
->q_user
, NULL
, e
, &pvp
, pvpbuf
,
188 pvp
!= NULL
&& pvp
[0] != NULL
&&
189 (pvp
[0][0] & 0377) == CANONNET
&&
190 pvp
[1] != NULL
&& pvp
[1][0] != '\0')
192 r
= name2qid(pvp
[1]);
193 if (r
== NOQGRP
&& LogLevel
> 10)
194 sm_syslog(LOG_INFO
, NOQID
,
195 "can't find queue group name %s, selection ignored",
197 if (tTd(20, 4) && r
!= NOQGRP
)
198 sm_syslog(LOG_INFO
, NOQID
,
199 "queue group name %s -> %d",
201 a
->q_qgrp
= r
== NOQGRP
? ENVQGRP
: r
;
206 ** If there was a parsing failure, mark it for queueing.
209 if (qup
&& OpMode
!= MD_INITALIAS
)
211 char *msg
= "Transient parse error -- message queued for future delivery";
213 if (e
->e_sendmode
== SM_DEFER
)
214 msg
= "Deferring message until queue run";
216 sm_dprintf("parseaddr: queuing message\n");
218 if (e
->e_message
== NULL
&& e
->e_sendmode
!= SM_DEFER
)
219 e
->e_message
= sm_rpool_strdup_x(e
->e_rpool
, msg
);
220 a
->q_state
= QS_QUEUEUP
;
221 a
->q_status
= "4.4.3";
225 ** Compute return value.
230 sm_dprintf("parseaddr-->");
231 printaddr(sm_debug_file(), a
, false);
237 ** INVALIDADDR -- check for address containing characters used for macros
240 ** addr -- the address to check.
241 ** delimptr -- if non-NULL: end of address to check, i.e.,
242 ** a pointer in the address string.
243 ** isrcpt -- true iff the address is for a recipient.
246 ** true -- if the address has characters that are reservered
247 ** for macros or is too long.
248 ** false -- otherwise.
252 invalidaddr(addr
, delimptr
, isrcpt
)
258 char savedelim
= '\0';
262 if (delimptr
!= NULL
)
264 /* delimptr points to the end of the address to test */
265 savedelim
= *delimptr
;
266 if (savedelim
!= '\0') /* if that isn't '\0' already: */
267 *delimptr
= '\0'; /* set it */
269 for (; *addr
!= '\0'; addr
++)
271 if ((*addr
& 0340) == 0200)
275 *addr
= BAD_CHAR_REPLACEMENT
;
277 if (++len
> MAXNAME
- 1)
282 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
292 usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"",
295 usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"",
299 if (delimptr
!= NULL
&& savedelim
!= '\0')
300 *delimptr
= savedelim
; /* restore old character at delimptr */
304 ** HASCTRLCHAR -- check for address containing meta-characters
306 ** Checks that the address contains no meta-characters, and contains
307 ** no "non-printable" characters unless they are quoted or escaped.
308 ** Quoted or escaped characters are literals.
311 ** addr -- the address to check.
312 ** isrcpt -- true if the address is for a recipient; false
314 ** complain -- true if an error should issued if the address
315 ** is invalid and should be "repaired".
318 ** true -- if the address has any "wierd" characters or
319 ** non-printable characters or if a quote is unbalanced.
320 ** false -- otherwise.
324 hasctrlchar(addr
, isrcpt
, complain
)
326 bool isrcpt
, complain
;
335 for (; *addr
!= '\0'; addr
++)
337 if (++len
> MAXNAME
- 1)
341 (void) shorten_rfc822_string(b
, MAXNAME
- 1);
342 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
348 if (!quoted
&& (*addr
< 32 || *addr
== 127))
350 result
= "non-printable character";
351 *addr
= BAD_CHAR_REPLACEMENT
;
356 else if (*addr
== '\\')
358 /* XXX Generic problem: no '\0' in strings. */
361 result
= "trailing \\ character";
362 *--addr
= BAD_CHAR_REPLACEMENT
;
366 if ((*addr
& 0340) == 0200)
369 result
= "8-bit character";
370 *addr
= BAD_CHAR_REPLACEMENT
;
375 result
= "unbalanced quote"; /* unbalanced quote */
376 if (result
!= NULL
&& complain
)
379 usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)",
382 usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)",
385 return result
!= NULL
;
388 ** ALLOCADDR -- do local allocations of address on demand.
390 ** Also lowercases the host name if requested.
393 ** a -- the address to reallocate.
394 ** flags -- the copy flag (see RF_ definitions in sendmail.h
395 ** for a description).
396 ** paddr -- the printname of the address.
403 ** Copies portions of a into local buffers as requested.
407 allocaddr(a
, flags
, paddr
, e
)
414 sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags
, paddr
);
418 if (a
->q_user
== NULL
)
420 if (a
->q_host
== NULL
)
423 if (bitset(RF_COPYPARSE
, flags
))
425 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_host
);
426 if (a
->q_user
!= a
->q_paddr
)
427 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_user
);
430 if (a
->q_paddr
== NULL
)
431 a
->q_paddr
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_user
);
435 ** PRESCAN -- Prescan name and make it canonical
437 ** Scans a name and turns it into a set of tokens. This process
438 ** deletes blanks and comments (in parentheses) (if the token type
439 ** for left paren is SPC).
441 ** This routine knows about quoted strings and angle brackets.
443 ** There are certain subtleties to this routine. The one that
444 ** comes to mind now is that backslashes on the ends of names
445 ** are silently stripped off; this is intentional. The problem
446 ** is that some versions of sndmsg (like at LBL) set the kill
447 ** character to something other than @ when reading addresses;
448 ** so people type "csvax.eric\@berkeley" -- which screws up the
452 ** addr -- the name to chomp.
453 ** delim -- the delimiter for the address, normally
454 ** '\0' or ','; \0 is accepted in any case.
455 ** If '\t' then we are reading the .cf file.
456 ** pvpbuf -- place to put the saved text -- note that
457 ** the pointers are static.
458 ** pvpbsize -- size of pvpbuf.
459 ** delimptr -- if non-NULL, set to the location of the
460 ** terminating delimiter.
461 ** toktab -- if set, a token table to use for parsing.
462 ** If NULL, use the default table.
463 ** ignore -- if true, ignore unbalanced addresses
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
, ignore
)
621 unsigned char *toktab
;
635 char *saveto
= CurEnv
->e_to
;
636 static char *av
[MAXATOM
+ 1];
637 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: ");
682 xputs(sm_debug_file(), p
);
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 else if (state
== QST
)
730 usrerr("553 Unbalanced '\"'");
733 else if (cmntcnt
> 0)
735 usrerr("553 Unbalanced '('");
738 else if (anglecnt
> 0)
741 usrerr("553 Unbalanced '<'");
748 else if (c
== delim
&& cmntcnt
<= 0 && state
!= QST
)
753 /* special case for better error management */
754 if (delim
== ',' && !route_syntax
&& !ignore
)
756 usrerr("553 Unbalanced '<'");
763 sm_dprintf("c=%c, s=%d; ", c
, state
);
765 /* chew up special characters */
771 /* kludge \! for naive users */
777 else if (c
!= '!' || state
== QST
)
779 /* see if there is room */
780 if (q
>= &pvpbuf
[pvpbsize
- 5])
791 else if (state
== QST
)
794 /* do nothing, just avoid next clauses */
796 else if (c
== '(' && toktab
['('] == SPC
)
801 else if (c
== ')' && toktab
['('] == SPC
)
807 usrerr("553 Unbalanced ')'");
814 else if (cmntcnt
> 0)
823 while (isascii(*ptr
) && isspace(*ptr
))
834 usrerr("553 Unbalanced '>'");
840 route_syntax
= false;
842 else if (delim
== ' ' && isascii(c
) && isspace(c
))
848 /* see if this is end of input */
849 if (c
== delim
&& anglecnt
<= 0 && state
!= QST
)
852 newstate
= StateTab
[state
][toktab
[c
& 0xff]];
854 sm_dprintf("ns=%02o\n", newstate
);
855 state
= newstate
& TYPE
;
858 if (isascii(c
) && isprint(c
))
859 usrerr("553 Illegal character %c", c
);
861 usrerr("553 Illegal character 0x%02x",
864 if (bitset(M
, newstate
))
866 if (bitset(B
, newstate
))
873 /* see if there is room */
874 if (q
>= &pvpbuf
[pvpbsize
- 5])
880 xputs(sm_debug_file(), tok
);
883 if (avp
>= &av
[MAXATOM
])
885 usrerr("553 5.1.0 prescan: too many tokens");
888 if (q
- tok
> MAXNAME
)
890 usrerr("553 5.1.0 prescan: token too long");
895 } while (c
!= '\0' && (c
!= delim
|| anglecnt
> 0));
897 if (delimptr
!= NULL
)
905 sm_dprintf("prescan==>");
906 printav(sm_debug_file(), av
);
908 CurEnv
->e_to
= saveto
;
912 sm_dprintf("prescan: null leading token\n");
918 ** REWRITE -- apply rewrite rules to token vector.
920 ** This routine is an ordered production system. Each rewrite
921 ** rule has a LHS (called the pattern) and a RHS (called the
922 ** rewrite); 'rwr' points the the current rewrite rule.
924 ** For each rewrite rule, 'avp' points the address vector we
925 ** are trying to match against, and 'pvp' points to the pattern.
926 ** If pvp points to a special match value (MATCHZANY, MATCHANY,
927 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
928 ** matched is saved away in the match vector (pointed to by 'mvp').
930 ** When a match between avp & pvp does not match, we try to
931 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
932 ** we must also back out the match in mvp. If we reach a
933 ** MATCHANY or MATCHZANY we just extend the match and start
936 ** When we finally match, we rewrite the address vector
937 ** and try over again.
940 ** pvp -- pointer to token vector.
941 ** ruleset -- the ruleset to use for rewriting.
942 ** reclevel -- recursion level (to catch loops).
943 ** e -- the current envelope.
944 ** maxatom -- maximum length of buffer (usually MAXATOM)
947 ** A status code. If EX_TEMPFAIL, higher level code should
956 char **match_first
; /* first token matched */
957 char **match_last
; /* last token matched */
958 char **match_pattern
; /* pointer to pattern */
962 rewrite(pvp
, ruleset
, reclevel
, e
, maxatom
)
966 register ENVELOPE
*e
;
969 register char *ap
; /* address pointer */
970 register char *rp
; /* rewrite pointer */
971 register char *rulename
; /* ruleset name */
972 register char *prefix
;
973 register char **avp
; /* address vector pointer */
974 register char **rvp
; /* rewrite vector pointer */
975 register struct match
*mlp
; /* cur ptr into mlist */
976 register struct rewrite
*rwr
; /* pointer to current rewrite rule */
977 int ruleno
; /* current rule number */
978 int rstat
= EX_OK
; /* return status */
980 struct match mlist
[MAXMATCH
]; /* stores match on LHS */
981 char *npvp
[MAXATOM
+ 1]; /* temporary space for rebuild */
986 ** mlp will not exceed mlist[] because readcf enforces
987 ** the upper limit of entries when reading rulesets.
990 if (ruleset
< 0 || ruleset
>= MAXRWSETS
)
992 syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset
);
995 rulename
= RuleSetNames
[ruleset
];
996 if (rulename
== NULL
)
998 (void) sm_snprintf(name
, sizeof name
, "%d", ruleset
);
1001 if (OpMode
== MD_TEST
)
1004 prefix
= "rewrite: ruleset ";
1005 if (OpMode
== MD_TEST
)
1007 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
1008 "%s%-16.16s input:", prefix
, rulename
);
1009 printav(smioout
, pvp
);
1011 else if (tTd(21, 1))
1013 sm_dprintf("%s%-16.16s input:", prefix
, rulename
);
1014 printav(sm_debug_file(), pvp
);
1016 if (reclevel
++ > MaxRuleRecursion
)
1018 syserr("rewrite: excessive recursion (max %d), ruleset %s",
1019 MaxRuleRecursion
, rulename
);
1028 ** Run through the list of rewrite rules, applying
1034 for (rwr
= RewriteRules
[ruleset
]; rwr
!= NULL
; )
1038 /* if already canonical, quit now */
1039 if (pvp
[0] != NULL
&& (pvp
[0][0] & 0377) == CANONNET
)
1045 sm_dprintf("-----trying rule (line %d):",
1048 sm_dprintf("-----trying rule:");
1049 printav(sm_debug_file(), rwr
->r_lhs
);
1052 /* try to match on this rule */
1056 if (++loopcount
> 100)
1058 syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
1062 sm_dprintf("workspace: ");
1063 printav(sm_debug_file(), pvp
);
1068 while ((ap
= *avp
) != NULL
|| *rvp
!= NULL
)
1073 sm_dprintf("ADVANCE rp=");
1074 xputs(sm_debug_file(), rp
);
1075 sm_dprintf(", ap=");
1076 xputs(sm_debug_file(), ap
);
1081 /* end-of-pattern before end-of-address */
1084 if (ap
== NULL
&& (*rp
& 0377) != MATCHZANY
&&
1085 (*rp
& 0377) != MATCHZERO
)
1087 /* end-of-input with patterns left */
1094 /* match any phrase in a class */
1095 mlp
->match_pattern
= rvp
;
1096 mlp
->match_first
= avp
;
1101 mlp
->match_last
= avp
++;
1102 cataddr(mlp
->match_first
, mlp
->match_last
,
1103 buf
, sizeof buf
, '\0');
1104 if (!wordinclass(buf
, rp
[1]))
1108 sm_dprintf("EXTEND rp=");
1109 xputs(sm_debug_file(), rp
);
1110 sm_dprintf(", ap=");
1111 xputs(sm_debug_file(), ap
);
1117 sm_dprintf("CLMATCH\n");
1122 /* match any token not in a class */
1123 if (wordinclass(ap
, rp
[1]))
1130 /* match exactly one token */
1131 mlp
->match_pattern
= rvp
;
1132 mlp
->match_first
= avp
;
1133 mlp
->match_last
= avp
++;
1138 /* match zero or more tokens */
1139 mlp
->match_pattern
= rvp
;
1140 mlp
->match_first
= avp
;
1141 mlp
->match_last
= avp
- 1;
1146 /* match zero tokens */
1151 ** Match against run-time macro.
1152 ** This algorithm is broken for the
1153 ** general case (no recursive macros,
1154 ** improper tokenization) but should
1155 ** work for the usual cases.
1158 ap
= macvalue(rp
[1], e
);
1159 mlp
->match_first
= avp
;
1161 sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n",
1163 ap
== NULL
? "(NULL)" : ap
);
1170 sm_strncasecmp(ap
, *avp
,
1174 avp
= mlp
->match_first
;
1177 ap
+= strlen(*avp
++);
1184 /* must have exact match */
1185 if (sm_strcasecmp(rp
, ap
))
1191 /* successful match on this token */
1196 /* match failed -- back up */
1197 while (--mlp
>= mlist
)
1199 rvp
= mlp
->match_pattern
;
1201 avp
= mlp
->match_last
+ 1;
1206 sm_dprintf("BACKUP rp=");
1207 xputs(sm_debug_file(), rp
);
1208 sm_dprintf(", ap=");
1209 xputs(sm_debug_file(), ap
);
1215 /* run off the end -- back up again */
1218 if ((*rp
& 0377) == MATCHANY
||
1219 (*rp
& 0377) == MATCHZANY
)
1221 /* extend binding and continue */
1222 mlp
->match_last
= avp
++;
1227 if ((*rp
& 0377) == MATCHCLASS
)
1229 /* extend binding and try again */
1230 mlp
->match_last
= avp
;
1237 /* total failure to match */
1243 ** See if we successfully matched
1246 if (mlp
< mlist
|| *rvp
!= NULL
)
1249 sm_dprintf("----- rule fails\n");
1259 sm_dprintf("-----rule matches:");
1260 printav(sm_debug_file(), rvp
);
1266 if ((*rp
& 0377) == CANONUSER
)
1273 else if ((*rp
& 0377) == CANONHOST
)
1281 for (avp
= npvp
; *rvp
!= NULL
; rvp
++)
1283 register struct match
*m
;
1287 if ((*rp
& 0377) == MATCHREPL
)
1289 /* substitute from LHS */
1290 m
= &mlist
[rp
[1] - '1'];
1291 if (m
< mlist
|| m
>= mlp
)
1293 syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
1299 sm_dprintf("$%c:", rp
[1]);
1300 pp
= m
->match_first
;
1301 while (pp
<= m
->match_last
)
1303 sm_dprintf(" %p=\"", *pp
);
1305 sm_dprintf("%s\"", *pp
++);
1309 pp
= m
->match_first
;
1310 while (pp
<= m
->match_last
)
1312 if (avp
>= &npvp
[maxatom
])
1319 /* some sort of replacement */
1320 if (avp
>= &npvp
[maxatom
])
1323 syserr("554 5.3.0 rewrite: expansion too long");
1325 sm_syslog(LOG_ERR
, e
->e_id
,
1326 "rewrite: expansion too long, ruleset=%s, ruleno=%d",
1330 if ((*rp
& 0377) != MACRODEXPAND
)
1332 /* vanilla replacement */
1337 /* $&{x} replacement */
1338 char *mval
= macvalue(rp
[1], e
);
1341 static size_t pvpb1_size
= 0;
1342 static char **pvpb1
= NULL
;
1343 char pvpbuf
[PSBUFSIZE
];
1346 sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n",
1348 mval
== NULL
? "(NULL)" : mval
);
1349 if (mval
== NULL
|| *mval
== '\0')
1352 /* save the remainder of the input */
1353 for (xpvp
= pvp
; *xpvp
!= NULL
; xpvp
++)
1354 trsize
+= sizeof *xpvp
;
1355 if ((size_t) trsize
> pvpb1_size
)
1360 sm_pmalloc_x(trsize
);
1361 pvpb1_size
= trsize
;
1364 memmove((char *) pvpb1
,
1368 /* scan the new replacement */
1369 xpvp
= prescan(mval
, '\0', pvpbuf
,
1370 sizeof pvpbuf
, NULL
,
1374 /* prescan pre-printed error */
1378 /* insert it into the output stream */
1379 while (*xpvp
!= NULL
)
1382 sm_dprintf(" ... %s\n",
1384 *avp
++ = sm_rpool_strdup_x(
1386 if (avp
>= &npvp
[maxatom
])
1391 sm_dprintf(" ... DONE\n");
1393 /* restore the old trailing input */
1394 memmove((char *) pvp
,
1403 ** Check for any hostname/keyword lookups.
1406 for (rvp
= npvp
; *rvp
!= NULL
; rvp
++)
1418 char cbuf
[MAXNAME
+ 1];
1419 char *pvpb1
[MAXATOM
+ 1];
1420 char *argvect
[MAX_MAP_ARGS
];
1421 char pvpbuf
[PSBUFSIZE
];
1424 if ((**rvp
& 0377) != HOSTBEGIN
&&
1425 (**rvp
& 0377) != LOOKUPBEGIN
)
1429 ** Got a hostname/keyword lookup.
1431 ** This could be optimized fairly easily.
1435 if ((**rvp
& 0377) == HOSTBEGIN
)
1442 endtoken
= LOOKUPEND
;
1444 if (mapname
== NULL
)
1445 syserr("554 5.3.0 rewrite: missing mapname");
1447 map
= stab(mapname
, ST_MAP
, ST_FIND
);
1449 syserr("554 5.3.0 rewrite: map %s not found",
1452 /* extract the match part */
1454 if (key_rvp
== NULL
)
1455 syserr("554 5.3.0 rewrite: missing key for map %s",
1461 while (*rvp
!= NULL
&& (**rvp
& 0377) != endtoken
)
1463 int nodetype
= **rvp
& 0377;
1465 if (nodetype
!= CANONHOST
&&
1466 nodetype
!= CANONUSER
)
1476 cataddr(xpvp
, NULL
, replac
,
1477 &pvpbuf
[sizeof pvpbuf
] - replac
,
1480 &argvect
[MAX_MAP_ARGS
- 1])
1481 *++arg_rvp
= replac
;
1482 replac
+= strlen(replac
) + 1;
1500 cataddr(xpvp
, NULL
, replac
,
1501 &pvpbuf
[sizeof pvpbuf
] - replac
,
1503 if (arg_rvp
< &argvect
[MAX_MAP_ARGS
- 1])
1504 *++arg_rvp
= replac
;
1506 if (arg_rvp
>= &argvect
[MAX_MAP_ARGS
- 1])
1507 argvect
[MAX_MAP_ARGS
- 1] = NULL
;
1511 /* save the remainder of the input string */
1512 trsize
= (int) (avp
- rvp
+ 1) * sizeof *rvp
;
1513 memmove((char *) pvpb1
, (char *) rvp
, trsize
);
1516 cataddr(key_rvp
, NULL
, cbuf
, sizeof cbuf
,
1517 map
== NULL
? '\0' : map
->s_map
.map_spacesub
);
1519 replac
= map_lookup(map
, cbuf
, argvect
, &rstat
, e
);
1521 /* if no replacement, use default */
1522 if (replac
== NULL
&& default_rvp
!= NULL
)
1524 /* create the default */
1525 cataddr(default_rvp
, NULL
, cbuf
, sizeof cbuf
, '\0');
1533 else if (*replac
== '\0')
1535 /* null replacement */
1541 /* scan the new replacement */
1542 xpvp
= prescan(replac
, '\0', pvpbuf
,
1543 sizeof pvpbuf
, NULL
, NULL
, false);
1546 /* prescan already printed error */
1551 /* append it to the token list */
1552 for (avp
= hbrvp
; *xpvp
!= NULL
; xpvp
++)
1554 *avp
++ = sm_rpool_strdup_x(e
->e_rpool
, *xpvp
);
1555 if (avp
>= &npvp
[maxatom
])
1559 /* restore the old trailing information */
1561 for (xpvp
= pvpb1
; (*avp
++ = *xpvp
++) != NULL
; )
1562 if (avp
>= &npvp
[maxatom
])
1567 ** Check for subroutine calls.
1570 status
= callsubr(npvp
, reclevel
, e
);
1571 if (rstat
== EX_OK
|| status
== EX_TEMPFAIL
)
1574 /* copy vector back into original space. */
1575 for (avp
= npvp
; *avp
++ != NULL
;)
1577 memmove((char *) pvp
, (char *) npvp
,
1578 (int) (avp
- npvp
) * sizeof *avp
);
1582 sm_dprintf("rewritten as:");
1583 printav(sm_debug_file(), pvp
);
1587 if (OpMode
== MD_TEST
)
1589 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
1590 "%s%-16.16s returns:", prefix
, rulename
);
1591 printav(smioout
, pvp
);
1593 else if (tTd(21, 1))
1595 sm_dprintf("%s%-16.16s returns:", prefix
, rulename
);
1596 printav(sm_debug_file(), pvp
);
1601 ** CALLSUBR -- call subroutines in rewrite vector
1604 ** pvp -- pointer to token vector.
1605 ** reclevel -- the current recursion level.
1606 ** e -- the current envelope.
1609 ** The status from the subroutine call.
1616 callsubr(pvp
, reclevel
, e
)
1628 int subrnumber
[MAX_SUBR
];
1629 int subrindex
[MAX_SUBR
];
1634 ** Look for subroutine calls in pvp, collect them into subr*[]
1635 ** We will perform the calls in the next loop, because we will
1636 ** call the "last" subroutine first to avoid recursive calls
1637 ** and too much copying.
1640 for (avp
= pvp
, j
= 0; *avp
!= NULL
; avp
++, j
++)
1642 if ((**avp
& 0377) == CALLSUBR
&& avp
[1] != NULL
)
1644 stripquotes(avp
[1]);
1645 subr
= strtorwset(avp
[1], NULL
, ST_FIND
);
1648 syserr("554 5.3.5 Unknown ruleset %s", avp
[1]);
1653 ** XXX instead of doing this we could optimize
1654 ** the rules after reading them: just remove
1655 ** calls to empty rulesets
1658 /* subroutine is an empty ruleset? don't call it */
1659 if (RewriteRules
[subr
] == NULL
)
1662 sm_dprintf("-----skip subr %s (%d)\n",
1664 for (i
= 2; avp
[i
] != NULL
; i
++)
1665 avp
[i
- 2] = avp
[i
];
1669 if (++nsubr
>= MAX_SUBR
)
1671 syserr("554 5.3.0 Too many subroutine calls (%d max)",
1675 subrnumber
[nsubr
] = subr
;
1676 subrindex
[nsubr
] = j
;
1681 ** Perform the actual subroutines calls, "last" one first, i.e.,
1682 ** go from the right to the left through all calls,
1683 ** do the rewriting in place.
1686 for (; nsubr
> 0; nsubr
--)
1688 subr
= subrnumber
[nsubr
];
1689 avp
= pvp
+ subrindex
[nsubr
];
1691 /* remove the subroutine call and name */
1692 for (i
= 2; avp
[i
] != NULL
; i
++)
1693 avp
[i
- 2] = avp
[i
];
1697 ** Now we need to call the ruleset specified for
1698 ** the subroutine. We can do this in place since
1699 ** we call the "last" subroutine first.
1702 status
= rewrite(avp
, subr
, reclevel
, e
,
1703 MAXATOM
- subrindex
[nsubr
]);
1704 if (status
!= EX_OK
&& status
!= EX_TEMPFAIL
)
1706 if (rstat
== EX_OK
|| status
== EX_TEMPFAIL
)
1712 ** MAP_LOOKUP -- do lookup in map
1715 ** smap -- the map to use for the lookup.
1716 ** key -- the key to look up.
1717 ** argvect -- arguments to pass to the map lookup.
1718 ** pstat -- a pointer to an integer in which to store the
1719 ** status from the lookup.
1720 ** e -- the current envelope.
1723 ** The result of the lookup.
1724 ** NULL -- if there was no data for the given key.
1728 map_lookup(smap
, key
, argvect
, pstat
, e
)
1735 auto int status
= EX_OK
;
1745 if (e
->e_sendmode
== SM_DEFER
&&
1746 bitset(MF_DEFER
, map
->map_mflags
))
1748 /* don't do any map lookups */
1750 sm_dprintf("map_lookup(%s, %s) => DEFERRED\n",
1752 *pstat
= EX_TEMPFAIL
;
1756 if (!bitset(MF_KEEPQUOTES
, map
->map_mflags
))
1761 sm_dprintf("map_lookup(%s, %s", smap
->s_name
, key
);
1766 for (i
= 0; argvect
[i
] != NULL
; i
++)
1767 sm_dprintf(", %%%d=%s", i
, argvect
[i
]);
1769 sm_dprintf(") => ");
1771 replac
= (*map
->map_class
->map_lookup
)(map
, key
, argvect
, &status
);
1773 sm_dprintf("%s (%d)\n",
1774 replac
!= NULL
? replac
: "NOT FOUND",
1777 /* should recover if status == EX_TEMPFAIL */
1778 if (status
== EX_TEMPFAIL
&& !bitset(MF_NODEFER
, map
->map_mflags
))
1780 *pstat
= EX_TEMPFAIL
;
1782 sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
1783 smap
->s_name
, key
, errno
);
1784 if (e
->e_message
== NULL
)
1788 (void) sm_snprintf(mbuf
, sizeof mbuf
,
1789 "%.80s map: lookup (%s): deferred",
1791 shortenstring(key
, MAXSHORTSTR
));
1792 e
->e_message
= sm_rpool_strdup_x(e
->e_rpool
, mbuf
);
1795 if (status
== EX_TEMPFAIL
&& map
->map_tapp
!= NULL
)
1797 size_t i
= strlen(key
) + strlen(map
->map_tapp
) + 1;
1798 static char *rwbuf
= NULL
;
1799 static size_t rwbuflen
= 0;
1806 rwbuf
= (char *) sm_pmalloc_x(rwbuflen
);
1808 (void) sm_strlcpyn(rwbuf
, rwbuflen
, 2, key
, map
->map_tapp
);
1810 sm_dprintf("map_lookup tempfail: returning \"%s\"\n",
1817 ** INITERRMAILERS -- initialize error and discard mailers
1826 ** initializes error and discard mailers.
1829 static MAILER discardmailer
;
1830 static MAILER errormailer
;
1831 static char *discardargv
[] = { "DISCARD", NULL
};
1832 static char *errorargv
[] = { "ERROR", NULL
};
1837 if (discardmailer
.m_name
== NULL
)
1839 /* initialize the discard mailer */
1840 discardmailer
.m_name
= "*discard*";
1841 discardmailer
.m_mailer
= "DISCARD";
1842 discardmailer
.m_argv
= discardargv
;
1844 if (errormailer
.m_name
== NULL
)
1846 /* initialize the bogus mailer */
1847 errormailer
.m_name
= "*error*";
1848 errormailer
.m_mailer
= "ERROR";
1849 errormailer
.m_argv
= errorargv
;
1853 ** BUILDADDR -- build address from token vector.
1856 ** tv -- token vector.
1857 ** a -- pointer to address descriptor to fill.
1858 ** If NULL, one will be allocated.
1859 ** flags -- info regarding whether this is a sender or
1861 ** e -- the current envelope.
1864 ** NULL if there was an error.
1871 static struct errcodes
1873 char *ec_name
; /* name of error code */
1874 int ec_code
; /* numeric code */
1877 { "usage", EX_USAGE
},
1878 { "nouser", EX_NOUSER
},
1879 { "nohost", EX_NOHOST
},
1880 { "unavailable", EX_UNAVAILABLE
},
1881 { "software", EX_SOFTWARE
},
1882 { "tempfail", EX_TEMPFAIL
},
1883 { "protocol", EX_PROTOCOL
},
1884 { "config", EX_CONFIG
},
1885 { NULL
, EX_UNAVAILABLE
}
1889 buildaddr(tv
, a
, flags
, e
)
1891 register ADDRESS
*a
;
1893 register ENVELOPE
*e
;
1895 bool tempfail
= false;
1898 register struct mailer
*m
;
1902 char hbuf
[MAXNAME
+ 1];
1903 static char ubuf
[MAXNAME
+ 2];
1907 sm_dprintf("buildaddr, flags=%x, tv=", flags
);
1908 printav(sm_debug_file(), tv
);
1913 a
= (ADDRESS
*) sm_rpool_malloc_x(e
->e_rpool
, sizeof *a
);
1914 memset((char *) a
, '\0', sizeof *a
);
1917 /* set up default error return flags */
1918 a
->q_flags
|= DefaultNotify
;
1920 /* figure out what net/mailer to use */
1921 if (*tv
== NULL
|| (**tv
& 0377) != CANONNET
)
1923 syserr("554 5.3.5 buildaddr: no mailer in parsed address");
1926 ** ExitStat may have been set by an earlier map open
1927 ** failure (to a permanent error (EX_OSERR) in syserr())
1928 ** so we also need to check if this particular $#error
1929 ** return wanted a 4XX failure.
1931 ** XXX the real fix is probably to set ExitStat correctly,
1932 ** i.e., to EX_TEMPFAIL if the map open is just a temporary
1936 if (ExitStat
== EX_TEMPFAIL
|| tempfail
)
1937 a
->q_state
= QS_QUEUEUP
;
1940 a
->q_state
= QS_BADADDR
;
1941 a
->q_mailer
= &errormailer
;
1948 /* extract host and user portions */
1949 if (*++tv
!= NULL
&& (**tv
& 0377) == CANONHOST
)
1957 while (*tv
!= NULL
&& (**tv
& 0377) != CANONUSER
)
1964 syserr("554 5.3.5 buildaddr: no user");
1969 else if (hostp
!= NULL
)
1970 cataddr(hostp
, tv
- 1, hbuf
, sizeof hbuf
, '\0');
1971 cataddr(++tv
, NULL
, ubuf
, sizeof ubuf
, ' ');
1974 /* save away the host name */
1975 if (sm_strcasecmp(mname
, "error") == 0)
1977 /* Set up triplet for use by -bv */
1978 a
->q_mailer
= &errormailer
;
1979 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, ubuf
);
1980 /* XXX wrong place? */
1984 register struct errcodes
*ep
;
1986 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, hbuf
);
1987 if (strchr(hbuf
, '.') != NULL
)
1989 a
->q_status
= sm_rpool_strdup_x(e
->e_rpool
,
1991 setstat(dsntoexitstat(hbuf
));
1993 else if (isascii(hbuf
[0]) && isdigit(hbuf
[0]))
1995 setstat(atoi(hbuf
));
1999 for (ep
= ErrorCodes
; ep
->ec_name
!= NULL
; ep
++)
2000 if (sm_strcasecmp(ep
->ec_name
, hbuf
) == 0)
2002 setstat(ep
->ec_code
);
2008 setstat(EX_UNAVAILABLE
);
2011 if (ISSMTPCODE(ubuf
) && ubuf
[3] == ' ')
2016 if ((off
= isenhsc(ubuf
+ 4, ' ')) > 0)
2018 ubuf
[off
+ 4] = '\0';
2026 (void) sm_strlcpyn(fmt
, sizeof fmt
, 2, ubuf
, " %s");
2028 usrerr(fmt
, ubuf
+ off
);
2029 else if (isenhsc(hbuf
, '\0') > 0)
2030 usrerrenh(hbuf
, fmt
, ubuf
+ off
);
2032 usrerr(fmt
, ubuf
+ off
);
2033 /* XXX ubuf[off - 1] = ' '; */
2039 usrerr("553 5.3.0 %s", ubuf
);
2044 for (mp
= Mailer
; (m
= *mp
++) != NULL
; )
2046 if (sm_strcasecmp(m
->m_name
, mname
) == 0)
2051 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname
);
2056 /* figure out what host (if any) */
2059 if (!bitnset(M_LOCALMAILER
, m
->m_flags
))
2061 syserr("554 5.3.5 buildaddr: no host");
2067 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, hbuf
);
2069 /* figure out the user */
2071 if (bitnset(M_CHECKUDB
, m
->m_flags
) && *p
== '@')
2076 a
->q_flags
|= QNOTREMOTE
;
2079 /* do special mapping for local mailer */
2082 if (*p
== '|' && bitnset(M_CHECKPROG
, m
->m_flags
))
2083 a
->q_mailer
= m
= ProgMailer
;
2084 else if (*p
== '/' && bitnset(M_CHECKFILE
, m
->m_flags
))
2085 a
->q_mailer
= m
= FileMailer
;
2086 else if (*p
== ':' && bitnset(M_CHECKINCLUDE
, m
->m_flags
))
2088 /* may be :include: */
2090 if (sm_strncasecmp(ubuf
, ":include:", 9) == 0)
2092 /* if :include:, don't need further rewriting */
2093 a
->q_mailer
= m
= InclMailer
;
2094 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, &ubuf
[9]);
2099 /* rewrite according recipient mailer rewriting rules */
2100 macdefine(&e
->e_macro
, A_PERM
, 'h', a
->q_host
);
2102 if (ConfigLevel
>= 10 ||
2103 !bitset(RF_SENDERADDR
|RF_HEADERADDR
, flags
))
2105 /* sender addresses done later */
2106 (void) rewrite(tv
, 2, 0, e
, maxatom
);
2107 if (m
->m_re_rwset
> 0)
2108 (void) rewrite(tv
, m
->m_re_rwset
, 0, e
, maxatom
);
2110 (void) rewrite(tv
, 4, 0, e
, maxatom
);
2112 /* save the result for the command line/RCPT argument */
2113 cataddr(tv
, NULL
, ubuf
, sizeof ubuf
, '\0');
2114 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, ubuf
);
2117 ** Do mapping to lower case as requested by mailer
2120 if (a
->q_host
!= NULL
&& !bitnset(M_HST_UPPER
, m
->m_flags
))
2121 makelower(a
->q_host
);
2122 if (!bitnset(M_USR_UPPER
, m
->m_flags
))
2123 makelower(a
->q_user
);
2127 sm_dprintf("buildaddr => ");
2128 printaddr(sm_debug_file(), a
, false);
2134 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
2137 ** pvp -- parameter vector to rebuild.
2138 ** evp -- last parameter to include. Can be NULL to
2140 ** buf -- buffer to build the string into.
2141 ** sz -- size of buf.
2142 ** spacesub -- the space separator character; if '\0',
2153 cataddr(pvp
, evp
, buf
, sz
, spacesub
)
2160 bool oatomtok
= false;
2161 bool natomtok
= false;
2168 if (spacesub
== '\0')
2169 spacesub
= SpaceSub
;
2178 while (*pvp
!= NULL
&& sz
> 0)
2180 natomtok
= (TokTypeTab
[**pvp
& 0xff] == ATM
);
2181 if (oatomtok
&& natomtok
)
2187 i
= sm_strlcpy(p
, *pvp
, sz
);
2191 oatomtok
= natomtok
;
2199 ** Silently truncate long strings: even though this doesn't
2200 ** seem like a good idea it is necessary because header checks
2201 ** send the whole header value to rscheck() and hence rewrite().
2202 ** The latter however sometimes uses a "short" buffer (e.g.,
2203 ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this
2204 ** error function. One possible fix to the problem is to pass
2205 ** flags to rscheck() and rewrite() to distinguish the various
2206 ** calls and only trigger the error if necessary. For now just
2207 ** undo the change from 8.13.0.
2211 usrerr("cataddr: string too long");
2216 ** SAMEADDR -- Determine if two addresses are the same
2218 ** This is not just a straight comparison -- if the mailer doesn't
2219 ** care about the host we just ignore it, etc.
2222 ** a, b -- pointers to the internal forms to compare.
2225 ** true -- they represent the same mailbox.
2226 ** false -- they don't.
2234 register ADDRESS
*a
;
2235 register ADDRESS
*b
;
2237 register ADDRESS
*ca
, *cb
;
2239 /* if they don't have the same mailer, forget it */
2240 if (a
->q_mailer
!= b
->q_mailer
)
2243 /* if the user isn't the same, we can drop out */
2244 if (strcmp(a
->q_user
, b
->q_user
) != 0)
2247 /* if we have good uids for both but they differ, these are different */
2248 if (a
->q_mailer
== ProgMailer
)
2252 if (ca
!= NULL
&& cb
!= NULL
&&
2253 bitset(QGOODUID
, ca
->q_flags
& cb
->q_flags
) &&
2254 ca
->q_uid
!= cb
->q_uid
)
2258 /* otherwise compare hosts (but be careful for NULL ptrs) */
2259 if (a
->q_host
== b
->q_host
)
2261 /* probably both null pointers */
2264 if (a
->q_host
== NULL
|| b
->q_host
== NULL
)
2266 /* only one is a null pointer */
2269 if (strcmp(a
->q_host
, b
->q_host
) != 0)
2275 ** PRINTADDR -- print address (for debugging)
2278 ** a -- the address to print
2279 ** follow -- follow the q_next chain.
2291 unsigned long qf_bit
;
2294 static struct qflags AddressFlags
[] =
2296 { "QGOODUID", QGOODUID
},
2297 { "QPRIMARY", QPRIMARY
},
2298 { "QNOTREMOTE", QNOTREMOTE
},
2299 { "QSELFREF", QSELFREF
},
2300 { "QBOGUSSHELL", QBOGUSSHELL
},
2301 { "QUNSAFEADDR", QUNSAFEADDR
},
2302 { "QPINGONSUCCESS", QPINGONSUCCESS
},
2303 { "QPINGONFAILURE", QPINGONFAILURE
},
2304 { "QPINGONDELAY", QPINGONDELAY
},
2305 { "QHASNOTIFY", QHASNOTIFY
},
2306 { "QRELAYED", QRELAYED
},
2307 { "QEXPANDED", QEXPANDED
},
2308 { "QDELIVERED", QDELIVERED
},
2309 { "QDELAYED", QDELAYED
},
2310 { "QTHISPASS", QTHISPASS
},
2311 { "QRCPTOK", QRCPTOK
},
2316 printaddr(fp
, a
, follow
)
2318 register ADDRESS
*a
;
2322 MAILER pseudomailer
;
2323 register struct qflags
*qfp
;
2328 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "[NULL]\n");
2334 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "%p=", a
);
2335 (void) sm_io_flush(fp
, SM_TIME_DEFAULT
);
2337 /* find the mailer -- carefully */
2346 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2347 "%s:\n\tmailer %d (%s), host `%s'\n",
2348 a
->q_paddr
== NULL
? "<null>" : a
->q_paddr
,
2349 m
->m_mno
, m
->m_name
,
2350 a
->q_host
== NULL
? "<null>" : a
->q_host
);
2351 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2352 "\tuser `%s', ruser `%s'\n",
2354 a
->q_ruser
== NULL
? "<null>" : a
->q_ruser
);
2355 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "\tstate=");
2359 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "OK");
2363 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2368 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2373 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2378 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "RETRY");
2382 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "SENT");
2386 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2391 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2396 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2401 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2406 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2411 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2416 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2421 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2426 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2431 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2435 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2436 ", next=%p, alias %p, uid %d, gid %d\n",
2437 a
->q_next
, a
->q_alias
,
2438 (int) a
->q_uid
, (int) a
->q_gid
);
2439 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "\tflags=%lx<",
2442 for (qfp
= AddressFlags
; qfp
->qf_name
!= NULL
; qfp
++)
2444 if (!bitset(qfp
->qf_bit
, a
->q_flags
))
2447 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2450 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "%s",
2453 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, ">\n");
2454 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2455 "\towner=%s, home=\"%s\", fullname=\"%s\"\n",
2456 a
->q_owner
== NULL
? "(none)" : a
->q_owner
,
2457 a
->q_home
== NULL
? "(none)" : a
->q_home
,
2458 a
->q_fullname
== NULL
? "(none)" : a
->q_fullname
);
2459 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2460 "\torcpt=\"%s\", statmta=%s, status=%s\n",
2461 a
->q_orcpt
== NULL
? "(none)" : a
->q_orcpt
,
2462 a
->q_statmta
== NULL
? "(none)" : a
->q_statmta
,
2463 a
->q_status
== NULL
? "(none)" : a
->q_status
);
2464 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2465 "\tfinalrcpt=\"%s\"\n",
2466 a
->q_finalrcpt
== NULL
? "(none)" : a
->q_finalrcpt
);
2467 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2468 "\trstatus=\"%s\"\n",
2469 a
->q_rstatus
== NULL
? "(none)" : a
->q_rstatus
);
2470 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2472 a
->q_statdate
== 0 ? "(none)" : ctime(&a
->q_statdate
));
2480 ** EMPTYADDR -- return true if this address is empty (``<>'')
2483 ** a -- pointer to the address
2486 ** true -- if this address is "empty" (i.e., no one should
2487 ** ever generate replies to it.
2488 ** false -- if it is a "regular" (read: replyable) address.
2493 register ADDRESS
*a
;
2495 return a
->q_paddr
== NULL
|| strcmp(a
->q_paddr
, "<>") == 0 ||
2496 a
->q_user
== NULL
|| strcmp(a
->q_user
, "<>") == 0;
2499 ** REMOTENAME -- return the name relative to the current mailer
2502 ** name -- the name to translate.
2503 ** m -- the mailer that we want to do rewriting relative to.
2504 ** flags -- fine tune operations.
2505 ** pstat -- pointer to status word.
2506 ** e -- the current envelope.
2509 ** the text string representing this address relative to
2510 ** the receiving mailer.
2516 ** The text string returned is tucked away locally;
2517 ** copy it if you intend to save it.
2521 remotename(name
, m
, flags
, pstat
, e
)
2526 register ENVELOPE
*e
;
2528 register char **pvp
;
2529 char *SM_NONVOLATILE fancy
;
2532 static char buf
[MAXNAME
+ 1];
2533 char lbuf
[MAXNAME
+ 1];
2534 char pvpbuf
[PSBUFSIZE
];
2538 sm_dprintf("remotename(%s)\n", name
);
2540 /* don't do anything if we are tagging it as special */
2541 if (bitset(RF_SENDERADDR
, flags
))
2543 rwset
= bitset(RF_HEADERADDR
, flags
) ? m
->m_sh_rwset
2549 rwset
= bitset(RF_HEADERADDR
, flags
) ? m
->m_rh_rwset
2557 addrtype
[0] = bitset(RF_HEADERADDR
, flags
) ? 'h' : 'e';
2558 macdefine(&e
->e_macro
, A_TEMP
, macid("{addr_type}"), addrtype
);
2561 ** Do a heuristic crack of this name to extract any comment info.
2562 ** This will leave the name as a comment and a $g macro.
2565 if (bitset(RF_CANONICAL
, flags
) || bitnset(M_NOCOMMENT
, m
->m_flags
))
2568 fancy
= crackaddr(name
, e
);
2571 ** Turn the name into canonical form.
2572 ** Normally this will be RFC 822 style, i.e., "user@domain".
2573 ** If this only resolves to "user", and the "C" flag is
2574 ** specified in the sending mailer, then the sender's
2575 ** domain will be appended.
2578 pvp
= prescan(name
, '\0', pvpbuf
, sizeof pvpbuf
, NULL
, NULL
, false);
2581 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
2582 *pstat
= EX_TEMPFAIL
;
2583 if (bitset(RF_ADDDOMAIN
, flags
) && e
->e_fromdomain
!= NULL
)
2585 /* append from domain to this address */
2586 register char **pxp
= pvp
;
2587 int l
= MAXATOM
; /* size of buffer for pvp */
2589 /* see if there is an "@domain" in the current name */
2590 while (*pxp
!= NULL
&& strcmp(*pxp
, "@") != 0)
2597 /* no.... append the "@domain" from the sender */
2598 register char **qxq
= e
->e_fromdomain
;
2600 while ((*pxp
++ = *qxq
++) != NULL
)
2605 usrerr("553 5.1.0 remotename: too many tokens");
2606 *pstat
= EX_UNAVAILABLE
;
2610 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
2611 *pstat
= EX_TEMPFAIL
;
2616 ** Do more specific rewriting.
2617 ** Rewrite using ruleset 1 or 2 depending on whether this is
2618 ** a sender address or not.
2619 ** Then run it through any receiving-mailer-specific rulesets.
2622 if (bitset(RF_SENDERADDR
, flags
))
2624 if (REWRITE(pvp
, 1, e
) == EX_TEMPFAIL
)
2625 *pstat
= EX_TEMPFAIL
;
2629 if (REWRITE(pvp
, 2, e
) == EX_TEMPFAIL
)
2630 *pstat
= EX_TEMPFAIL
;
2634 if (REWRITE(pvp
, rwset
, e
) == EX_TEMPFAIL
)
2635 *pstat
= EX_TEMPFAIL
;
2639 ** Do any final sanitation the address may require.
2640 ** This will normally be used to turn internal forms
2641 ** (e.g., user@host.LOCAL) into external form. This
2642 ** may be used as a default to the above rules.
2645 if (REWRITE(pvp
, 4, e
) == EX_TEMPFAIL
)
2646 *pstat
= EX_TEMPFAIL
;
2649 ** Now restore the comment information we had at the beginning.
2652 cataddr(pvp
, NULL
, lbuf
, sizeof lbuf
, '\0');
2653 oldg
= macget(&e
->e_macro
, 'g');
2654 macset(&e
->e_macro
, 'g', lbuf
);
2657 /* need to make sure route-addrs have <angle brackets> */
2658 if (bitset(RF_CANONICAL
, flags
) && lbuf
[0] == '@')
2659 expand("<\201g>", buf
, sizeof buf
, e
);
2661 expand(fancy
, buf
, sizeof buf
, e
);
2663 macset(&e
->e_macro
, 'g', oldg
);
2667 sm_dprintf("remotename => `%s'\n", buf
);
2671 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
2674 ** a -- the address to map (but just the user name part).
2675 ** sendq -- the sendq in which to install any replacement
2677 ** aliaslevel -- the alias nesting depth.
2678 ** e -- the envelope.
2684 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
2685 Q_PINGFLAGS|QHASNOTIFY|\
2686 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\
2687 QBYTRACE|QBYNDELAY|QBYNRELAY)
2690 maplocaluser(a
, sendq
, aliaslevel
, e
)
2691 register ADDRESS
*a
;
2696 register char **pvp
;
2697 register ADDRESS
*SM_NONVOLATILE a1
= NULL
;
2698 char pvpbuf
[PSBUFSIZE
];
2702 sm_dprintf("maplocaluser: ");
2703 printaddr(sm_debug_file(), a
, false);
2705 pvp
= prescan(a
->q_user
, '\0', pvpbuf
, sizeof pvpbuf
, NULL
, NULL
, false);
2709 sm_dprintf("maplocaluser: cannot prescan %s\n",
2714 macdefine(&e
->e_macro
, A_PERM
, 'h', a
->q_host
);
2715 macdefine(&e
->e_macro
, A_PERM
, 'u', a
->q_user
);
2716 macdefine(&e
->e_macro
, A_PERM
, 'z', a
->q_home
);
2718 macdefine(&e
->e_macro
, A_PERM
, macid("{addr_type}"), "e r");
2719 if (REWRITE(pvp
, 5, e
) == EX_TEMPFAIL
)
2722 sm_dprintf("maplocaluser: rewrite tempfail\n");
2723 a
->q_state
= QS_QUEUEUP
;
2724 a
->q_status
= "4.4.3";
2727 if (pvp
[0] == NULL
|| (pvp
[0][0] & 0377) != CANONNET
)
2730 sm_dprintf("maplocaluser: doesn't resolve\n");
2735 a1
= buildaddr(pvp
, NULL
, 0, e
);
2736 SM_EXCEPT(exc
, "E:mta.quickabort")
2739 ** mark address as bad, S5 returned an error
2740 ** and we gave that back to the SMTP client.
2743 a
->q_state
= QS_DONTSEND
;
2744 sm_exc_raisenew_x(&EtypeQuickAbort
, 2);
2747 /* if non-null, mailer destination specified -- has it changed? */
2748 if (a1
== NULL
|| sameaddr(a
, a1
))
2751 sm_dprintf("maplocaluser: address unchanged\n");
2755 /* make new address take on flags and print attributes of old */
2756 a1
->q_flags
&= ~Q_COPYFLAGS
;
2757 a1
->q_flags
|= a
->q_flags
& Q_COPYFLAGS
;
2758 a1
->q_paddr
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_paddr
);
2759 a1
->q_finalrcpt
= a
->q_finalrcpt
;
2760 a1
->q_orcpt
= a
->q_orcpt
;
2762 /* mark old address as dead; insert new address */
2763 a
->q_state
= QS_REPLACED
;
2766 sm_dprintf("maplocaluser: QS_REPLACED ");
2767 printaddr(sm_debug_file(), a
, false);
2770 allocaddr(a1
, RF_COPYALL
, sm_rpool_strdup_x(e
->e_rpool
, a
->q_paddr
), e
);
2771 (void) recipient(a1
, sendq
, aliaslevel
, e
);
2774 ** DEQUOTE_INIT -- initialize dequote map
2777 ** map -- the internal map structure.
2778 ** args -- arguments.
2785 dequote_init(map
, args
)
2789 register char *p
= args
;
2791 /* there is no check whether there is really an argument */
2792 map
->map_mflags
|= MF_KEEPQUOTES
;
2795 while (isascii(*p
) && isspace(*p
))
2806 map
->map_mflags
|= MF_DEFER
;
2811 map
->map_spacesub
= *++p
;
2814 while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
2819 if (map
->map_app
!= NULL
)
2820 map
->map_app
= newstr(map
->map_app
);
2825 ** DEQUOTE_MAP -- unquote an address
2828 ** map -- the internal map structure (ignored).
2829 ** name -- the name to dequote.
2830 ** av -- arguments (ignored).
2831 ** statp -- pointer to status out-parameter.
2834 ** NULL -- if there were no quotes, or if the resulting
2835 ** unquoted buffer would not be acceptable to prescan.
2836 ** else -- The dequoted buffer.
2841 dequote_map(map
, name
, av
, statp
)
2854 bool quotemode
= false;
2855 bool bslashmode
= false;
2856 char spacesub
= map
->map_spacesub
;
2858 for (p
= q
= name
; (c
= *p
++) != '\0'; )
2867 if (c
== ' ' && spacesub
!= '\0')
2900 quotemode
= !quotemode
;
2909 if (anglecnt
-- <= 0)
2916 if (anglecnt
!= 0 || cmntcnt
!= 0 || bslashmode
||
2917 quotemode
|| quotecnt
<= 0 || spacecnt
!= 0)
2920 return map_rewrite(map
, name
, strlen(name
), NULL
);
2923 ** RSCHECK -- check string(s) for validity using rewriting sets
2926 ** rwset -- the rewriting set to use.
2927 ** p1 -- the first string to check.
2928 ** p2 -- the second string to check -- may be null.
2929 ** e -- the current envelope.
2930 ** flags -- control some behavior, see RSF_ in sendmail.h
2931 ** logl -- logging level.
2932 ** host -- NULL or relay host.
2933 ** logid -- id for sm_syslog.
2936 ** EX_OK -- if the rwset doesn't resolve to $#error
2937 ** else -- the failure status (message printed)
2941 rscheck(rwset
, p1
, p2
, e
, flags
, logl
, host
, logid
)
2954 int volatile rstat
= EX_OK
;
2957 bool volatile discard
= false;
2959 bool saveQuickAbort
= QuickAbort
;
2960 bool saveSuprErrs
= SuprErrs
;
2961 bool quarantine
= false;
2962 char ubuf
[BUFSIZ
* 2];
2964 char pvpbuf
[PSBUFSIZE
];
2965 extern char MsgBuf
[];
2968 sm_dprintf("rscheck(%s, %s, %s)\n", rwset
, p1
,
2969 p2
== NULL
? "(NULL)" : p2
);
2971 rsno
= strtorwset(rwset
, NULL
, ST_FIND
);
2977 bufsize
= strlen(p1
) + strlen(p2
) + 2;
2978 if (bufsize
> sizeof buf0
)
2979 buf
= sm_malloc_x(bufsize
);
2983 bufsize
= sizeof buf0
;
2985 (void) sm_snprintf(buf
, bufsize
, "%s%c%s", p1
, CONDELSE
, p2
);
2989 bufsize
= strlen(p1
) + 1;
2990 if (bufsize
> sizeof buf0
)
2991 buf
= sm_malloc_x(bufsize
);
2995 bufsize
= sizeof buf0
;
2997 (void) sm_strlcpy(buf
, p1
, bufsize
);
3003 pvp
= prescan(buf
, '\0', pvpbuf
, sizeof pvpbuf
, NULL
,
3004 bitset(RSF_RMCOMM
, flags
) ? NULL
: TokTypeNoC
,
3005 bitset(RSF_RMCOMM
, flags
) ? false : true);
3006 SuprErrs
= saveSuprErrs
;
3010 sm_dprintf("rscheck: cannot prescan input\n");
3012 syserr("rscheck: cannot prescan input: \"%s\"",
3013 shortenstring(buf, MAXSHORTSTR));
3018 if (bitset(RSF_UNSTRUCTURED
, flags
))
3020 (void) REWRITE(pvp
, rsno
, e
);
3021 if (bitset(RSF_UNSTRUCTURED
, flags
))
3022 SuprErrs
= saveSuprErrs
;
3023 if (pvp
[0] == NULL
|| (pvp
[0][0] & 0377) != CANONNET
||
3024 pvp
[1] == NULL
|| (strcmp(pvp
[1], "error") != 0 &&
3025 strcmp(pvp
[1], "discard") != 0))
3030 if (strcmp(pvp
[1], "discard") == 0)
3033 sm_dprintf("rscheck: discard mailer selected\n");
3034 e
->e_flags
|= EF_DISCARD
;
3037 else if (strcmp(pvp
[1], "error") == 0 &&
3038 pvp
[2] != NULL
&& (pvp
[2][0] & 0377) == CANONHOST
&&
3039 pvp
[3] != NULL
&& strcmp(pvp
[3], "quarantine") == 0)
3041 if (pvp
[4] == NULL
||
3042 (pvp
[4][0] & 0377) != CANONUSER
||
3044 e
->e_quarmsg
= sm_rpool_strdup_x(e
->e_rpool
,
3048 cataddr(&(pvp
[5]), NULL
, ubuf
,
3050 e
->e_quarmsg
= sm_rpool_strdup_x(e
->e_rpool
,
3053 macdefine(&e
->e_macro
, A_PERM
,
3054 macid("{quarantine}"), e
->e_quarmsg
);
3059 int savelogusrerrs
= LogUsrErrs
;
3060 static bool logged
= false;
3062 /* got an error -- process it */
3063 saveexitstat
= ExitStat
;
3065 (void) buildaddr(pvp
, &a1
, 0, e
);
3066 LogUsrErrs
= savelogusrerrs
;
3068 ExitStat
= saveexitstat
;
3071 if (bitset(RSF_COUNT
, flags
))
3072 markstats(e
, &a1
, STATS_REJECT
);
3077 if (LogLevel
> logl
)
3086 (void) sm_snprintf(p
, SPACELEFT(lbuf
, p
),
3095 relay
= macvalue('_', e
);
3098 (void) sm_snprintf(p
, SPACELEFT(lbuf
, p
),
3099 ", relay=%s", relay
);
3104 sm_syslog(LOG_NOTICE
, logid
,
3105 "ruleset=%s, arg1=%s%s, discard",
3107 else if (quarantine
)
3108 sm_syslog(LOG_NOTICE
, logid
,
3109 "ruleset=%s, arg1=%s%s, quarantine=%s",
3110 rwset
, p1
, lbuf
, ubuf
);
3112 sm_syslog(LOG_NOTICE
, logid
,
3113 "ruleset=%s, arg1=%s%s, reject=%s",
3114 rwset
, p1
, lbuf
, MsgBuf
);
3124 QuickAbort
= saveQuickAbort
;
3130 /* rulesets don't set errno */
3132 if (rstat
!= EX_OK
&& QuickAbort
)
3133 sm_exc_raisenew_x(&EtypeQuickAbort
, 2);
3137 ** RSCAP -- call rewriting set to return capabilities
3140 ** rwset -- the rewriting set to use.
3141 ** p1 -- the first string to check.
3142 ** p2 -- the second string to check -- may be null.
3143 ** e -- the current envelope.
3144 ** pvp -- pointer to token vector.
3145 ** pvpbuf -- buffer space.
3146 ** size -- size of buffer space.
3149 ** EX_UNAVAILABLE -- ruleset doesn't exist.
3150 ** EX_DATAERR -- prescan() failed.
3151 ** EX_OK -- rewrite() was successful.
3152 ** else -- return status from rewrite().
3156 rscap(rwset
, p1
, p2
, e
, pvp
, pvpbuf
, size
)
3167 int volatile rstat
= EX_OK
;
3169 bool saveQuickAbort
= QuickAbort
;
3170 bool saveSuprErrs
= SuprErrs
;
3172 extern char MsgBuf
[];
3175 sm_dprintf("rscap(%s, %s, %s)\n", rwset
, p1
,
3176 p2
== NULL
? "(NULL)" : p2
);
3180 rsno
= strtorwset(rwset
, NULL
, ST_FIND
);
3182 return EX_UNAVAILABLE
;
3186 bufsize
= strlen(p1
) + strlen(p2
) + 2;
3187 if (bufsize
> sizeof buf0
)
3188 buf
= sm_malloc_x(bufsize
);
3192 bufsize
= sizeof buf0
;
3194 (void) sm_snprintf(buf
, bufsize
, "%s%c%s", p1
, CONDELSE
, p2
);
3198 bufsize
= strlen(p1
) + 1;
3199 if (bufsize
> sizeof buf0
)
3200 buf
= sm_malloc_x(bufsize
);
3204 bufsize
= sizeof buf0
;
3206 (void) sm_strlcpy(buf
, p1
, bufsize
);
3212 *pvp
= prescan(buf
, '\0', pvpbuf
, size
, NULL
, NULL
, false);
3214 rstat
= rewrite(*pvp
, rsno
, 0, e
, size
);
3218 sm_dprintf("rscap: cannot prescan input\n");
3227 SuprErrs
= saveSuprErrs
;
3228 QuickAbort
= saveQuickAbort
;
3230 /* prevent information leak, this may contain rewrite error */