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.
17 SM_RCSID("@(#)$Id: parseaddr.c,v 8.359.2.9 2003/09/16 18:07:50 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;
640 /* initialize the token type table */
644 if (OperatorChars
== NULL
)
647 OperatorChars
= macvalue('o', CurEnv
);
648 if (OperatorChars
== NULL
)
649 OperatorChars
= ".:@[]";
651 expand(OperatorChars
, obuf
, sizeof obuf
- sizeof DELIMCHARS
,
653 (void) sm_strlcat(obuf
, DELIMCHARS
, sizeof obuf
);
654 for (p
= obuf
; *p
!= '\0'; p
++)
656 if (TokTypeTab
[*p
& 0xff] == ATM
)
657 TokTypeTab
[*p
& 0xff] = OPR
;
658 if (TokTypeNoC
[*p
& 0xff] == ATM
)
659 TokTypeNoC
[*p
& 0xff] = OPR
;
665 /* make sure error messages don't have garbage on them */
670 route_syntax
= false;
680 sm_dprintf("prescan: ");
691 /* store away any old lookahead character */
692 if (c
!= NOCHAR
&& !bslashmode
)
694 /* see if there is room */
695 if (q
>= &pvpbuf
[pvpbsize
- 5])
698 usrerr("553 5.1.1 Address too long");
699 if (strlen(addr
) > MAXNAME
)
700 addr
[MAXNAME
] = '\0';
702 if (delimptr
!= NULL
)
708 CurEnv
->e_to
= saveto
;
712 /* squirrel it away */
714 if ((char) c
== (char) -1 && !tTd(82, 101))
716 #endif /* !ALLOW_255 */
720 /* read a new input character */
724 /* diagnose and patch up bad syntax */
727 usrerr("553 Unbalanced '\"'");
730 else if (cmntcnt
> 0)
732 usrerr("553 Unbalanced '('");
735 else if (anglecnt
> 0)
738 usrerr("553 Unbalanced '<'");
745 else if (c
== delim
&& cmntcnt
<= 0 && state
!= QST
)
750 /* special case for better error management */
751 if (delim
== ',' && !route_syntax
)
753 usrerr("553 Unbalanced '<'");
760 sm_dprintf("c=%c, s=%d; ", c
, state
);
762 /* chew up special characters */
768 /* kludge \! for naive users */
774 else if (c
!= '!' || state
== QST
)
776 /* see if there is room */
777 if (q
>= &pvpbuf
[pvpbsize
- 5])
788 else if (state
== QST
)
791 /* do nothing, just avoid next clauses */
793 else if (c
== '(' && toktab
['('] == SPC
)
798 else if (c
== ')' && toktab
['('] == SPC
)
802 usrerr("553 Unbalanced ')'");
808 else if (cmntcnt
> 0)
817 while (isascii(*ptr
) && isspace(*ptr
))
826 usrerr("553 Unbalanced '>'");
831 route_syntax
= false;
833 else if (delim
== ' ' && isascii(c
) && isspace(c
))
839 /* see if this is end of input */
840 if (c
== delim
&& anglecnt
<= 0 && state
!= QST
)
843 newstate
= StateTab
[state
][toktab
[c
& 0xff]];
845 sm_dprintf("ns=%02o\n", newstate
);
846 state
= newstate
& TYPE
;
849 if (isascii(c
) && isprint(c
))
850 usrerr("553 Illegal character %c", c
);
852 usrerr("553 Illegal character 0x%02x",
855 if (bitset(M
, newstate
))
857 if (bitset(B
, newstate
))
864 /* see if there is room */
865 if (q
>= &pvpbuf
[pvpbsize
- 5])
874 if (avp
>= &av
[MAXATOM
])
876 usrerr("553 5.1.0 prescan: too many tokens");
879 if (q
- tok
> MAXNAME
)
881 usrerr("553 5.1.0 prescan: token too long");
886 } while (c
!= '\0' && (c
!= delim
|| anglecnt
> 0));
888 if (delimptr
!= NULL
)
896 sm_dprintf("prescan==>");
899 CurEnv
->e_to
= saveto
;
903 sm_dprintf("prescan: null leading token\n");
909 ** REWRITE -- apply rewrite rules to token vector.
911 ** This routine is an ordered production system. Each rewrite
912 ** rule has a LHS (called the pattern) and a RHS (called the
913 ** rewrite); 'rwr' points the the current rewrite rule.
915 ** For each rewrite rule, 'avp' points the address vector we
916 ** are trying to match against, and 'pvp' points to the pattern.
917 ** If pvp points to a special match value (MATCHZANY, MATCHANY,
918 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
919 ** matched is saved away in the match vector (pointed to by 'mvp').
921 ** When a match between avp & pvp does not match, we try to
922 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
923 ** we must also back out the match in mvp. If we reach a
924 ** MATCHANY or MATCHZANY we just extend the match and start
927 ** When we finally match, we rewrite the address vector
928 ** and try over again.
931 ** pvp -- pointer to token vector.
932 ** ruleset -- the ruleset to use for rewriting.
933 ** reclevel -- recursion level (to catch loops).
934 ** e -- the current envelope.
935 ** maxatom -- maximum length of buffer (usually MAXATOM)
938 ** A status code. If EX_TEMPFAIL, higher level code should
947 char **match_first
; /* first token matched */
948 char **match_last
; /* last token matched */
949 char **match_pattern
; /* pointer to pattern */
953 rewrite(pvp
, ruleset
, reclevel
, e
, maxatom
)
957 register ENVELOPE
*e
;
960 register char *ap
; /* address pointer */
961 register char *rp
; /* rewrite pointer */
962 register char *rulename
; /* ruleset name */
963 register char *prefix
;
964 register char **avp
; /* address vector pointer */
965 register char **rvp
; /* rewrite vector pointer */
966 register struct match
*mlp
; /* cur ptr into mlist */
967 register struct rewrite
*rwr
; /* pointer to current rewrite rule */
968 int ruleno
; /* current rule number */
969 int rstat
= EX_OK
; /* return status */
971 struct match mlist
[MAXMATCH
]; /* stores match on LHS */
972 char *npvp
[MAXATOM
+ 1]; /* temporary space for rebuild */
977 ** mlp will not exceed mlist[] because readcf enforces
978 ** the upper limit of entries when reading rulesets.
981 if (ruleset
< 0 || ruleset
>= MAXRWSETS
)
983 syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset
);
986 rulename
= RuleSetNames
[ruleset
];
987 if (rulename
== NULL
)
989 (void) sm_snprintf(name
, sizeof name
, "%d", ruleset
);
992 if (OpMode
== MD_TEST
)
995 prefix
= "rewrite: ruleset ";
996 if (OpMode
== MD_TEST
)
998 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
999 "%s%-16.16s input:", prefix
, rulename
);
1002 else if (tTd(21, 1))
1004 sm_dprintf("%s%-16.16s input:", prefix
, rulename
);
1007 if (reclevel
++ > MaxRuleRecursion
)
1009 syserr("rewrite: excessive recursion (max %d), ruleset %s",
1010 MaxRuleRecursion
, rulename
);
1019 ** Run through the list of rewrite rules, applying
1025 for (rwr
= RewriteRules
[ruleset
]; rwr
!= NULL
; )
1029 /* if already canonical, quit now */
1030 if (pvp
[0] != NULL
&& (pvp
[0][0] & 0377) == CANONNET
)
1036 sm_dprintf("-----trying rule (line %d):",
1039 sm_dprintf("-----trying rule:");
1040 printav(rwr
->r_lhs
);
1043 /* try to match on this rule */
1047 if (++loopcount
> 100)
1049 syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
1053 sm_dprintf("workspace: ");
1059 while ((ap
= *avp
) != NULL
|| *rvp
!= NULL
)
1064 sm_dprintf("ADVANCE rp=");
1066 sm_dprintf(", ap=");
1072 /* end-of-pattern before end-of-address */
1075 if (ap
== NULL
&& (*rp
& 0377) != MATCHZANY
&&
1076 (*rp
& 0377) != MATCHZERO
)
1078 /* end-of-input with patterns left */
1085 /* match any phrase in a class */
1086 mlp
->match_pattern
= rvp
;
1087 mlp
->match_first
= avp
;
1092 mlp
->match_last
= avp
++;
1093 cataddr(mlp
->match_first
, mlp
->match_last
,
1094 buf
, sizeof buf
, '\0');
1095 if (!wordinclass(buf
, rp
[1]))
1099 sm_dprintf("EXTEND rp=");
1101 sm_dprintf(", ap=");
1108 sm_dprintf("CLMATCH\n");
1113 /* match any token not in a class */
1114 if (wordinclass(ap
, rp
[1]))
1121 /* match exactly one token */
1122 mlp
->match_pattern
= rvp
;
1123 mlp
->match_first
= avp
;
1124 mlp
->match_last
= avp
++;
1129 /* match zero or more tokens */
1130 mlp
->match_pattern
= rvp
;
1131 mlp
->match_first
= avp
;
1132 mlp
->match_last
= avp
- 1;
1137 /* match zero tokens */
1142 ** Match against run-time macro.
1143 ** This algorithm is broken for the
1144 ** general case (no recursive macros,
1145 ** improper tokenization) but should
1146 ** work for the usual cases.
1149 ap
= macvalue(rp
[1], e
);
1150 mlp
->match_first
= avp
;
1152 sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n",
1154 ap
== NULL
? "(NULL)" : ap
);
1161 sm_strncasecmp(ap
, *avp
,
1165 avp
= mlp
->match_first
;
1168 ap
+= strlen(*avp
++);
1175 /* must have exact match */
1176 if (sm_strcasecmp(rp
, ap
))
1182 /* successful match on this token */
1187 /* match failed -- back up */
1188 while (--mlp
>= mlist
)
1190 rvp
= mlp
->match_pattern
;
1192 avp
= mlp
->match_last
+ 1;
1197 sm_dprintf("BACKUP rp=");
1199 sm_dprintf(", ap=");
1206 /* run off the end -- back up again */
1209 if ((*rp
& 0377) == MATCHANY
||
1210 (*rp
& 0377) == MATCHZANY
)
1212 /* extend binding and continue */
1213 mlp
->match_last
= avp
++;
1218 if ((*rp
& 0377) == MATCHCLASS
)
1220 /* extend binding and try again */
1221 mlp
->match_last
= avp
;
1228 /* total failure to match */
1234 ** See if we successfully matched
1237 if (mlp
< mlist
|| *rvp
!= NULL
)
1240 sm_dprintf("----- rule fails\n");
1250 sm_dprintf("-----rule matches:");
1257 if ((*rp
& 0377) == CANONUSER
)
1264 else if ((*rp
& 0377) == CANONHOST
)
1272 for (avp
= npvp
; *rvp
!= NULL
; rvp
++)
1274 register struct match
*m
;
1278 if ((*rp
& 0377) == MATCHREPL
)
1280 /* substitute from LHS */
1281 m
= &mlist
[rp
[1] - '1'];
1282 if (m
< mlist
|| m
>= mlp
)
1284 syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
1290 sm_dprintf("$%c:", rp
[1]);
1291 pp
= m
->match_first
;
1292 while (pp
<= m
->match_last
)
1294 sm_dprintf(" %p=\"", *pp
);
1296 sm_dprintf("%s\"", *pp
++);
1300 pp
= m
->match_first
;
1301 while (pp
<= m
->match_last
)
1303 if (avp
>= &npvp
[maxatom
])
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];
1411 char *argvect
[MAX_MAP_ARGS
];
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
;
1435 if (mapname
== NULL
)
1436 syserr("554 5.3.0 rewrite: missing mapname");
1438 map
= stab(mapname
, ST_MAP
, ST_FIND
);
1440 syserr("554 5.3.0 rewrite: map %s not found",
1443 /* extract the match part */
1445 if (key_rvp
== NULL
)
1446 syserr("554 5.3.0 rewrite: missing key for map %s",
1452 while (*rvp
!= NULL
&& (**rvp
& 0377) != endtoken
)
1454 int nodetype
= **rvp
& 0377;
1456 if (nodetype
!= CANONHOST
&&
1457 nodetype
!= CANONUSER
)
1467 cataddr(xpvp
, NULL
, replac
,
1468 &pvpbuf
[sizeof pvpbuf
] - replac
,
1471 &argvect
[MAX_MAP_ARGS
- 1])
1472 *++arg_rvp
= replac
;
1473 replac
+= strlen(replac
) + 1;
1491 cataddr(xpvp
, NULL
, replac
,
1492 &pvpbuf
[sizeof pvpbuf
] - replac
,
1494 if (arg_rvp
< &argvect
[MAX_MAP_ARGS
- 1])
1495 *++arg_rvp
= replac
;
1497 if (arg_rvp
>= &argvect
[MAX_MAP_ARGS
- 1])
1498 argvect
[MAX_MAP_ARGS
- 1] = NULL
;
1502 /* save the remainder of the input string */
1503 trsize
= (int) (avp
- rvp
+ 1) * sizeof *rvp
;
1504 memmove((char *) pvpb1
, (char *) rvp
, trsize
);
1507 cataddr(key_rvp
, NULL
, cbuf
, sizeof cbuf
,
1508 map
== NULL
? '\0' : map
->s_map
.map_spacesub
);
1510 replac
= map_lookup(map
, cbuf
, argvect
, &rstat
, e
);
1512 /* if no replacement, use default */
1513 if (replac
== NULL
&& default_rvp
!= NULL
)
1515 /* create the default */
1516 cataddr(default_rvp
, NULL
, cbuf
, sizeof cbuf
, '\0');
1524 else if (*replac
== '\0')
1526 /* null replacement */
1532 /* scan the new replacement */
1533 xpvp
= prescan(replac
, '\0', pvpbuf
,
1534 sizeof pvpbuf
, NULL
, NULL
);
1537 /* prescan already printed error */
1542 /* append it to the token list */
1543 for (avp
= hbrvp
; *xpvp
!= NULL
; xpvp
++)
1545 *avp
++ = sm_rpool_strdup_x(e
->e_rpool
, *xpvp
);
1546 if (avp
>= &npvp
[maxatom
])
1550 /* restore the old trailing information */
1552 for (xpvp
= pvpb1
; (*avp
++ = *xpvp
++) != NULL
; )
1553 if (avp
>= &npvp
[maxatom
])
1558 ** Check for subroutine calls.
1561 status
= callsubr(npvp
, reclevel
, e
);
1562 if (rstat
== EX_OK
|| status
== EX_TEMPFAIL
)
1565 /* copy vector back into original space. */
1566 for (avp
= npvp
; *avp
++ != NULL
;)
1568 memmove((char *) pvp
, (char *) npvp
,
1569 (int) (avp
- npvp
) * sizeof *avp
);
1573 sm_dprintf("rewritten as:");
1578 if (OpMode
== MD_TEST
)
1580 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
1581 "%s%-16.16s returns:", prefix
, rulename
);
1584 else if (tTd(21, 1))
1586 sm_dprintf("%s%-16.16s returns:", prefix
, rulename
);
1592 ** CALLSUBR -- call subroutines in rewrite vector
1595 ** pvp -- pointer to token vector.
1596 ** reclevel -- the current recursion level.
1597 ** e -- the current envelope.
1600 ** The status from the subroutine call.
1607 callsubr(pvp
, reclevel
, e
)
1619 int subrnumber
[MAX_SUBR
];
1620 int subrindex
[MAX_SUBR
];
1625 ** Look for subroutine calls in pvp, collect them into subr*[]
1626 ** We will perform the calls in the next loop, because we will
1627 ** call the "last" subroutine first to avoid recursive calls
1628 ** and too much copying.
1631 for (avp
= pvp
, j
= 0; *avp
!= NULL
; avp
++, j
++)
1633 if ((**avp
& 0377) == CALLSUBR
&& avp
[1] != NULL
)
1635 stripquotes(avp
[1]);
1636 subr
= strtorwset(avp
[1], NULL
, ST_FIND
);
1639 syserr("554 5.3.5 Unknown ruleset %s", avp
[1]);
1644 ** XXX instead of doing this we could optimize
1645 ** the rules after reading them: just remove
1646 ** calls to empty rulesets
1649 /* subroutine is an empty ruleset? don't call it */
1650 if (RewriteRules
[subr
] == NULL
)
1653 sm_dprintf("-----skip subr %s (%d)\n",
1655 for (i
= 2; avp
[i
] != NULL
; i
++)
1656 avp
[i
- 2] = avp
[i
];
1660 if (++nsubr
>= MAX_SUBR
)
1662 syserr("554 5.3.0 Too many subroutine calls (%d max)",
1666 subrnumber
[nsubr
] = subr
;
1667 subrindex
[nsubr
] = j
;
1672 ** Perform the actual subroutines calls, "last" one first, i.e.,
1673 ** go from the right to the left through all calls,
1674 ** do the rewriting in place.
1677 for (; nsubr
> 0; nsubr
--)
1679 subr
= subrnumber
[nsubr
];
1680 avp
= pvp
+ subrindex
[nsubr
];
1682 /* remove the subroutine call and name */
1683 for (i
= 2; avp
[i
] != NULL
; i
++)
1684 avp
[i
- 2] = avp
[i
];
1688 ** Now we need to call the ruleset specified for
1689 ** the subroutine. We can do this in place since
1690 ** we call the "last" subroutine first.
1693 status
= rewrite(avp
, subr
, reclevel
, e
,
1694 MAXATOM
- subrindex
[nsubr
]);
1695 if (status
!= EX_OK
&& status
!= EX_TEMPFAIL
)
1697 if (rstat
== EX_OK
|| status
== EX_TEMPFAIL
)
1703 ** MAP_LOOKUP -- do lookup in map
1706 ** smap -- the map to use for the lookup.
1707 ** key -- the key to look up.
1708 ** argvect -- arguments to pass to the map lookup.
1709 ** pstat -- a pointer to an integer in which to store the
1710 ** status from the lookup.
1711 ** e -- the current envelope.
1714 ** The result of the lookup.
1715 ** NULL -- if there was no data for the given key.
1719 map_lookup(smap
, key
, argvect
, pstat
, e
)
1726 auto int status
= EX_OK
;
1736 if (e
->e_sendmode
== SM_DEFER
&&
1737 bitset(MF_DEFER
, map
->map_mflags
))
1739 /* don't do any map lookups */
1741 sm_dprintf("map_lookup(%s, %s) => DEFERRED\n",
1743 *pstat
= EX_TEMPFAIL
;
1747 if (!bitset(MF_KEEPQUOTES
, map
->map_mflags
))
1752 sm_dprintf("map_lookup(%s, %s", smap
->s_name
, key
);
1757 for (i
= 0; argvect
[i
] != NULL
; i
++)
1758 sm_dprintf(", %%%d=%s", i
, argvect
[i
]);
1760 sm_dprintf(") => ");
1762 replac
= (*map
->map_class
->map_lookup
)(map
, key
, argvect
, &status
);
1764 sm_dprintf("%s (%d)\n",
1765 replac
!= NULL
? replac
: "NOT FOUND",
1768 /* should recover if status == EX_TEMPFAIL */
1769 if (status
== EX_TEMPFAIL
&& !bitset(MF_NODEFER
, map
->map_mflags
))
1771 *pstat
= EX_TEMPFAIL
;
1773 sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
1774 smap
->s_name
, key
, errno
);
1775 if (e
->e_message
== NULL
)
1779 (void) sm_snprintf(mbuf
, sizeof mbuf
,
1780 "%.80s map: lookup (%s): deferred",
1782 shortenstring(key
, MAXSHORTSTR
));
1783 e
->e_message
= sm_rpool_strdup_x(e
->e_rpool
, mbuf
);
1786 if (status
== EX_TEMPFAIL
&& map
->map_tapp
!= NULL
)
1788 size_t i
= strlen(key
) + strlen(map
->map_tapp
) + 1;
1789 static char *rwbuf
= NULL
;
1790 static size_t rwbuflen
= 0;
1797 rwbuf
= (char *) sm_pmalloc_x(rwbuflen
);
1799 (void) sm_strlcpyn(rwbuf
, rwbuflen
, 2, key
, map
->map_tapp
);
1801 sm_dprintf("map_lookup tempfail: returning \"%s\"\n",
1808 ** INITERRMAILERS -- initialize error and discard mailers
1817 ** initializes error and discard mailers.
1820 static MAILER discardmailer
;
1821 static MAILER errormailer
;
1822 static char *discardargv
[] = { "DISCARD", NULL
};
1823 static char *errorargv
[] = { "ERROR", NULL
};
1828 if (discardmailer
.m_name
== NULL
)
1830 /* initialize the discard mailer */
1831 discardmailer
.m_name
= "*discard*";
1832 discardmailer
.m_mailer
= "DISCARD";
1833 discardmailer
.m_argv
= discardargv
;
1835 if (errormailer
.m_name
== NULL
)
1837 /* initialize the bogus mailer */
1838 errormailer
.m_name
= "*error*";
1839 errormailer
.m_mailer
= "ERROR";
1840 errormailer
.m_argv
= errorargv
;
1844 ** BUILDADDR -- build address from token vector.
1847 ** tv -- token vector.
1848 ** a -- pointer to address descriptor to fill.
1849 ** If NULL, one will be allocated.
1850 ** flags -- info regarding whether this is a sender or
1852 ** e -- the current envelope.
1855 ** NULL if there was an error.
1862 static struct errcodes
1864 char *ec_name
; /* name of error code */
1865 int ec_code
; /* numeric code */
1868 { "usage", EX_USAGE
},
1869 { "nouser", EX_NOUSER
},
1870 { "nohost", EX_NOHOST
},
1871 { "unavailable", EX_UNAVAILABLE
},
1872 { "software", EX_SOFTWARE
},
1873 { "tempfail", EX_TEMPFAIL
},
1874 { "protocol", EX_PROTOCOL
},
1875 { "config", EX_CONFIG
},
1876 { NULL
, EX_UNAVAILABLE
}
1880 buildaddr(tv
, a
, flags
, e
)
1882 register ADDRESS
*a
;
1884 register ENVELOPE
*e
;
1886 bool tempfail
= false;
1889 register struct mailer
*m
;
1893 char hbuf
[MAXNAME
+ 1];
1894 static char ubuf
[MAXNAME
+ 2];
1898 sm_dprintf("buildaddr, flags=%x, tv=", flags
);
1904 a
= (ADDRESS
*) sm_rpool_malloc_x(e
->e_rpool
, sizeof *a
);
1905 memset((char *) a
, '\0', sizeof *a
);
1908 /* set up default error return flags */
1909 a
->q_flags
|= DefaultNotify
;
1911 /* figure out what net/mailer to use */
1912 if (*tv
== NULL
|| (**tv
& 0377) != CANONNET
)
1914 syserr("554 5.3.5 buildaddr: no mailer in parsed address");
1916 #if _FFR_ALLOW_S0_ERROR_4XX
1918 ** ExitStat may have been set by an earlier map open
1919 ** failure (to a permanent error (EX_OSERR) in syserr())
1920 ** so we also need to check if this particular $#error
1921 ** return wanted a 4XX failure.
1923 ** XXX the real fix is probably to set ExitStat correctly,
1924 ** i.e., to EX_TEMPFAIL if the map open is just a temporary
1927 ** tempfail is tested here even if _FFR_ALLOW_S0_ERROR_4XX
1928 ** is not set; that's ok because it is initialized to false.
1930 #endif /* _FFR_ALLOW_S0_ERROR_4XX */
1932 if (ExitStat
== EX_TEMPFAIL
|| tempfail
)
1933 a
->q_state
= QS_QUEUEUP
;
1936 a
->q_state
= QS_BADADDR
;
1937 a
->q_mailer
= &errormailer
;
1944 /* extract host and user portions */
1945 if (*++tv
!= NULL
&& (**tv
& 0377) == CANONHOST
)
1953 while (*tv
!= NULL
&& (**tv
& 0377) != CANONUSER
)
1960 syserr("554 5.3.5 buildaddr: no user");
1965 else if (hostp
!= NULL
)
1966 cataddr(hostp
, tv
- 1, hbuf
, sizeof hbuf
, '\0');
1967 cataddr(++tv
, NULL
, ubuf
, sizeof ubuf
, ' ');
1970 /* save away the host name */
1971 if (sm_strcasecmp(mname
, "error") == 0)
1973 /* Set up triplet for use by -bv */
1974 a
->q_mailer
= &errormailer
;
1975 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, ubuf
);
1976 /* XXX wrong place? */
1980 register struct errcodes
*ep
;
1982 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, hbuf
);
1983 if (strchr(hbuf
, '.') != NULL
)
1985 a
->q_status
= sm_rpool_strdup_x(e
->e_rpool
,
1987 setstat(dsntoexitstat(hbuf
));
1989 else if (isascii(hbuf
[0]) && isdigit(hbuf
[0]))
1991 setstat(atoi(hbuf
));
1995 for (ep
= ErrorCodes
; ep
->ec_name
!= NULL
; ep
++)
1996 if (sm_strcasecmp(ep
->ec_name
, hbuf
) == 0)
1998 setstat(ep
->ec_code
);
2004 setstat(EX_UNAVAILABLE
);
2007 if (ISSMTPCODE(ubuf
) && ubuf
[3] == ' ')
2012 if ((off
= isenhsc(ubuf
+ 4, ' ')) > 0)
2014 ubuf
[off
+ 4] = '\0';
2022 (void) sm_strlcpyn(fmt
, sizeof fmt
, 2, ubuf
, " %s");
2024 usrerr(fmt
, ubuf
+ off
);
2025 else if (isenhsc(hbuf
, '\0') > 0)
2026 usrerrenh(hbuf
, fmt
, ubuf
+ off
);
2028 usrerr(fmt
, ubuf
+ off
);
2029 /* XXX ubuf[off - 1] = ' '; */
2030 #if _FFR_ALLOW_S0_ERROR_4XX
2033 #endif /* _FFR_ALLOW_S0_ERROR_4XX */
2037 usrerr("553 5.3.0 %s", ubuf
);
2042 for (mp
= Mailer
; (m
= *mp
++) != NULL
; )
2044 if (sm_strcasecmp(m
->m_name
, mname
) == 0)
2049 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname
);
2054 /* figure out what host (if any) */
2057 if (!bitnset(M_LOCALMAILER
, m
->m_flags
))
2059 syserr("554 5.3.5 buildaddr: no host");
2065 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, hbuf
);
2067 /* figure out the user */
2069 if (bitnset(M_CHECKUDB
, m
->m_flags
) && *p
== '@')
2074 a
->q_flags
|= QNOTREMOTE
;
2077 /* do special mapping for local mailer */
2080 if (*p
== '|' && bitnset(M_CHECKPROG
, m
->m_flags
))
2081 a
->q_mailer
= m
= ProgMailer
;
2082 else if (*p
== '/' && bitnset(M_CHECKFILE
, m
->m_flags
))
2083 a
->q_mailer
= m
= FileMailer
;
2084 else if (*p
== ':' && bitnset(M_CHECKINCLUDE
, m
->m_flags
))
2086 /* may be :include: */
2088 if (sm_strncasecmp(ubuf
, ":include:", 9) == 0)
2090 /* if :include:, don't need further rewriting */
2091 a
->q_mailer
= m
= InclMailer
;
2092 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, &ubuf
[9]);
2097 /* rewrite according recipient mailer rewriting rules */
2098 macdefine(&e
->e_macro
, A_PERM
, 'h', a
->q_host
);
2100 if (ConfigLevel
>= 10 ||
2101 !bitset(RF_SENDERADDR
|RF_HEADERADDR
, flags
))
2103 /* sender addresses done later */
2104 (void) rewrite(tv
, 2, 0, e
, maxatom
);
2105 if (m
->m_re_rwset
> 0)
2106 (void) rewrite(tv
, m
->m_re_rwset
, 0, e
, maxatom
);
2108 (void) rewrite(tv
, 4, 0, e
, maxatom
);
2110 /* save the result for the command line/RCPT argument */
2111 cataddr(tv
, NULL
, ubuf
, sizeof ubuf
, '\0');
2112 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, ubuf
);
2115 ** Do mapping to lower case as requested by mailer
2118 if (a
->q_host
!= NULL
&& !bitnset(M_HST_UPPER
, m
->m_flags
))
2119 makelower(a
->q_host
);
2120 if (!bitnset(M_USR_UPPER
, m
->m_flags
))
2121 makelower(a
->q_user
);
2125 sm_dprintf("buildaddr => ");
2126 printaddr(a
, false);
2132 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
2135 ** pvp -- parameter vector to rebuild.
2136 ** evp -- last parameter to include. Can be NULL to
2138 ** buf -- buffer to build the string into.
2139 ** sz -- size of buf.
2140 ** spacesub -- the space separator character; if '\0',
2151 cataddr(pvp
, evp
, buf
, sz
, spacesub
)
2158 bool oatomtok
= false;
2159 bool natomtok
= false;
2166 if (spacesub
== '\0')
2167 spacesub
= SpaceSub
;
2176 while (*pvp
!= NULL
&& sz
> 0)
2178 natomtok
= (TokTypeTab
[**pvp
& 0xff] == ATM
);
2179 if (oatomtok
&& natomtok
)
2185 if ((i
= sm_strlcpy(p
, *pvp
, sz
)) >= sz
)
2187 oatomtok
= natomtok
;
2193 #if _FFR_CATCH_LONG_STRINGS
2194 /* Don't silently truncate long strings; broken for evp != NULL */
2196 syserr("cataddr: string too long");
2197 #endif /* _FFR_CATCH_LONG_STRINGS */
2201 ** SAMEADDR -- Determine if two addresses are the same
2203 ** This is not just a straight comparison -- if the mailer doesn't
2204 ** care about the host we just ignore it, etc.
2207 ** a, b -- pointers to the internal forms to compare.
2210 ** true -- they represent the same mailbox.
2211 ** false -- they don't.
2219 register ADDRESS
*a
;
2220 register ADDRESS
*b
;
2222 register ADDRESS
*ca
, *cb
;
2224 /* if they don't have the same mailer, forget it */
2225 if (a
->q_mailer
!= b
->q_mailer
)
2228 /* if the user isn't the same, we can drop out */
2229 if (strcmp(a
->q_user
, b
->q_user
) != 0)
2232 /* if we have good uids for both but they differ, these are different */
2233 if (a
->q_mailer
== ProgMailer
)
2237 if (ca
!= NULL
&& cb
!= NULL
&&
2238 bitset(QGOODUID
, ca
->q_flags
& cb
->q_flags
) &&
2239 ca
->q_uid
!= cb
->q_uid
)
2243 /* otherwise compare hosts (but be careful for NULL ptrs) */
2244 if (a
->q_host
== b
->q_host
)
2246 /* probably both null pointers */
2249 if (a
->q_host
== NULL
|| b
->q_host
== NULL
)
2251 /* only one is a null pointer */
2254 if (strcmp(a
->q_host
, b
->q_host
) != 0)
2260 ** PRINTADDR -- print address (for debugging)
2263 ** a -- the address to print
2264 ** follow -- follow the q_next chain.
2276 unsigned long qf_bit
;
2279 static struct qflags AddressFlags
[] =
2281 { "QGOODUID", QGOODUID
},
2282 { "QPRIMARY", QPRIMARY
},
2283 { "QNOTREMOTE", QNOTREMOTE
},
2284 { "QSELFREF", QSELFREF
},
2285 { "QBOGUSSHELL", QBOGUSSHELL
},
2286 { "QUNSAFEADDR", QUNSAFEADDR
},
2287 { "QPINGONSUCCESS", QPINGONSUCCESS
},
2288 { "QPINGONFAILURE", QPINGONFAILURE
},
2289 { "QPINGONDELAY", QPINGONDELAY
},
2290 { "QHASNOTIFY", QHASNOTIFY
},
2291 { "QRELAYED", QRELAYED
},
2292 { "QEXPANDED", QEXPANDED
},
2293 { "QDELIVERED", QDELIVERED
},
2294 { "QDELAYED", QDELAYED
},
2295 { "QTHISPASS", QTHISPASS
},
2296 { "QRCPTOK", QRCPTOK
},
2301 printaddr(a
, follow
)
2302 register ADDRESS
*a
;
2306 MAILER pseudomailer
;
2307 register struct qflags
*qfp
;
2312 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "[NULL]\n");
2318 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "%p=", a
);
2319 (void) sm_io_flush(smioout
, SM_TIME_DEFAULT
);
2321 /* find the mailer -- carefully */
2330 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2331 "%s:\n\tmailer %d (%s), host `%s'\n",
2332 a
->q_paddr
== NULL
? "<null>" : a
->q_paddr
,
2333 m
->m_mno
, m
->m_name
,
2334 a
->q_host
== NULL
? "<null>" : a
->q_host
);
2335 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2336 "\tuser `%s', ruser `%s'\n",
2338 a
->q_ruser
== NULL
? "<null>" : a
->q_ruser
);
2339 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "\tstate=");
2343 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "OK");
2347 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2352 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2357 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2362 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "RETRY");
2366 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "SENT");
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
,
2395 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2400 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2405 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2410 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2415 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2419 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2420 ", next=%p, alias %p, uid %d, gid %d\n",
2421 a
->q_next
, a
->q_alias
,
2422 (int) a
->q_uid
, (int) a
->q_gid
);
2423 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "\tflags=%lx<",
2426 for (qfp
= AddressFlags
; qfp
->qf_name
!= NULL
; qfp
++)
2428 if (!bitset(qfp
->qf_bit
, a
->q_flags
))
2431 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2434 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, "%s",
2437 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
, ">\n");
2438 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2439 "\towner=%s, home=\"%s\", fullname=\"%s\"\n",
2440 a
->q_owner
== NULL
? "(none)" : a
->q_owner
,
2441 a
->q_home
== NULL
? "(none)" : a
->q_home
,
2442 a
->q_fullname
== NULL
? "(none)" : a
->q_fullname
);
2443 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2444 "\torcpt=\"%s\", statmta=%s, status=%s\n",
2445 a
->q_orcpt
== NULL
? "(none)" : a
->q_orcpt
,
2446 a
->q_statmta
== NULL
? "(none)" : a
->q_statmta
,
2447 a
->q_status
== NULL
? "(none)" : a
->q_status
);
2448 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2449 "\tfinalrcpt=\"%s\"\n",
2450 a
->q_finalrcpt
== NULL
? "(none)" : a
->q_finalrcpt
);
2451 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2452 "\trstatus=\"%s\"\n",
2453 a
->q_rstatus
== NULL
? "(none)" : a
->q_rstatus
);
2454 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
2456 a
->q_statdate
== 0 ? "(none)" : ctime(&a
->q_statdate
));
2464 ** EMPTYADDR -- return true if this address is empty (``<>'')
2467 ** a -- pointer to the address
2470 ** true -- if this address is "empty" (i.e., no one should
2471 ** ever generate replies to it.
2472 ** false -- if it is a "regular" (read: replyable) address.
2477 register ADDRESS
*a
;
2479 return a
->q_paddr
== NULL
|| strcmp(a
->q_paddr
, "<>") == 0 ||
2480 a
->q_user
== NULL
|| strcmp(a
->q_user
, "<>") == 0;
2483 ** REMOTENAME -- return the name relative to the current mailer
2486 ** name -- the name to translate.
2487 ** m -- the mailer that we want to do rewriting relative to.
2488 ** flags -- fine tune operations.
2489 ** pstat -- pointer to status word.
2490 ** e -- the current envelope.
2493 ** the text string representing this address relative to
2494 ** the receiving mailer.
2500 ** The text string returned is tucked away locally;
2501 ** copy it if you intend to save it.
2505 remotename(name
, m
, flags
, pstat
, e
)
2510 register ENVELOPE
*e
;
2512 register char **pvp
;
2513 char *SM_NONVOLATILE fancy
;
2516 static char buf
[MAXNAME
+ 1];
2517 char lbuf
[MAXNAME
+ 1];
2518 char pvpbuf
[PSBUFSIZE
];
2522 sm_dprintf("remotename(%s)\n", name
);
2524 /* don't do anything if we are tagging it as special */
2525 if (bitset(RF_SENDERADDR
, flags
))
2527 rwset
= bitset(RF_HEADERADDR
, flags
) ? m
->m_sh_rwset
2533 rwset
= bitset(RF_HEADERADDR
, flags
) ? m
->m_rh_rwset
2541 addrtype
[0] = bitset(RF_HEADERADDR
, flags
) ? 'h' : 'e';
2542 macdefine(&e
->e_macro
, A_TEMP
, macid("{addr_type}"), addrtype
);
2545 ** Do a heuristic crack of this name to extract any comment info.
2546 ** This will leave the name as a comment and a $g macro.
2549 if (bitset(RF_CANONICAL
, flags
) || bitnset(M_NOCOMMENT
, m
->m_flags
))
2552 fancy
= crackaddr(name
, e
);
2555 ** Turn the name into canonical form.
2556 ** Normally this will be RFC 822 style, i.e., "user@domain".
2557 ** If this only resolves to "user", and the "C" flag is
2558 ** specified in the sending mailer, then the sender's
2559 ** domain will be appended.
2562 pvp
= prescan(name
, '\0', pvpbuf
, sizeof pvpbuf
, NULL
, NULL
);
2565 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
2566 *pstat
= EX_TEMPFAIL
;
2567 if (bitset(RF_ADDDOMAIN
, flags
) && e
->e_fromdomain
!= NULL
)
2569 /* append from domain to this address */
2570 register char **pxp
= pvp
;
2571 int l
= MAXATOM
; /* size of buffer for pvp */
2573 /* see if there is an "@domain" in the current name */
2574 while (*pxp
!= NULL
&& strcmp(*pxp
, "@") != 0)
2581 /* no.... append the "@domain" from the sender */
2582 register char **qxq
= e
->e_fromdomain
;
2584 while ((*pxp
++ = *qxq
++) != NULL
)
2589 usrerr("553 5.1.0 remotename: too many tokens");
2590 *pstat
= EX_UNAVAILABLE
;
2594 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
2595 *pstat
= EX_TEMPFAIL
;
2600 ** Do more specific rewriting.
2601 ** Rewrite using ruleset 1 or 2 depending on whether this is
2602 ** a sender address or not.
2603 ** Then run it through any receiving-mailer-specific rulesets.
2606 if (bitset(RF_SENDERADDR
, flags
))
2608 if (REWRITE(pvp
, 1, e
) == EX_TEMPFAIL
)
2609 *pstat
= EX_TEMPFAIL
;
2613 if (REWRITE(pvp
, 2, e
) == EX_TEMPFAIL
)
2614 *pstat
= EX_TEMPFAIL
;
2618 if (REWRITE(pvp
, rwset
, e
) == EX_TEMPFAIL
)
2619 *pstat
= EX_TEMPFAIL
;
2623 ** Do any final sanitation the address may require.
2624 ** This will normally be used to turn internal forms
2625 ** (e.g., user@host.LOCAL) into external form. This
2626 ** may be used as a default to the above rules.
2629 if (REWRITE(pvp
, 4, e
) == EX_TEMPFAIL
)
2630 *pstat
= EX_TEMPFAIL
;
2633 ** Now restore the comment information we had at the beginning.
2636 cataddr(pvp
, NULL
, lbuf
, sizeof lbuf
, '\0');
2637 oldg
= macget(&e
->e_macro
, 'g');
2638 macset(&e
->e_macro
, 'g', lbuf
);
2641 /* need to make sure route-addrs have <angle brackets> */
2642 if (bitset(RF_CANONICAL
, flags
) && lbuf
[0] == '@')
2643 expand("<\201g>", buf
, sizeof buf
, e
);
2645 expand(fancy
, buf
, sizeof buf
, e
);
2647 macset(&e
->e_macro
, 'g', oldg
);
2651 sm_dprintf("remotename => `%s'\n", buf
);
2655 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
2658 ** a -- the address to map (but just the user name part).
2659 ** sendq -- the sendq in which to install any replacement
2661 ** aliaslevel -- the alias nesting depth.
2662 ** e -- the envelope.
2668 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
2669 Q_PINGFLAGS|QHASNOTIFY|\
2670 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\
2671 QBYTRACE|QBYNDELAY|QBYNRELAY)
2674 maplocaluser(a
, sendq
, aliaslevel
, e
)
2675 register ADDRESS
*a
;
2680 register char **pvp
;
2681 register ADDRESS
*SM_NONVOLATILE a1
= NULL
;
2682 char pvpbuf
[PSBUFSIZE
];
2686 sm_dprintf("maplocaluser: ");
2687 printaddr(a
, false);
2689 pvp
= prescan(a
->q_user
, '\0', pvpbuf
, sizeof pvpbuf
, NULL
, NULL
);
2693 sm_dprintf("maplocaluser: cannot prescan %s\n",
2698 macdefine(&e
->e_macro
, A_PERM
, 'h', a
->q_host
);
2699 macdefine(&e
->e_macro
, A_PERM
, 'u', a
->q_user
);
2700 macdefine(&e
->e_macro
, A_PERM
, 'z', a
->q_home
);
2702 macdefine(&e
->e_macro
, A_PERM
, macid("{addr_type}"), "e r");
2703 if (REWRITE(pvp
, 5, e
) == EX_TEMPFAIL
)
2706 sm_dprintf("maplocaluser: rewrite tempfail\n");
2707 a
->q_state
= QS_QUEUEUP
;
2708 a
->q_status
= "4.4.3";
2711 if (pvp
[0] == NULL
|| (pvp
[0][0] & 0377) != CANONNET
)
2714 sm_dprintf("maplocaluser: doesn't resolve\n");
2719 a1
= buildaddr(pvp
, NULL
, 0, e
);
2720 SM_EXCEPT(exc
, "E:mta.quickabort")
2723 ** mark address as bad, S5 returned an error
2724 ** and we gave that back to the SMTP client.
2727 a
->q_state
= QS_DONTSEND
;
2728 sm_exc_raisenew_x(&EtypeQuickAbort
, 2);
2731 /* if non-null, mailer destination specified -- has it changed? */
2732 if (a1
== NULL
|| sameaddr(a
, a1
))
2735 sm_dprintf("maplocaluser: address unchanged\n");
2739 /* make new address take on flags and print attributes of old */
2740 a1
->q_flags
&= ~Q_COPYFLAGS
;
2741 a1
->q_flags
|= a
->q_flags
& Q_COPYFLAGS
;
2742 a1
->q_paddr
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_paddr
);
2743 a1
->q_finalrcpt
= a
->q_finalrcpt
;
2744 a1
->q_orcpt
= a
->q_orcpt
;
2746 /* mark old address as dead; insert new address */
2747 a
->q_state
= QS_REPLACED
;
2750 sm_dprintf("maplocaluser: QS_REPLACED ");
2751 printaddr(a
, false);
2754 allocaddr(a1
, RF_COPYALL
, sm_rpool_strdup_x(e
->e_rpool
, a
->q_paddr
), e
);
2755 (void) recipient(a1
, sendq
, aliaslevel
, e
);
2758 ** DEQUOTE_INIT -- initialize dequote map
2761 ** map -- the internal map structure.
2762 ** args -- arguments.
2769 dequote_init(map
, args
)
2773 register char *p
= args
;
2775 /* there is no check whether there is really an argument */
2776 map
->map_mflags
|= MF_KEEPQUOTES
;
2779 while (isascii(*p
) && isspace(*p
))
2790 map
->map_mflags
|= MF_DEFER
;
2795 map
->map_spacesub
= *++p
;
2798 while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
2803 if (map
->map_app
!= NULL
)
2804 map
->map_app
= newstr(map
->map_app
);
2809 ** DEQUOTE_MAP -- unquote an address
2812 ** map -- the internal map structure (ignored).
2813 ** name -- the name to dequote.
2814 ** av -- arguments (ignored).
2815 ** statp -- pointer to status out-parameter.
2818 ** NULL -- if there were no quotes, or if the resulting
2819 ** unquoted buffer would not be acceptable to prescan.
2820 ** else -- The dequoted buffer.
2825 dequote_map(map
, name
, av
, statp
)
2838 bool quotemode
= false;
2839 bool bslashmode
= false;
2840 char spacesub
= map
->map_spacesub
;
2842 for (p
= q
= name
; (c
= *p
++) != '\0'; )
2851 if (c
== ' ' && spacesub
!= '\0')
2884 quotemode
= !quotemode
;
2893 if (anglecnt
-- <= 0)
2900 if (anglecnt
!= 0 || cmntcnt
!= 0 || bslashmode
||
2901 quotemode
|| quotecnt
<= 0 || spacecnt
!= 0)
2904 return map_rewrite(map
, name
, strlen(name
), NULL
);
2907 ** RSCHECK -- check string(s) for validity using rewriting sets
2910 ** rwset -- the rewriting set to use.
2911 ** p1 -- the first string to check.
2912 ** p2 -- the second string to check -- may be null.
2913 ** e -- the current envelope.
2914 ** flags -- control some behavior, see RSF_ in sendmail.h
2915 ** logl -- logging level.
2916 ** host -- NULL or relay host.
2917 ** logid -- id for sm_syslog.
2920 ** EX_OK -- if the rwset doesn't resolve to $#error
2921 ** else -- the failure status (message printed)
2925 rscheck(rwset
, p1
, p2
, e
, flags
, logl
, host
, logid
)
2938 int volatile rstat
= EX_OK
;
2941 bool volatile discard
= false;
2943 bool saveQuickAbort
= QuickAbort
;
2944 bool saveSuprErrs
= SuprErrs
;
2946 bool quarantine
= false;
2947 char ubuf
[BUFSIZ
* 2];
2948 #endif /* _FFR_QUARANTINE */
2950 char pvpbuf
[PSBUFSIZE
];
2951 extern char MsgBuf
[];
2954 sm_dprintf("rscheck(%s, %s, %s)\n", rwset
, p1
,
2955 p2
== NULL
? "(NULL)" : p2
);
2957 rsno
= strtorwset(rwset
, NULL
, ST_FIND
);
2963 bufsize
= strlen(p1
) + strlen(p2
) + 2;
2964 if (bufsize
> sizeof buf0
)
2965 buf
= sm_malloc_x(bufsize
);
2969 bufsize
= sizeof buf0
;
2971 (void) sm_snprintf(buf
, bufsize
, "%s%c%s", p1
, CONDELSE
, p2
);
2975 bufsize
= strlen(p1
) + 1;
2976 if (bufsize
> sizeof buf0
)
2977 buf
= sm_malloc_x(bufsize
);
2981 bufsize
= sizeof buf0
;
2983 (void) sm_strlcpy(buf
, p1
, bufsize
);
2989 pvp
= prescan(buf
, '\0', pvpbuf
, sizeof pvpbuf
, NULL
,
2990 bitset(RSF_RMCOMM
, flags
) ? NULL
: TokTypeNoC
);
2991 SuprErrs
= saveSuprErrs
;
2995 sm_dprintf("rscheck: cannot prescan input\n");
2997 syserr("rscheck: cannot prescan input: \"%s\"",
2998 shortenstring(buf, MAXSHORTSTR));
3003 if (bitset(RSF_UNSTRUCTURED
, flags
))
3005 (void) REWRITE(pvp
, rsno
, e
);
3006 if (bitset(RSF_UNSTRUCTURED
, flags
))
3007 SuprErrs
= saveSuprErrs
;
3008 if (pvp
[0] == NULL
|| (pvp
[0][0] & 0377) != CANONNET
||
3009 pvp
[1] == NULL
|| (strcmp(pvp
[1], "error") != 0 &&
3010 strcmp(pvp
[1], "discard") != 0))
3015 if (strcmp(pvp
[1], "discard") == 0)
3018 sm_dprintf("rscheck: discard mailer selected\n");
3019 e
->e_flags
|= EF_DISCARD
;
3023 else if (strcmp(pvp
[1], "error") == 0 &&
3024 pvp
[2] != NULL
&& (pvp
[2][0] & 0377) == CANONHOST
&&
3025 pvp
[3] != NULL
&& strcmp(pvp
[3], "quarantine") == 0)
3027 if (pvp
[4] == NULL
||
3028 (pvp
[4][0] & 0377) != CANONUSER
||
3030 e
->e_quarmsg
= sm_rpool_strdup_x(e
->e_rpool
,
3034 cataddr(&(pvp
[5]), NULL
, ubuf
,
3036 e
->e_quarmsg
= sm_rpool_strdup_x(e
->e_rpool
,
3039 macdefine(&e
->e_macro
, A_PERM
,
3040 macid("{quarantine}"), e
->e_quarmsg
);
3043 #endif /* _FFR_QUARANTINE */
3046 int savelogusrerrs
= LogUsrErrs
;
3047 static bool logged
= false;
3049 /* got an error -- process it */
3050 saveexitstat
= ExitStat
;
3052 (void) buildaddr(pvp
, &a1
, 0, e
);
3053 LogUsrErrs
= savelogusrerrs
;
3055 ExitStat
= saveexitstat
;
3058 if (bitset(RSF_COUNT
, flags
))
3059 markstats(e
, &a1
, STATS_REJECT
);
3064 if (LogLevel
> logl
)
3073 (void) sm_snprintf(p
, SPACELEFT(lbuf
, p
),
3082 relay
= macvalue('_', e
);
3085 (void) sm_snprintf(p
, SPACELEFT(lbuf
, p
),
3086 ", relay=%s", relay
);
3091 sm_syslog(LOG_NOTICE
, logid
,
3092 "ruleset=%s, arg1=%s%s, discard",
3095 else if (quarantine
)
3096 sm_syslog(LOG_NOTICE
, logid
,
3097 "ruleset=%s, arg1=%s%s, quarantine=%s",
3098 rwset
, p1
, lbuf
, ubuf
);
3099 #endif /* _FFR_QUARANTINE */
3101 sm_syslog(LOG_NOTICE
, logid
,
3102 "ruleset=%s, arg1=%s%s, reject=%s",
3103 rwset
, p1
, lbuf
, MsgBuf
);
3113 QuickAbort
= saveQuickAbort
;
3119 /* rulesets don't set errno */
3121 if (rstat
!= EX_OK
&& QuickAbort
)
3122 sm_exc_raisenew_x(&EtypeQuickAbort
, 2);
3126 ** RSCAP -- call rewriting set to return capabilities
3129 ** rwset -- the rewriting set to use.
3130 ** p1 -- the first string to check.
3131 ** p2 -- the second string to check -- may be null.
3132 ** e -- the current envelope.
3133 ** pvp -- pointer to token vector.
3134 ** pvpbuf -- buffer space.
3135 ** size -- size of buffer space.
3138 ** EX_UNAVAILABLE -- ruleset doesn't exist.
3139 ** EX_DATAERR -- prescan() failed.
3140 ** EX_OK -- rewrite() was successful.
3141 ** else -- return status from rewrite().
3145 rscap(rwset
, p1
, p2
, e
, pvp
, pvpbuf
, size
)
3156 int volatile rstat
= EX_OK
;
3158 bool saveQuickAbort
= QuickAbort
;
3159 bool saveSuprErrs
= SuprErrs
;
3161 extern char MsgBuf
[];
3164 sm_dprintf("rscap(%s, %s, %s)\n", rwset
, p1
,
3165 p2
== NULL
? "(NULL)" : p2
);
3169 rsno
= strtorwset(rwset
, NULL
, ST_FIND
);
3171 return EX_UNAVAILABLE
;
3175 bufsize
= strlen(p1
) + strlen(p2
) + 2;
3176 if (bufsize
> sizeof buf0
)
3177 buf
= sm_malloc_x(bufsize
);
3181 bufsize
= sizeof buf0
;
3183 (void) sm_snprintf(buf
, bufsize
, "%s%c%s", p1
, CONDELSE
, p2
);
3187 bufsize
= strlen(p1
) + 1;
3188 if (bufsize
> sizeof buf0
)
3189 buf
= sm_malloc_x(bufsize
);
3193 bufsize
= sizeof buf0
;
3195 (void) sm_strlcpy(buf
, p1
, bufsize
);
3201 *pvp
= prescan(buf
, '\0', pvpbuf
, size
, NULL
, NULL
);
3203 rstat
= rewrite(*pvp
, rsno
, 0, e
, size
);
3207 sm_dprintf("rscap: cannot prescan input\n");
3216 SuprErrs
= saveSuprErrs
;
3217 QuickAbort
= saveQuickAbort
;
3219 /* prevent information leak, this may contain rewrite error */