2 * Copyright (c) 1998-2006 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.401 2007/09/27 23:33:59 ca Exp $")
18 #include <sm/sendmail.h>
21 static void allocaddr
__P((ADDRESS
*, int, char *, ENVELOPE
*));
22 static int callsubr
__P((char**, int, ENVELOPE
*));
23 static char *map_lookup
__P((STAB
*, char *, char **, int *, ENVELOPE
*));
24 static ADDRESS
*buildaddr
__P((char **, ADDRESS
*, int, ENVELOPE
*));
25 static bool hasctrlchar
__P((register char *, bool, bool));
27 /* replacement for illegal characters in addresses */
28 #define BAD_CHAR_REPLACEMENT '?'
31 ** PARSEADDR -- Parse an address
33 ** Parses an address and breaks it up into three parts: a
34 ** net to transmit the message on, the host to transmit it
35 ** to, and a user on that host. These are loaded into an
36 ** ADDRESS header with the values squirreled away if necessary.
37 ** The "user" part may not be a real user; the process may
38 ** just reoccur on that machine. For example, on a machine
39 ** with an arpanet connection, the address
40 ** csvax.bill@berkeley
41 ** will break up to a "user" of 'csvax.bill' and a host
42 ** of 'berkeley' -- to be transmitted over the arpanet.
45 ** addr -- the address to parse.
46 ** a -- a pointer to the address descriptor buffer.
47 ** If NULL, an address will be created.
48 ** flags -- describe detail for parsing. See RF_ definitions
50 ** delim -- the character to terminate the address, passed
52 ** delimptr -- if non-NULL, set to the location of the
53 ** delim character that was found.
54 ** e -- the envelope that will contain this address.
55 ** isrcpt -- true if the address denotes a recipient; false
56 ** indicates a sender.
59 ** A pointer to the address descriptor header (`a' if
67 /* following delimiters are inherent to the internal algorithms */
68 #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
71 parseaddr(addr
, a
, flags
, delim
, delimptr
, e
, isrcpt
)
81 auto char *delimptrbuf
;
83 char pvpbuf
[PSBUFSIZE
];
86 ** Initialize and prescan address.
91 sm_dprintf("\n--parseaddr(%s)\n", addr
);
94 delimptr
= &delimptrbuf
;
96 pvp
= prescan(addr
, delim
, pvpbuf
, sizeof(pvpbuf
), delimptr
,
101 sm_dprintf("parseaddr-->NULL\n");
105 if (invalidaddr(addr
, delim
== '\0' ? NULL
: *delimptr
, isrcpt
))
108 sm_dprintf("parseaddr-->bad address\n");
113 ** Save addr if we are going to have to.
115 ** We have to do this early because there is a chance that
116 ** the map lookups in the rewriting rules could clobber
117 ** static memory somewhere.
120 if (bitset(RF_COPYPADDR
, flags
) && addr
!= NULL
)
122 char savec
= **delimptr
;
126 e
->e_to
= addr
= sm_rpool_strdup_x(e
->e_rpool
, addr
);
132 ** Apply rewriting rules.
133 ** Ruleset 0 does basic parsing. It must resolve.
137 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
139 if (REWRITE(pvp
, 0, e
) == EX_TEMPFAIL
)
143 ** Build canonical address from pvp.
146 a
= buildaddr(pvp
, a
, flags
, e
);
148 if (hasctrlchar(a
->q_user
, isrcpt
, true))
151 sm_dprintf("parseaddr-->bad q_user\n");
154 ** Just mark the address as bad so DSNs work.
155 ** hasctrlchar() has to make sure that the address
156 ** has been sanitized, e.g., shortened.
159 a
->q_state
= QS_BADADDR
;
163 ** Make local copies of the host & user and then
164 ** transport them out.
167 allocaddr(a
, flags
, addr
, e
);
168 if (QS_IS_BADADDR(a
->q_state
))
170 /* weed out bad characters in the printable address too */
171 (void) hasctrlchar(a
->q_paddr
, isrcpt
, false);
176 ** Select a queue directory for recipient addresses.
177 ** This is done here and in split_across_queue_groups(),
178 ** but the latter applies to addresses after aliasing,
179 ** and only if splitting is done.
182 if ((a
->q_qgrp
== NOAQGRP
|| a
->q_qgrp
== ENVQGRP
) &&
183 !bitset(RF_SENDERADDR
|RF_HEADERADDR
|RF_RM_ADDR
, flags
) &&
184 OpMode
!= MD_INITALIAS
)
188 /* call ruleset which should return a queue group name */
189 r
= rscap(RS_QUEUEGROUP
, a
->q_user
, NULL
, e
, &pvp
, pvpbuf
,
192 pvp
!= NULL
&& pvp
[0] != NULL
&&
193 (pvp
[0][0] & 0377) == CANONNET
&&
194 pvp
[1] != NULL
&& pvp
[1][0] != '\0')
196 r
= name2qid(pvp
[1]);
197 if (r
== NOQGRP
&& LogLevel
> 10)
198 sm_syslog(LOG_INFO
, NOQID
,
199 "can't find queue group name %s, selection ignored",
201 if (tTd(20, 4) && r
!= NOQGRP
)
202 sm_syslog(LOG_INFO
, NOQID
,
203 "queue group name %s -> %d",
205 a
->q_qgrp
= r
== NOQGRP
? ENVQGRP
: r
;
210 ** If there was a parsing failure, mark it for queueing.
213 if (qup
&& OpMode
!= MD_INITALIAS
)
215 char *msg
= "Transient parse error -- message queued for future delivery";
217 if (e
->e_sendmode
== SM_DEFER
)
218 msg
= "Deferring message until queue run";
220 sm_dprintf("parseaddr: queueing message\n");
222 if (e
->e_message
== NULL
&& e
->e_sendmode
!= SM_DEFER
)
223 e
->e_message
= sm_rpool_strdup_x(e
->e_rpool
, msg
);
224 a
->q_state
= QS_QUEUEUP
;
225 a
->q_status
= "4.4.3";
229 ** Compute return value.
234 sm_dprintf("parseaddr-->");
235 printaddr(sm_debug_file(), a
, false);
241 ** INVALIDADDR -- check for address containing characters used for macros
244 ** addr -- the address to check.
245 ** delimptr -- if non-NULL: end of address to check, i.e.,
246 ** a pointer in the address string.
247 ** isrcpt -- true iff the address is for a recipient.
250 ** true -- if the address has characters that are reservered
251 ** for macros or is too long.
252 ** false -- otherwise.
256 invalidaddr(addr
, delimptr
, isrcpt
)
262 char savedelim
= '\0';
266 if (delimptr
!= NULL
)
268 /* delimptr points to the end of the address to test */
269 savedelim
= *delimptr
;
270 if (savedelim
!= '\0') /* if that isn't '\0' already: */
271 *delimptr
= '\0'; /* set it */
273 for (; *addr
!= '\0'; addr
++)
275 if (!EightBitAddrOK
&& (*addr
& 0340) == 0200)
279 *addr
= BAD_CHAR_REPLACEMENT
;
281 if (++len
> MAXNAME
- 1)
286 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
296 usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"",
299 usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"",
303 if (delimptr
!= NULL
&& savedelim
!= '\0')
304 *delimptr
= savedelim
; /* restore old character at delimptr */
308 ** HASCTRLCHAR -- check for address containing meta-characters
310 ** Checks that the address contains no meta-characters, and contains
311 ** no "non-printable" characters unless they are quoted or escaped.
312 ** Quoted or escaped characters are literals.
315 ** addr -- the address to check.
316 ** isrcpt -- true if the address is for a recipient; false
318 ** complain -- true if an error should issued if the address
319 ** is invalid and should be "repaired".
322 ** true -- if the address has any "wierd" characters or
323 ** non-printable characters or if a quote is unbalanced.
324 ** false -- otherwise.
328 hasctrlchar(addr
, isrcpt
, complain
)
330 bool isrcpt
, complain
;
339 for (; *addr
!= '\0'; addr
++)
341 if (++len
> MAXNAME
- 1)
345 (void) shorten_rfc822_string(b
, MAXNAME
- 1);
346 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
352 if (!EightBitAddrOK
&& !quoted
&& (*addr
< 32 || *addr
== 127))
354 result
= "non-printable character";
355 *addr
= BAD_CHAR_REPLACEMENT
;
360 else if (*addr
== '\\')
362 /* XXX Generic problem: no '\0' in strings. */
365 result
= "trailing \\ character";
366 *--addr
= BAD_CHAR_REPLACEMENT
;
370 if (!EightBitAddrOK
&& (*addr
& 0340) == 0200)
373 result
= "8-bit character";
374 *addr
= BAD_CHAR_REPLACEMENT
;
379 result
= "unbalanced quote"; /* unbalanced quote */
380 if (result
!= NULL
&& complain
)
383 usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)",
386 usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)",
389 return result
!= NULL
;
392 ** ALLOCADDR -- do local allocations of address on demand.
394 ** Also lowercases the host name if requested.
397 ** a -- the address to reallocate.
398 ** flags -- the copy flag (see RF_ definitions in sendmail.h
399 ** for a description).
400 ** paddr -- the printname of the address.
407 ** Copies portions of a into local buffers as requested.
411 allocaddr(a
, flags
, paddr
, e
)
418 sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags
, paddr
);
422 if (a
->q_user
== NULL
)
424 if (a
->q_host
== NULL
)
427 if (bitset(RF_COPYPARSE
, flags
))
429 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_host
);
430 if (a
->q_user
!= a
->q_paddr
)
431 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_user
);
434 if (a
->q_paddr
== NULL
)
435 a
->q_paddr
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_user
);
440 ** PRESCAN -- Prescan name and make it canonical
442 ** Scans a name and turns it into a set of tokens. This process
443 ** deletes blanks and comments (in parentheses) (if the token type
444 ** for left paren is SPC).
446 ** This routine knows about quoted strings and angle brackets.
448 ** There are certain subtleties to this routine. The one that
449 ** comes to mind now is that backslashes on the ends of names
450 ** are silently stripped off; this is intentional. The problem
451 ** is that some versions of sndmsg (like at LBL) set the kill
452 ** character to something other than @ when reading addresses;
453 ** so people type "csvax.eric\@berkeley" -- which screws up the
457 ** addr -- the name to chomp.
458 ** delim -- the delimiter for the address, normally
459 ** '\0' or ','; \0 is accepted in any case.
460 ** If '\t' then we are reading the .cf file.
461 ** pvpbuf -- place to put the saved text -- note that
462 ** the pointers are static.
463 ** pvpbsize -- size of pvpbuf.
464 ** delimptr -- if non-NULL, set to the location of the
465 ** terminating delimiter.
466 ** toktab -- if set, a token table to use for parsing.
467 ** If NULL, use the default table.
468 ** ignore -- if true, ignore unbalanced addresses
471 ** A pointer to a vector of tokens.
475 /* states and character types */
476 #define OPR 0 /* operator */
477 #define ATM 1 /* atom */
478 #define QST 2 /* in quoted string */
479 #define SPC 3 /* chewing up spaces */
480 #define ONE 4 /* pick up one character */
481 #define ILL 5 /* illegal character */
483 #define NSTATES 6 /* number of states */
484 #define TYPE 017 /* mask to select state type */
486 /* meta bits for table */
487 #define M 020 /* meta character; don't pass through */
488 #define B 040 /* cause a break */
489 #define MB M|B /* meta-break */
491 static short StateTab
[NSTATES
][NSTATES
] =
493 /* oldst chtype> OPR ATM QST SPC ONE ILL */
494 /*OPR*/ { OPR
|B
, ATM
|B
, QST
|B
, SPC
|MB
, ONE
|B
, ILL
|MB
},
495 /*ATM*/ { OPR
|B
, ATM
, QST
|B
, SPC
|MB
, ONE
|B
, ILL
|MB
},
496 /*QST*/ { QST
, QST
, OPR
, QST
, QST
, QST
},
497 /*SPC*/ { OPR
, ATM
, QST
, SPC
|M
, ONE
, ILL
|MB
},
498 /*ONE*/ { OPR
, OPR
, OPR
, OPR
, OPR
, ILL
|MB
},
499 /*ILL*/ { OPR
|B
, ATM
|B
, QST
|B
, SPC
|MB
, ONE
|B
, ILL
|M
}
502 /* these all get modified with the OperatorChars */
504 /* token type table for external strings */
505 unsigned char ExtTokenTab
[256] =
507 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
508 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,SPC
,SPC
,SPC
,SPC
,SPC
,ATM
,ATM
,
509 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
510 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
511 /* sp ! " # $ % & ' ( ) * + , - . / */
512 SPC
,ATM
,QST
,ATM
,ATM
,ATM
,ATM
,ATM
, SPC
,SPC
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
513 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
514 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
515 /* @ A B C D E F G H I J K L M N O */
516 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
517 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
518 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
519 /* ` a b c d e f g h i j k l m n o */
520 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
521 /* p q r s t u v w x y z { | } ~ del */
522 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
524 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
525 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
526 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
527 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
528 /* sp ! " # $ % & ' ( ) * + , - . / */
529 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
530 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
531 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
532 /* @ A B C D E F G H I J K L M N O */
533 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
534 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
535 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
536 /* ` a b c d e f g h i j k l m n o */
537 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
538 /* p q r s t u v w x y z { | } ~ del */
539 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
542 /* token type table for internal strings */
543 unsigned char IntTokenTab
[256] =
545 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
546 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,SPC
,SPC
,SPC
,SPC
,SPC
,ATM
,ATM
,
547 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
548 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
549 /* sp ! " # $ % & ' ( ) * + , - . / */
550 SPC
,ATM
,QST
,ATM
,ATM
,ATM
,ATM
,ATM
, SPC
,SPC
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
551 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
552 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
553 /* @ A B C D E F G H I J K L M N O */
554 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
555 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
556 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
557 /* ` a b c d e f g h i j k l m n o */
558 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
559 /* p q r s t u v w x y z { | } ~ del */
560 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
562 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
563 OPR
,OPR
,ONE
,OPR
,OPR
,OPR
,OPR
,OPR
, OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,
564 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
565 OPR
,OPR
,OPR
,ONE
,ONE
,ONE
,OPR
,OPR
, OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,
566 /* sp ! " # $ % & ' ( ) * + , - . / */
567 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
568 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
569 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
570 /* @ A B C D E F G H I J K L M N O */
571 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
572 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
573 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
574 /* ` a b c d e f g h i j k l m n o */
575 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
576 /* p q r s t u v w x y z { | } ~ del */
577 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ONE
580 /* token type table for MIME parsing */
581 unsigned char MimeTokenTab
[256] =
583 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
584 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,SPC
,SPC
,SPC
,SPC
,SPC
,ILL
,ILL
,
585 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
586 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
587 /* sp ! " # $ % & ' ( ) * + , - . / */
588 SPC
,ATM
,QST
,ATM
,ATM
,ATM
,ATM
,ATM
, SPC
,SPC
,ATM
,ATM
,OPR
,ATM
,ATM
,OPR
,
589 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
590 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,
591 /* @ A B C D E F G H I J K L M N O */
592 OPR
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
593 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
594 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,OPR
,OPR
,OPR
,ATM
,ATM
,
595 /* ` a b c d e f g h i j k l m n o */
596 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
597 /* p q r s t u v w x y z { | } ~ del */
598 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
600 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
601 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
602 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
603 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
604 /* sp ! " # $ % & ' ( ) * + , - . / */
605 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
606 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
607 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
608 /* @ A B C D E F G H I J K L M N O */
609 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
610 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
611 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
612 /* ` a b c d e f g h i j k l m n o */
613 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,
614 /* p q r s t u v w x y z { | } ~ del */
615 ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
, ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ILL
,ONE
618 /* token type table: don't strip comments */
619 unsigned char TokTypeNoC
[256] =
621 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
622 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,SPC
,SPC
,SPC
,SPC
,SPC
,ATM
,ATM
,
623 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
624 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
625 /* sp ! " # $ % & ' ( ) * + , - . / */
626 SPC
,ATM
,QST
,ATM
,ATM
,ATM
,ATM
,ATM
, OPR
,OPR
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
627 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
628 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
629 /* @ A B C D E F G H I J K L M N O */
630 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
631 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
632 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
633 /* ` a b c d e f g h i j k l m n o */
634 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
635 /* p q r s t u v w x y z { | } ~ del */
636 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
638 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
639 OPR
,OPR
,ONE
,OPR
,OPR
,OPR
,OPR
,OPR
, OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,
640 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
641 OPR
,OPR
,OPR
,ONE
,ONE
,ONE
,OPR
,OPR
, OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,OPR
,
642 /* sp ! " # $ % & ' ( ) * + , - . / */
643 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
644 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
645 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
646 /* @ A B C D E F G H I J K L M N O */
647 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
648 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
649 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
650 /* ` a b c d e f g h i j k l m n o */
651 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,
652 /* p q r s t u v w x y z { | } ~ del */
653 ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
, ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ATM
,ONE
657 #define NOCHAR (-1) /* signal nothing in lookahead token */
660 prescan(addr
, delim
, pvpbuf
, pvpbsize
, delimptr
, toktab
, ignore
)
666 unsigned char *toktab
;
680 char *saveto
= CurEnv
->e_to
;
681 static char *av
[MAXATOM
+ 1];
682 static bool firsttime
= true;
686 /* initialize the token type table */
690 if (OperatorChars
== NULL
)
693 OperatorChars
= macvalue('o', CurEnv
);
694 if (OperatorChars
== NULL
)
695 OperatorChars
= ".:@[]";
697 expand(OperatorChars
, obuf
, sizeof(obuf
) - sizeof(DELIMCHARS
),
699 (void) sm_strlcat(obuf
, DELIMCHARS
, sizeof(obuf
));
700 for (p
= obuf
; *p
!= '\0'; p
++)
702 if (IntTokenTab
[*p
& 0xff] == ATM
)
703 IntTokenTab
[*p
& 0xff] = OPR
;
704 if (ExtTokenTab
[*p
& 0xff] == ATM
)
705 ExtTokenTab
[*p
& 0xff] = OPR
;
706 if (TokTypeNoC
[*p
& 0xff] == ATM
)
707 TokTypeNoC
[*p
& 0xff] = OPR
;
711 toktab
= ExtTokenTab
;
713 /* make sure error messages don't have garbage on them */
718 route_syntax
= false;
728 sm_dprintf("prescan: ");
729 xputs(sm_debug_file(), p
);
739 /* store away any old lookahead character */
740 if (c
!= NOCHAR
&& !bslashmode
)
742 /* see if there is room */
743 if (q
>= &pvpbuf
[pvpbsize
- 5])
746 usrerr("553 5.1.1 Address too long");
747 if (strlen(addr
) > MAXNAME
)
748 addr
[MAXNAME
] = '\0';
750 if (delimptr
!= NULL
)
756 CurEnv
->e_to
= saveto
;
760 /* squirrel it away */
762 if ((char) c
== (char) -1 && !tTd(82, 101) &&
765 #endif /* !ALLOW_255 */
769 /* read a new input character */
773 /* diagnose and patch up bad syntax */
776 else if (state
== QST
)
778 usrerr("553 Unbalanced '\"'");
781 else if (cmntcnt
> 0)
783 usrerr("553 Unbalanced '('");
786 else if (anglecnt
> 0)
789 usrerr("553 Unbalanced '<'");
796 else if (c
== delim
&& cmntcnt
<= 0 && state
!= QST
)
801 /* special case for better error management */
802 if (delim
== ',' && !route_syntax
&& !ignore
)
804 usrerr("553 Unbalanced '<'");
811 sm_dprintf("c=%c, s=%d; ", c
, state
);
813 /* chew up special characters */
819 /* kludge \! for naive users */
825 else if (c
!= '!' || state
== QST
)
827 /* see if there is room */
828 if (q
>= &pvpbuf
[pvpbsize
- 5])
839 else if (state
== QST
)
842 /* do nothing, just avoid next clauses */
844 else if (c
== '(' && toktab
['('] == SPC
)
849 else if (c
== ')' && toktab
['('] == SPC
)
855 usrerr("553 Unbalanced ')'");
862 else if (cmntcnt
> 0)
871 while (isascii(*ptr
) && isspace(*ptr
))
882 usrerr("553 Unbalanced '>'");
888 route_syntax
= false;
890 else if (delim
== ' ' && isascii(c
) && isspace(c
))
896 /* see if this is end of input */
897 if (c
== delim
&& anglecnt
<= 0 && state
!= QST
)
900 newstate
= StateTab
[state
][toktab
[c
& 0xff]];
902 sm_dprintf("ns=%02o\n", newstate
);
903 state
= newstate
& TYPE
;
906 if (isascii(c
) && isprint(c
))
907 usrerr("553 Illegal character %c", c
);
909 usrerr("553 Illegal character 0x%02x",
912 if (bitset(M
, newstate
))
914 if (bitset(B
, newstate
))
921 /* see if there is room */
922 if (q
>= &pvpbuf
[pvpbsize
- 5])
928 xputs(sm_debug_file(), tok
);
931 if (avp
>= &av
[MAXATOM
])
933 usrerr("553 5.1.0 prescan: too many tokens");
936 if (q
- tok
> MAXNAME
)
938 usrerr("553 5.1.0 prescan: token too long");
943 } while (c
!= '\0' && (c
!= delim
|| anglecnt
> 0));
945 if (delimptr
!= NULL
)
953 sm_dprintf("prescan==>");
954 printav(sm_debug_file(), av
);
956 CurEnv
->e_to
= saveto
;
960 sm_dprintf("prescan: null leading token\n");
966 ** REWRITE -- apply rewrite rules to token vector.
968 ** This routine is an ordered production system. Each rewrite
969 ** rule has a LHS (called the pattern) and a RHS (called the
970 ** rewrite); 'rwr' points the the current rewrite rule.
972 ** For each rewrite rule, 'avp' points the address vector we
973 ** are trying to match against, and 'pvp' points to the pattern.
974 ** If pvp points to a special match value (MATCHZANY, MATCHANY,
975 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
976 ** matched is saved away in the match vector (pointed to by 'mvp').
978 ** When a match between avp & pvp does not match, we try to
979 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
980 ** we must also back out the match in mvp. If we reach a
981 ** MATCHANY or MATCHZANY we just extend the match and start
984 ** When we finally match, we rewrite the address vector
985 ** and try over again.
988 ** pvp -- pointer to token vector.
989 ** ruleset -- the ruleset to use for rewriting.
990 ** reclevel -- recursion level (to catch loops).
991 ** e -- the current envelope.
992 ** maxatom -- maximum length of buffer (usually MAXATOM)
995 ** A status code. If EX_TEMPFAIL, higher level code should
1004 char **match_first
; /* first token matched */
1005 char **match_last
; /* last token matched */
1006 char **match_pattern
; /* pointer to pattern */
1010 rewrite(pvp
, ruleset
, reclevel
, e
, maxatom
)
1014 register ENVELOPE
*e
;
1017 register char *ap
; /* address pointer */
1018 register char *rp
; /* rewrite pointer */
1019 register char *rulename
; /* ruleset name */
1020 register char *prefix
;
1021 register char **avp
; /* address vector pointer */
1022 register char **rvp
; /* rewrite vector pointer */
1023 register struct match
*mlp
; /* cur ptr into mlist */
1024 register struct rewrite
*rwr
; /* pointer to current rewrite rule */
1025 int ruleno
; /* current rule number */
1026 int rstat
= EX_OK
; /* return status */
1028 struct match mlist
[MAXMATCH
]; /* stores match on LHS */
1029 char *npvp
[MAXATOM
+ 1]; /* temporary space for rebuild */
1034 ** mlp will not exceed mlist[] because readcf enforces
1035 ** the upper limit of entries when reading rulesets.
1038 if (ruleset
< 0 || ruleset
>= MAXRWSETS
)
1040 syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset
);
1043 rulename
= RuleSetNames
[ruleset
];
1044 if (rulename
== NULL
)
1046 (void) sm_snprintf(name
, sizeof(name
), "%d", ruleset
);
1049 if (OpMode
== MD_TEST
)
1052 prefix
= "rewrite: ruleset ";
1053 if (OpMode
== MD_TEST
)
1055 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
1056 "%s%-16.16s input:", prefix
, rulename
);
1057 printav(smioout
, pvp
);
1059 else if (tTd(21, 1))
1061 sm_dprintf("%s%-16.16s input:", prefix
, rulename
);
1062 printav(sm_debug_file(), pvp
);
1064 if (reclevel
++ > MaxRuleRecursion
)
1066 syserr("rewrite: excessive recursion (max %d), ruleset %s",
1067 MaxRuleRecursion
, rulename
);
1076 ** Run through the list of rewrite rules, applying
1082 for (rwr
= RewriteRules
[ruleset
]; rwr
!= NULL
; )
1086 /* if already canonical, quit now */
1087 if (pvp
[0] != NULL
&& (pvp
[0][0] & 0377) == CANONNET
)
1093 sm_dprintf("-----trying rule (line %d):",
1096 sm_dprintf("-----trying rule:");
1097 printav(sm_debug_file(), rwr
->r_lhs
);
1100 /* try to match on this rule */
1104 if (++loopcount
> 100)
1106 syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
1110 sm_dprintf("workspace: ");
1111 printav(sm_debug_file(), pvp
);
1116 while ((ap
= *avp
) != NULL
|| *rvp
!= NULL
)
1121 sm_dprintf("ADVANCE rp=");
1122 xputs(sm_debug_file(), rp
);
1123 sm_dprintf(", ap=");
1124 xputs(sm_debug_file(), ap
);
1129 /* end-of-pattern before end-of-address */
1133 (rp
[0] & 0377) != MATCHZANY
&&
1134 (rp
[0] & 0377) != MATCHZERO
)
1136 /* end-of-input with patterns left */
1140 switch (rp
[0] & 0377)
1143 /* match any phrase in a class */
1144 mlp
->match_pattern
= rvp
;
1145 mlp
->match_first
= avp
;
1150 mlp
->match_last
= avp
++;
1151 cataddr(mlp
->match_first
, mlp
->match_last
,
1152 buf
, sizeof(buf
), '\0', true);
1153 if (!wordinclass(buf
, rp
[1]))
1157 sm_dprintf("EXTEND rp=");
1158 xputs(sm_debug_file(), rp
);
1159 sm_dprintf(", ap=");
1160 xputs(sm_debug_file(), ap
);
1166 sm_dprintf("CLMATCH\n");
1171 /* match any token not in a class */
1172 if (wordinclass(ap
, rp
[1]))
1179 /* match exactly one token */
1180 mlp
->match_pattern
= rvp
;
1181 mlp
->match_first
= avp
;
1182 mlp
->match_last
= avp
++;
1187 /* match zero or more tokens */
1188 mlp
->match_pattern
= rvp
;
1189 mlp
->match_first
= avp
;
1190 mlp
->match_last
= avp
- 1;
1195 /* match zero tokens */
1200 ** Match against run-time macro.
1201 ** This algorithm is broken for the
1202 ** general case (no recursive macros,
1203 ** improper tokenization) but should
1204 ** work for the usual cases.
1207 ap
= macvalue(rp
[1], e
);
1208 mlp
->match_first
= avp
;
1210 sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n",
1212 ap
== NULL
? "(NULL)" : ap
);
1219 sm_strncasecmp(ap
, *avp
,
1223 avp
= mlp
->match_first
;
1226 ap
+= strlen(*avp
++);
1233 /* must have exact match */
1234 if (sm_strcasecmp(rp
, ap
))
1240 /* successful match on this token */
1245 /* match failed -- back up */
1246 while (--mlp
>= mlist
)
1248 rvp
= mlp
->match_pattern
;
1250 avp
= mlp
->match_last
+ 1;
1255 sm_dprintf("BACKUP rp=");
1256 xputs(sm_debug_file(), rp
);
1257 sm_dprintf(", ap=");
1258 xputs(sm_debug_file(), ap
);
1264 /* run off the end -- back up again */
1268 if ((rp
[0] & 0377) == MATCHANY
||
1269 (rp
[0] & 0377) == MATCHZANY
)
1271 /* extend binding and continue */
1272 mlp
->match_last
= avp
++;
1277 if ((rp
[0] & 0377) == MATCHCLASS
)
1279 /* extend binding and try again */
1280 mlp
->match_last
= avp
;
1287 /* total failure to match */
1293 ** See if we successfully matched
1296 if (mlp
< mlist
|| *rvp
!= NULL
)
1299 sm_dprintf("----- rule fails\n");
1309 sm_dprintf("-----rule matches:");
1310 printav(sm_debug_file(), rvp
);
1316 if ((rp
[0] & 0377) == CANONUSER
)
1323 else if ((rp
[0] & 0377) == CANONHOST
)
1331 for (avp
= npvp
; *rvp
!= NULL
; rvp
++)
1333 register struct match
*m
;
1337 if ((rp
[0] & 0377) == MATCHREPL
)
1339 /* substitute from LHS */
1340 m
= &mlist
[rp
[1] - '1'];
1341 if (m
< mlist
|| m
>= mlp
)
1343 syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
1349 sm_dprintf("$%c:", rp
[1]);
1350 pp
= m
->match_first
;
1351 while (pp
<= m
->match_last
)
1353 sm_dprintf(" %p=\"", *pp
);
1355 sm_dprintf("%s\"", *pp
++);
1359 pp
= m
->match_first
;
1360 while (pp
<= m
->match_last
)
1362 if (avp
>= &npvp
[maxatom
])
1369 /* some sort of replacement */
1370 if (avp
>= &npvp
[maxatom
])
1373 syserr("554 5.3.0 rewrite: expansion too long");
1375 sm_syslog(LOG_ERR
, e
->e_id
,
1376 "rewrite: expansion too long, ruleset=%s, ruleno=%d",
1380 if ((rp
[0] & 0377) != MACRODEXPAND
)
1382 /* vanilla replacement from RHS */
1387 /* $&{x} replacement */
1388 char *mval
= macvalue(rp
[1], e
);
1391 static size_t pvpb1_size
= 0;
1392 static char **pvpb1
= NULL
;
1393 char pvpbuf
[PSBUFSIZE
];
1396 sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n",
1398 mval
== NULL
? "(NULL)" : mval
);
1399 if (mval
== NULL
|| *mval
== '\0')
1402 /* save the remainder of the input */
1403 for (xpvp
= pvp
; *xpvp
!= NULL
; xpvp
++)
1404 trsize
+= sizeof(*xpvp
);
1405 if (trsize
> pvpb1_size
)
1410 sm_pmalloc_x(trsize
);
1411 pvpb1_size
= trsize
;
1414 memmove((char *) pvpb1
,
1418 /* scan the new replacement */
1419 xpvp
= prescan(mval
, '\0', pvpbuf
,
1420 sizeof(pvpbuf
), NULL
,
1424 /* prescan pre-printed error */
1428 /* insert it into the output stream */
1429 while (*xpvp
!= NULL
)
1432 sm_dprintf(" ... %s\n",
1434 *avp
++ = sm_rpool_strdup_x(
1436 if (avp
>= &npvp
[maxatom
])
1441 sm_dprintf(" ... DONE\n");
1443 /* restore the old trailing input */
1444 memmove((char *) pvp
,
1453 ** Check for any hostname/keyword lookups.
1456 for (rvp
= npvp
; *rvp
!= NULL
; rvp
++)
1469 char *pvpb1
[MAXATOM
+ 1];
1470 char *argvect
[MAX_MAP_ARGS
];
1471 char pvpbuf
[PSBUFSIZE
];
1475 if ((rvp
[0][0] & 0377) == HOSTBEGIN
)
1480 else if ((rvp
[0][0] & 0377) == LOOKUPBEGIN
)
1482 endtoken
= LOOKUPEND
;
1484 if (mapname
== NULL
)
1486 syserr("554 5.3.0 rewrite: missing mapname");
1495 ** Got a hostname/keyword lookup.
1497 ** This could be optimized fairly easily.
1500 map
= stab(mapname
, ST_MAP
, ST_FIND
);
1502 syserr("554 5.3.0 rewrite: map %s not found",
1505 /* extract the match part */
1507 if (key_rvp
== NULL
)
1509 syserr("554 5.3.0 rewrite: missing key for map %s",
1518 while (*rvp
!= NULL
&& ((rvp
[0][0] & 0377) != endtoken
))
1520 int nodetype
= rvp
[0][0] & 0377;
1522 if (nodetype
!= CANONHOST
&&
1523 nodetype
!= CANONUSER
)
1533 cataddr(xpvp
, NULL
, replac
,
1534 &pvpbuf
[sizeof(pvpbuf
)] - replac
,
1537 &argvect
[MAX_MAP_ARGS
- 1])
1538 *++arg_rvp
= replac
;
1539 replac
+= strlen(replac
) + 1;
1557 cataddr(xpvp
, NULL
, replac
,
1558 &pvpbuf
[sizeof(pvpbuf
)] - replac
,
1560 if (arg_rvp
< &argvect
[MAX_MAP_ARGS
- 1])
1561 *++arg_rvp
= replac
;
1563 if (arg_rvp
>= &argvect
[MAX_MAP_ARGS
- 1])
1564 argvect
[MAX_MAP_ARGS
- 1] = NULL
;
1568 /* save the remainder of the input string */
1569 trsize
= (avp
- rvp
+ 1) * sizeof(*rvp
);
1570 memmove((char *) pvpb1
, (char *) rvp
, trsize
);
1573 cataddr(key_rvp
, NULL
, cbuf
, sizeof(cbuf
),
1574 map
== NULL
? '\0' : map
->s_map
.map_spacesub
,
1577 replac
= map_lookup(map
, cbuf
, argvect
, &rstat
, e
);
1579 /* if no replacement, use default */
1580 if (replac
== NULL
&& default_rvp
!= NULL
)
1582 /* create the default */
1583 cataddr(default_rvp
, NULL
, cbuf
, sizeof(cbuf
),
1592 else if (*replac
== '\0')
1594 /* null replacement */
1600 /* scan the new replacement */
1601 xpvp
= prescan(replac
, '\0', pvpbuf
,
1602 sizeof(pvpbuf
), NULL
, NULL
,
1606 /* prescan already printed error */
1611 /* append it to the token list */
1612 for (avp
= hbrvp
; *xpvp
!= NULL
; xpvp
++)
1614 *avp
++ = sm_rpool_strdup_x(e
->e_rpool
, *xpvp
);
1615 if (avp
>= &npvp
[maxatom
])
1619 /* restore the old trailing information */
1621 for (xpvp
= pvpb1
; (*avp
++ = *xpvp
++) != NULL
; )
1622 if (avp
>= &npvp
[maxatom
])
1627 ** Check for subroutine calls.
1630 status
= callsubr(npvp
, reclevel
, e
);
1631 if (rstat
== EX_OK
|| status
== EX_TEMPFAIL
)
1634 /* copy vector back into original space. */
1635 for (avp
= npvp
; *avp
++ != NULL
;)
1637 memmove((char *) pvp
, (char *) npvp
,
1638 (int) (avp
- npvp
) * sizeof(*avp
));
1642 sm_dprintf("rewritten as:");
1643 printav(sm_debug_file(), pvp
);
1647 if (OpMode
== MD_TEST
)
1649 (void) sm_io_fprintf(smioout
, SM_TIME_DEFAULT
,
1650 "%s%-16.16s returns:", prefix
, rulename
);
1651 printav(smioout
, pvp
);
1653 else if (tTd(21, 1))
1655 sm_dprintf("%s%-16.16s returns:", prefix
, rulename
);
1656 printav(sm_debug_file(), pvp
);
1661 ** CALLSUBR -- call subroutines in rewrite vector
1664 ** pvp -- pointer to token vector.
1665 ** reclevel -- the current recursion level.
1666 ** e -- the current envelope.
1669 ** The status from the subroutine call.
1676 callsubr(pvp
, reclevel
, e
)
1688 int subrnumber
[MAX_SUBR
];
1689 int subrindex
[MAX_SUBR
];
1694 ** Look for subroutine calls in pvp, collect them into subr*[]
1695 ** We will perform the calls in the next loop, because we will
1696 ** call the "last" subroutine first to avoid recursive calls
1697 ** and too much copying.
1700 for (avp
= pvp
, j
= 0; *avp
!= NULL
; avp
++, j
++)
1702 if ((avp
[0][0] & 0377) == CALLSUBR
&& avp
[1] != NULL
)
1704 stripquotes(avp
[1]);
1705 subr
= strtorwset(avp
[1], NULL
, ST_FIND
);
1708 syserr("554 5.3.5 Unknown ruleset %s", avp
[1]);
1713 ** XXX instead of doing this we could optimize
1714 ** the rules after reading them: just remove
1715 ** calls to empty rulesets
1718 /* subroutine is an empty ruleset? don't call it */
1719 if (RewriteRules
[subr
] == NULL
)
1722 sm_dprintf("-----skip subr %s (%d)\n",
1724 for (i
= 2; avp
[i
] != NULL
; i
++)
1725 avp
[i
- 2] = avp
[i
];
1729 if (++nsubr
>= MAX_SUBR
)
1731 syserr("554 5.3.0 Too many subroutine calls (%d max)",
1735 subrnumber
[nsubr
] = subr
;
1736 subrindex
[nsubr
] = j
;
1741 ** Perform the actual subroutines calls, "last" one first, i.e.,
1742 ** go from the right to the left through all calls,
1743 ** do the rewriting in place.
1746 for (; nsubr
> 0; nsubr
--)
1748 subr
= subrnumber
[nsubr
];
1749 avp
= pvp
+ subrindex
[nsubr
];
1751 /* remove the subroutine call and name */
1752 for (i
= 2; avp
[i
] != NULL
; i
++)
1753 avp
[i
- 2] = avp
[i
];
1757 ** Now we need to call the ruleset specified for
1758 ** the subroutine. We can do this in place since
1759 ** we call the "last" subroutine first.
1762 status
= rewrite(avp
, subr
, reclevel
, e
,
1763 MAXATOM
- subrindex
[nsubr
]);
1764 if (status
!= EX_OK
&& status
!= EX_TEMPFAIL
)
1766 if (rstat
== EX_OK
|| status
== EX_TEMPFAIL
)
1772 ** MAP_LOOKUP -- do lookup in map
1775 ** smap -- the map to use for the lookup.
1776 ** key -- the key to look up.
1777 ** argvect -- arguments to pass to the map lookup.
1778 ** pstat -- a pointer to an integer in which to store the
1779 ** status from the lookup.
1780 ** e -- the current envelope.
1783 ** The result of the lookup.
1784 ** NULL -- if there was no data for the given key.
1788 map_lookup(smap
, key
, argvect
, pstat
, e
)
1795 auto int status
= EX_OK
;
1805 if (e
->e_sendmode
== SM_DEFER
&&
1806 bitset(MF_DEFER
, map
->map_mflags
))
1808 /* don't do any map lookups */
1810 sm_dprintf("map_lookup(%s, %s) => DEFERRED\n",
1812 *pstat
= EX_TEMPFAIL
;
1816 if (!bitset(MF_KEEPQUOTES
, map
->map_mflags
))
1821 sm_dprintf("map_lookup(%s, ", smap
->s_name
);
1822 xputs(sm_debug_file(), key
);
1827 for (i
= 0; argvect
[i
] != NULL
; i
++)
1828 sm_dprintf(", %%%d=%s", i
, argvect
[i
]);
1830 sm_dprintf(") => ");
1832 replac
= (*map
->map_class
->map_lookup
)(map
, key
, argvect
, &status
);
1834 sm_dprintf("%s (%d)\n",
1835 replac
!= NULL
? replac
: "NOT FOUND",
1838 /* should recover if status == EX_TEMPFAIL */
1839 if (status
== EX_TEMPFAIL
&& !bitset(MF_NODEFER
, map
->map_mflags
))
1841 *pstat
= EX_TEMPFAIL
;
1843 sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
1844 smap
->s_name
, key
, errno
);
1845 if (e
->e_message
== NULL
)
1849 (void) sm_snprintf(mbuf
, sizeof(mbuf
),
1850 "%.80s map: lookup (%s): deferred",
1852 shortenstring(key
, MAXSHORTSTR
));
1853 e
->e_message
= sm_rpool_strdup_x(e
->e_rpool
, mbuf
);
1856 if (status
== EX_TEMPFAIL
&& map
->map_tapp
!= NULL
)
1858 size_t i
= strlen(key
) + strlen(map
->map_tapp
) + 1;
1859 static char *rwbuf
= NULL
;
1860 static size_t rwbuflen
= 0;
1867 rwbuf
= (char *) sm_pmalloc_x(rwbuflen
);
1869 (void) sm_strlcpyn(rwbuf
, rwbuflen
, 2, key
, map
->map_tapp
);
1871 sm_dprintf("map_lookup tempfail: returning \"%s\"\n",
1878 ** INITERRMAILERS -- initialize error and discard mailers
1887 ** initializes error and discard mailers.
1890 static MAILER discardmailer
;
1891 static MAILER errormailer
;
1892 static char *discardargv
[] = { "DISCARD", NULL
};
1893 static char *errorargv
[] = { "ERROR", NULL
};
1898 if (discardmailer
.m_name
== NULL
)
1900 /* initialize the discard mailer */
1901 discardmailer
.m_name
= "*discard*";
1902 discardmailer
.m_mailer
= "DISCARD";
1903 discardmailer
.m_argv
= discardargv
;
1905 if (errormailer
.m_name
== NULL
)
1907 /* initialize the bogus mailer */
1908 errormailer
.m_name
= "*error*";
1909 errormailer
.m_mailer
= "ERROR";
1910 errormailer
.m_argv
= errorargv
;
1914 ** BUILDADDR -- build address from token vector.
1917 ** tv -- token vector.
1918 ** a -- pointer to address descriptor to fill.
1919 ** If NULL, one will be allocated.
1920 ** flags -- info regarding whether this is a sender or
1922 ** e -- the current envelope.
1925 ** NULL if there was an error.
1932 static struct errcodes
1934 char *ec_name
; /* name of error code */
1935 int ec_code
; /* numeric code */
1938 { "usage", EX_USAGE
},
1939 { "nouser", EX_NOUSER
},
1940 { "nohost", EX_NOHOST
},
1941 { "unavailable", EX_UNAVAILABLE
},
1942 { "software", EX_SOFTWARE
},
1943 { "tempfail", EX_TEMPFAIL
},
1944 { "protocol", EX_PROTOCOL
},
1945 { "config", EX_CONFIG
},
1946 { NULL
, EX_UNAVAILABLE
}
1950 buildaddr(tv
, a
, flags
, e
)
1952 register ADDRESS
*a
;
1954 register ENVELOPE
*e
;
1956 bool tempfail
= false;
1959 register struct mailer
*m
;
1963 char hbuf
[MAXNAME
+ 1];
1964 static char ubuf
[MAXNAME
+ 2];
1968 sm_dprintf("buildaddr, flags=%x, tv=", flags
);
1969 printav(sm_debug_file(), tv
);
1974 a
= (ADDRESS
*) sm_rpool_malloc_x(e
->e_rpool
, sizeof(*a
));
1975 memset((char *) a
, '\0', sizeof(*a
));
1978 /* set up default error return flags */
1979 a
->q_flags
|= DefaultNotify
;
1981 /* figure out what net/mailer to use */
1982 if (*tv
== NULL
|| (**tv
& 0377) != CANONNET
)
1984 syserr("554 5.3.5 buildaddr: no mailer in parsed address");
1987 ** ExitStat may have been set by an earlier map open
1988 ** failure (to a permanent error (EX_OSERR) in syserr())
1989 ** so we also need to check if this particular $#error
1990 ** return wanted a 4XX failure.
1992 ** XXX the real fix is probably to set ExitStat correctly,
1993 ** i.e., to EX_TEMPFAIL if the map open is just a temporary
1997 if (ExitStat
== EX_TEMPFAIL
|| tempfail
)
1998 a
->q_state
= QS_QUEUEUP
;
2001 a
->q_state
= QS_BADADDR
;
2002 a
->q_mailer
= &errormailer
;
2009 /* extract host and user portions */
2010 if (*++tv
!= NULL
&& (**tv
& 0377) == CANONHOST
)
2018 while (*tv
!= NULL
&& (**tv
& 0377) != CANONUSER
)
2025 syserr("554 5.3.5 buildaddr: no user");
2030 else if (hostp
!= NULL
)
2031 cataddr(hostp
, tv
- 1, hbuf
, sizeof(hbuf
), '\0', false);
2032 cataddr(++tv
, NULL
, ubuf
, sizeof(ubuf
), ' ', false);
2035 /* save away the host name */
2036 if (sm_strcasecmp(mname
, "error") == 0)
2038 /* Set up triplet for use by -bv */
2039 a
->q_mailer
= &errormailer
;
2040 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, ubuf
);
2041 /* XXX wrong place? */
2045 register struct errcodes
*ep
;
2047 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, hbuf
);
2048 if (strchr(hbuf
, '.') != NULL
)
2050 a
->q_status
= sm_rpool_strdup_x(e
->e_rpool
,
2052 setstat(dsntoexitstat(hbuf
));
2054 else if (isascii(hbuf
[0]) && isdigit(hbuf
[0]))
2056 setstat(atoi(hbuf
));
2060 for (ep
= ErrorCodes
; ep
->ec_name
!= NULL
; ep
++)
2061 if (sm_strcasecmp(ep
->ec_name
, hbuf
) == 0)
2063 setstat(ep
->ec_code
);
2069 setstat(EX_UNAVAILABLE
);
2072 if (ISSMTPCODE(ubuf
) && ubuf
[3] == ' ')
2077 if ((off
= isenhsc(ubuf
+ 4, ' ')) > 0)
2079 ubuf
[off
+ 4] = '\0';
2087 (void) sm_strlcpyn(fmt
, sizeof(fmt
), 2, ubuf
, " %s");
2089 usrerr(fmt
, ubuf
+ off
);
2090 else if (isenhsc(hbuf
, '\0') > 0)
2091 usrerrenh(hbuf
, fmt
, ubuf
+ off
);
2093 usrerr(fmt
, ubuf
+ off
);
2094 /* XXX ubuf[off - 1] = ' '; */
2100 usrerr("553 5.3.0 %s", ubuf
);
2105 for (mp
= Mailer
; (m
= *mp
++) != NULL
; )
2107 if (sm_strcasecmp(m
->m_name
, mname
) == 0)
2112 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname
);
2117 /* figure out what host (if any) */
2120 if (!bitnset(M_LOCALMAILER
, m
->m_flags
))
2122 syserr("554 5.3.5 buildaddr: no host");
2128 a
->q_host
= sm_rpool_strdup_x(e
->e_rpool
, hbuf
);
2130 /* figure out the user */
2132 if (bitnset(M_CHECKUDB
, m
->m_flags
) && *p
== '@')
2137 a
->q_flags
|= QNOTREMOTE
;
2140 /* do special mapping for local mailer */
2143 if (*p
== '|' && bitnset(M_CHECKPROG
, m
->m_flags
))
2144 a
->q_mailer
= m
= ProgMailer
;
2145 else if (*p
== '/' && bitnset(M_CHECKFILE
, m
->m_flags
))
2146 a
->q_mailer
= m
= FileMailer
;
2147 else if (*p
== ':' && bitnset(M_CHECKINCLUDE
, m
->m_flags
))
2149 /* may be :include: */
2151 if (sm_strncasecmp(ubuf
, ":include:", 9) == 0)
2153 /* if :include:, don't need further rewriting */
2154 a
->q_mailer
= m
= InclMailer
;
2155 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, &ubuf
[9]);
2160 /* rewrite according recipient mailer rewriting rules */
2161 macdefine(&e
->e_macro
, A_PERM
, 'h', a
->q_host
);
2163 if (ConfigLevel
>= 10 ||
2164 !bitset(RF_SENDERADDR
|RF_HEADERADDR
, flags
))
2166 /* sender addresses done later */
2167 (void) rewrite(tv
, 2, 0, e
, maxatom
);
2168 if (m
->m_re_rwset
> 0)
2169 (void) rewrite(tv
, m
->m_re_rwset
, 0, e
, maxatom
);
2171 (void) rewrite(tv
, 4, 0, e
, maxatom
);
2173 /* save the result for the command line/RCPT argument */
2174 cataddr(tv
, NULL
, ubuf
, sizeof(ubuf
), '\0', true);
2175 a
->q_user
= sm_rpool_strdup_x(e
->e_rpool
, ubuf
);
2178 ** Do mapping to lower case as requested by mailer
2181 if (a
->q_host
!= NULL
&& !bitnset(M_HST_UPPER
, m
->m_flags
))
2182 makelower(a
->q_host
);
2183 if (!bitnset(M_USR_UPPER
, m
->m_flags
))
2184 makelower(a
->q_user
);
2188 sm_dprintf("buildaddr => ");
2189 printaddr(sm_debug_file(), a
, false);
2195 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
2198 ** pvp -- parameter vector to rebuild.
2199 ** evp -- last parameter to include. Can be NULL to
2201 ** buf -- buffer to build the string into.
2202 ** sz -- size of buf.
2203 ** spacesub -- the space separator character; if '\0',
2205 ** external -- convert to external form?
2206 ** (no metacharacters; METAQUOTEs removed, see below)
2215 ** There are two formats for strings: internal and external.
2216 ** The external format is just an eight-bit clean string (no
2217 ** null bytes, everything else OK). The internal format can
2218 ** include sendmail metacharacters. The special character
2219 ** METAQUOTE essentially quotes the character following, stripping
2220 ** it of all special semantics.
2222 ** The cataddr routine needs to be aware of whether it is producing
2223 ** an internal or external form as output (it only takes internal
2226 ** The parseaddr routine has a similar issue on input, but that
2227 ** is flagged on the basis of which token table is passed in.
2231 cataddr(pvp
, evp
, buf
, sz
, spacesub
, external
)
2239 bool oatomtok
, natomtok
;
2242 oatomtok
= natomtok
= false;
2245 sm_dprintf("cataddr(%d) <==", external
);
2246 printav(sm_debug_file(), pvp
);
2252 if (spacesub
== '\0')
2253 spacesub
= SpaceSub
;
2262 while (*pvp
!= NULL
&& sz
> 0)
2266 natomtok
= (ExtTokenTab
[**pvp
& 0xff] == ATM
);
2267 if (oatomtok
&& natomtok
)
2273 for (q
= *pvp
; *q
!= '\0'; )
2282 ** If the current character (c) is METAQUOTE and we
2283 ** want the "external" form and the next character
2284 ** is not NUL, then overwrite METAQUOTE with that
2285 ** character (i.e., METAQUOTE ch is changed to
2286 ** ch). p[-1] is used because p is advanced (above).
2289 if ((c
& 0377) == METAQUOTE
&& external
&& *q
!= '\0')
2294 oatomtok
= natomtok
;
2301 ** Silently truncate long strings: even though this doesn't
2302 ** seem like a good idea it is necessary because header checks
2303 ** send the whole header value to rscheck() and hence rewrite().
2304 ** The latter however sometimes uses a "short" buffer (e.g.,
2305 ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this
2306 ** error function. One possible fix to the problem is to pass
2307 ** flags to rscheck() and rewrite() to distinguish the various
2308 ** calls and only trigger the error if necessary. For now just
2309 ** undo the change from 8.13.0.
2313 usrerr("cataddr: string too long");
2318 sm_dprintf(" cataddr => %s\n", str2prt(buf
));
2322 ** SAMEADDR -- Determine if two addresses are the same
2324 ** This is not just a straight comparison -- if the mailer doesn't
2325 ** care about the host we just ignore it, etc.
2328 ** a, b -- pointers to the internal forms to compare.
2331 ** true -- they represent the same mailbox.
2332 ** false -- they don't.
2340 register ADDRESS
*a
;
2341 register ADDRESS
*b
;
2343 register ADDRESS
*ca
, *cb
;
2345 /* if they don't have the same mailer, forget it */
2346 if (a
->q_mailer
!= b
->q_mailer
)
2349 /* if the user isn't the same, we can drop out */
2350 if (strcmp(a
->q_user
, b
->q_user
) != 0)
2353 /* if we have good uids for both but they differ, these are different */
2354 if (a
->q_mailer
== ProgMailer
)
2358 if (ca
!= NULL
&& cb
!= NULL
&&
2359 bitset(QGOODUID
, ca
->q_flags
& cb
->q_flags
) &&
2360 ca
->q_uid
!= cb
->q_uid
)
2364 /* otherwise compare hosts (but be careful for NULL ptrs) */
2365 if (a
->q_host
== b
->q_host
)
2367 /* probably both null pointers */
2370 if (a
->q_host
== NULL
|| b
->q_host
== NULL
)
2372 /* only one is a null pointer */
2375 if (strcmp(a
->q_host
, b
->q_host
) != 0)
2381 ** PRINTADDR -- print address (for debugging)
2384 ** a -- the address to print
2385 ** follow -- follow the q_next chain.
2397 unsigned long qf_bit
;
2400 static struct qflags AddressFlags
[] =
2402 { "QGOODUID", QGOODUID
},
2403 { "QPRIMARY", QPRIMARY
},
2404 { "QNOTREMOTE", QNOTREMOTE
},
2405 { "QSELFREF", QSELFREF
},
2406 { "QBOGUSSHELL", QBOGUSSHELL
},
2407 { "QUNSAFEADDR", QUNSAFEADDR
},
2408 { "QPINGONSUCCESS", QPINGONSUCCESS
},
2409 { "QPINGONFAILURE", QPINGONFAILURE
},
2410 { "QPINGONDELAY", QPINGONDELAY
},
2411 { "QHASNOTIFY", QHASNOTIFY
},
2412 { "QRELAYED", QRELAYED
},
2413 { "QEXPANDED", QEXPANDED
},
2414 { "QDELIVERED", QDELIVERED
},
2415 { "QDELAYED", QDELAYED
},
2416 { "QTHISPASS", QTHISPASS
},
2417 { "QRCPTOK", QRCPTOK
},
2422 printaddr(fp
, a
, follow
)
2424 register ADDRESS
*a
;
2428 MAILER pseudomailer
;
2429 register struct qflags
*qfp
;
2434 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "[NULL]\n");
2440 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "%p=", a
);
2441 (void) sm_io_flush(fp
, SM_TIME_DEFAULT
);
2443 /* find the mailer -- carefully */
2452 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2453 "%s:\n\tmailer %d (%s), host `%s'\n",
2454 a
->q_paddr
== NULL
? "<null>" : a
->q_paddr
,
2455 m
->m_mno
, m
->m_name
,
2456 a
->q_host
== NULL
? "<null>" : a
->q_host
);
2457 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2458 "\tuser `%s', ruser `%s'\n",
2460 a
->q_ruser
== NULL
? "<null>" : a
->q_ruser
);
2461 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "\tstate=");
2465 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "OK");
2469 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2474 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2479 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2484 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "RETRY");
2488 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "SENT");
2492 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2497 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2502 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2507 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2512 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2517 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2522 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2527 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2532 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2537 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2541 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2542 ", next=%p, alias %p, uid %d, gid %d\n",
2543 a
->q_next
, a
->q_alias
,
2544 (int) a
->q_uid
, (int) a
->q_gid
);
2545 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "\tflags=%lx<",
2548 for (qfp
= AddressFlags
; qfp
->qf_name
!= NULL
; qfp
++)
2550 if (!bitset(qfp
->qf_bit
, a
->q_flags
))
2553 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2556 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, "%s",
2559 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
, ">\n");
2560 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2561 "\towner=%s, home=\"%s\", fullname=\"%s\"\n",
2562 a
->q_owner
== NULL
? "(none)" : a
->q_owner
,
2563 a
->q_home
== NULL
? "(none)" : a
->q_home
,
2564 a
->q_fullname
== NULL
? "(none)" : a
->q_fullname
);
2565 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2566 "\torcpt=\"%s\", statmta=%s, status=%s\n",
2567 a
->q_orcpt
== NULL
? "(none)" : a
->q_orcpt
,
2568 a
->q_statmta
== NULL
? "(none)" : a
->q_statmta
,
2569 a
->q_status
== NULL
? "(none)" : a
->q_status
);
2570 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2571 "\tfinalrcpt=\"%s\"\n",
2572 a
->q_finalrcpt
== NULL
? "(none)" : a
->q_finalrcpt
);
2573 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2574 "\trstatus=\"%s\"\n",
2575 a
->q_rstatus
== NULL
? "(none)" : a
->q_rstatus
);
2576 (void) sm_io_fprintf(fp
, SM_TIME_DEFAULT
,
2578 a
->q_statdate
== 0 ? "(none)" : ctime(&a
->q_statdate
));
2586 ** EMPTYADDR -- return true if this address is empty (``<>'')
2589 ** a -- pointer to the address
2592 ** true -- if this address is "empty" (i.e., no one should
2593 ** ever generate replies to it.
2594 ** false -- if it is a "regular" (read: replyable) address.
2599 register ADDRESS
*a
;
2601 return a
->q_paddr
== NULL
|| strcmp(a
->q_paddr
, "<>") == 0 ||
2602 a
->q_user
== NULL
|| strcmp(a
->q_user
, "<>") == 0;
2605 ** REMOTENAME -- return the name relative to the current mailer
2608 ** name -- the name to translate.
2609 ** m -- the mailer that we want to do rewriting relative to.
2610 ** flags -- fine tune operations.
2611 ** pstat -- pointer to status word.
2612 ** e -- the current envelope.
2615 ** the text string representing this address relative to
2616 ** the receiving mailer.
2622 ** The text string returned is tucked away locally;
2623 ** copy it if you intend to save it.
2627 remotename(name
, m
, flags
, pstat
, e
)
2632 register ENVELOPE
*e
;
2634 register char **pvp
;
2635 char *SM_NONVOLATILE fancy
;
2638 static char buf
[MAXNAME
+ 1];
2639 char lbuf
[MAXNAME
+ 1];
2640 char pvpbuf
[PSBUFSIZE
];
2645 sm_dprintf("remotename(");
2646 xputs(sm_debug_file(), name
);
2650 /* don't do anything if we are tagging it as special */
2651 if (bitset(RF_SENDERADDR
, flags
))
2653 rwset
= bitset(RF_HEADERADDR
, flags
) ? m
->m_sh_rwset
2659 rwset
= bitset(RF_HEADERADDR
, flags
) ? m
->m_rh_rwset
2667 addrtype
[0] = bitset(RF_HEADERADDR
, flags
) ? 'h' : 'e';
2668 macdefine(&e
->e_macro
, A_TEMP
, macid("{addr_type}"), addrtype
);
2671 ** Do a heuristic crack of this name to extract any comment info.
2672 ** This will leave the name as a comment and a $g macro.
2675 if (bitset(RF_CANONICAL
, flags
) || bitnset(M_NOCOMMENT
, m
->m_flags
))
2678 fancy
= crackaddr(name
, e
);
2681 ** Turn the name into canonical form.
2682 ** Normally this will be RFC 822 style, i.e., "user@domain".
2683 ** If this only resolves to "user", and the "C" flag is
2684 ** specified in the sending mailer, then the sender's
2685 ** domain will be appended.
2688 pvp
= prescan(name
, '\0', pvpbuf
, sizeof(pvpbuf
), NULL
, NULL
, false);
2691 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
2692 *pstat
= EX_TEMPFAIL
;
2693 if (bitset(RF_ADDDOMAIN
, flags
) && e
->e_fromdomain
!= NULL
)
2695 /* append from domain to this address */
2696 register char **pxp
= pvp
;
2697 int l
= MAXATOM
; /* size of buffer for pvp */
2699 /* see if there is an "@domain" in the current name */
2700 while (*pxp
!= NULL
&& strcmp(*pxp
, "@") != 0)
2707 /* no.... append the "@domain" from the sender */
2708 register char **qxq
= e
->e_fromdomain
;
2710 while ((*pxp
++ = *qxq
++) != NULL
)
2715 usrerr("553 5.1.0 remotename: too many tokens");
2716 *pstat
= EX_UNAVAILABLE
;
2720 if (REWRITE(pvp
, 3, e
) == EX_TEMPFAIL
)
2721 *pstat
= EX_TEMPFAIL
;
2726 ** Do more specific rewriting.
2727 ** Rewrite using ruleset 1 or 2 depending on whether this is
2728 ** a sender address or not.
2729 ** Then run it through any receiving-mailer-specific rulesets.
2732 if (bitset(RF_SENDERADDR
, flags
))
2734 if (REWRITE(pvp
, 1, e
) == EX_TEMPFAIL
)
2735 *pstat
= EX_TEMPFAIL
;
2739 if (REWRITE(pvp
, 2, e
) == EX_TEMPFAIL
)
2740 *pstat
= EX_TEMPFAIL
;
2744 if (REWRITE(pvp
, rwset
, e
) == EX_TEMPFAIL
)
2745 *pstat
= EX_TEMPFAIL
;
2749 ** Do any final sanitation the address may require.
2750 ** This will normally be used to turn internal forms
2751 ** (e.g., user@host.LOCAL) into external form. This
2752 ** may be used as a default to the above rules.
2755 if (REWRITE(pvp
, 4, e
) == EX_TEMPFAIL
)
2756 *pstat
= EX_TEMPFAIL
;
2759 ** Now restore the comment information we had at the beginning.
2762 cataddr(pvp
, NULL
, lbuf
, sizeof(lbuf
), '\0', false);
2763 oldg
= macget(&e
->e_macro
, 'g');
2764 macset(&e
->e_macro
, 'g', lbuf
);
2767 /* need to make sure route-addrs have <angle brackets> */
2768 if (bitset(RF_CANONICAL
, flags
) && lbuf
[0] == '@')
2769 expand("<\201g>", buf
, sizeof(buf
), e
);
2771 expand(fancy
, buf
, sizeof(buf
), e
);
2773 macset(&e
->e_macro
, 'g', oldg
);
2778 sm_dprintf("remotename => `");
2779 xputs(sm_debug_file(), buf
);
2785 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
2788 ** a -- the address to map (but just the user name part).
2789 ** sendq -- the sendq in which to install any replacement
2791 ** aliaslevel -- the alias nesting depth.
2792 ** e -- the envelope.
2798 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
2799 Q_PINGFLAGS|QHASNOTIFY|\
2800 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\
2801 QBYTRACE|QBYNDELAY|QBYNRELAY)
2804 maplocaluser(a
, sendq
, aliaslevel
, e
)
2805 register ADDRESS
*a
;
2810 register char **pvp
;
2811 register ADDRESS
*SM_NONVOLATILE a1
= NULL
;
2812 char pvpbuf
[PSBUFSIZE
];
2816 sm_dprintf("maplocaluser: ");
2817 printaddr(sm_debug_file(), a
, false);
2819 pvp
= prescan(a
->q_user
, '\0', pvpbuf
, sizeof(pvpbuf
), NULL
, NULL
,
2824 sm_dprintf("maplocaluser: cannot prescan %s\n",
2829 macdefine(&e
->e_macro
, A_PERM
, 'h', a
->q_host
);
2830 macdefine(&e
->e_macro
, A_PERM
, 'u', a
->q_user
);
2831 macdefine(&e
->e_macro
, A_PERM
, 'z', a
->q_home
);
2833 macdefine(&e
->e_macro
, A_PERM
, macid("{addr_type}"), "e r");
2834 if (REWRITE(pvp
, 5, e
) == EX_TEMPFAIL
)
2837 sm_dprintf("maplocaluser: rewrite tempfail\n");
2838 a
->q_state
= QS_QUEUEUP
;
2839 a
->q_status
= "4.4.3";
2842 if (pvp
[0] == NULL
|| (pvp
[0][0] & 0377) != CANONNET
)
2845 sm_dprintf("maplocaluser: doesn't resolve\n");
2850 a1
= buildaddr(pvp
, NULL
, 0, e
);
2851 SM_EXCEPT(exc
, "E:mta.quickabort")
2854 ** mark address as bad, S5 returned an error
2855 ** and we gave that back to the SMTP client.
2858 a
->q_state
= QS_DONTSEND
;
2859 sm_exc_raisenew_x(&EtypeQuickAbort
, 2);
2862 /* if non-null, mailer destination specified -- has it changed? */
2863 if (a1
== NULL
|| sameaddr(a
, a1
))
2866 sm_dprintf("maplocaluser: address unchanged\n");
2870 /* make new address take on flags and print attributes of old */
2871 a1
->q_flags
&= ~Q_COPYFLAGS
;
2872 a1
->q_flags
|= a
->q_flags
& Q_COPYFLAGS
;
2873 a1
->q_paddr
= sm_rpool_strdup_x(e
->e_rpool
, a
->q_paddr
);
2874 a1
->q_finalrcpt
= a
->q_finalrcpt
;
2875 a1
->q_orcpt
= a
->q_orcpt
;
2877 /* mark old address as dead; insert new address */
2878 a
->q_state
= QS_REPLACED
;
2881 sm_dprintf("maplocaluser: QS_REPLACED ");
2882 printaddr(sm_debug_file(), a
, false);
2885 allocaddr(a1
, RF_COPYALL
, sm_rpool_strdup_x(e
->e_rpool
, a
->q_paddr
), e
);
2886 (void) recipient(a1
, sendq
, aliaslevel
, e
);
2889 ** DEQUOTE_INIT -- initialize dequote map
2892 ** map -- the internal map structure.
2893 ** args -- arguments.
2900 dequote_init(map
, args
)
2904 register char *p
= args
;
2906 /* there is no check whether there is really an argument */
2907 map
->map_mflags
|= MF_KEEPQUOTES
;
2910 while (isascii(*p
) && isspace(*p
))
2921 map
->map_mflags
|= MF_DEFER
;
2926 map
->map_spacesub
= *++p
;
2929 while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
2934 if (map
->map_app
!= NULL
)
2935 map
->map_app
= newstr(map
->map_app
);
2940 ** DEQUOTE_MAP -- unquote an address
2943 ** map -- the internal map structure (ignored).
2944 ** name -- the name to dequote.
2945 ** av -- arguments (ignored).
2946 ** statp -- pointer to status out-parameter.
2949 ** NULL -- if there were no quotes, or if the resulting
2950 ** unquoted buffer would not be acceptable to prescan.
2951 ** else -- The dequoted buffer.
2956 dequote_map(map
, name
, av
, statp
)
2969 bool quotemode
= false;
2970 bool bslashmode
= false;
2971 char spacesub
= map
->map_spacesub
;
2973 for (p
= q
= name
; (c
= *p
++) != '\0'; )
2982 if (c
== ' ' && spacesub
!= '\0')
3015 quotemode
= !quotemode
;
3024 if (anglecnt
-- <= 0)
3031 if (anglecnt
!= 0 || cmntcnt
!= 0 || bslashmode
||
3032 quotemode
|| quotecnt
<= 0 || spacecnt
!= 0)
3035 return map_rewrite(map
, name
, strlen(name
), NULL
);
3038 ** RSCHECK -- check string(s) for validity using rewriting sets
3041 ** rwset -- the rewriting set to use.
3042 ** p1 -- the first string to check.
3043 ** p2 -- the second string to check -- may be null.
3044 ** e -- the current envelope.
3045 ** flags -- control some behavior, see RSF_ in sendmail.h
3046 ** logl -- logging level.
3047 ** host -- NULL or relay host.
3048 ** logid -- id for sm_syslog.
3049 ** addr -- if not NULL and ruleset returns $#error:
3050 ** store mailer triple here.
3053 ** EX_OK -- if the rwset doesn't resolve to $#error
3054 ** else -- the failure status (message printed)
3058 rscheck(rwset
, p1
, p2
, e
, flags
, logl
, host
, logid
, addr
)
3072 int volatile rstat
= EX_OK
;
3075 bool volatile discard
= false;
3076 bool saveQuickAbort
= QuickAbort
;
3077 bool saveSuprErrs
= SuprErrs
;
3078 bool quarantine
= false;
3079 char ubuf
[BUFSIZ
* 2];
3081 char pvpbuf
[PSBUFSIZE
];
3082 extern char MsgBuf
[];
3085 sm_dprintf("rscheck(%s, %s, %s)\n", rwset
, p1
,
3086 p2
== NULL
? "(NULL)" : p2
);
3088 rsno
= strtorwset(rwset
, NULL
, ST_FIND
);
3094 bufsize
= strlen(p1
) + strlen(p2
) + 2;
3095 if (bufsize
> sizeof(buf0
))
3096 buf
= sm_malloc_x(bufsize
);
3100 bufsize
= sizeof(buf0
);
3102 (void) sm_snprintf(buf
, bufsize
, "%s%c%s", p1
, CONDELSE
, p2
);
3106 bufsize
= strlen(p1
) + 1;
3107 if (bufsize
> sizeof(buf0
))
3108 buf
= sm_malloc_x(bufsize
);
3112 bufsize
= sizeof(buf0
);
3114 (void) sm_strlcpy(buf
, p1
, bufsize
);
3120 pvp
= prescan(buf
, '\0', pvpbuf
, sizeof(pvpbuf
), NULL
,
3121 bitset(RSF_RMCOMM
, flags
) ?
3122 IntTokenTab
: TokTypeNoC
,
3123 bitset(RSF_RMCOMM
, flags
) ? false : true);
3124 SuprErrs
= saveSuprErrs
;
3128 sm_dprintf("rscheck: cannot prescan input\n");
3130 syserr("rscheck: cannot prescan input: \"%s\"",
3131 shortenstring(buf, MAXSHORTSTR));
3136 if (bitset(RSF_UNSTRUCTURED
, flags
))
3138 (void) REWRITE(pvp
, rsno
, e
);
3139 if (bitset(RSF_UNSTRUCTURED
, flags
))
3140 SuprErrs
= saveSuprErrs
;
3141 if (pvp
[0] == NULL
|| (pvp
[0][0] & 0377) != CANONNET
||
3142 pvp
[1] == NULL
|| (strcmp(pvp
[1], "error") != 0 &&
3143 strcmp(pvp
[1], "discard") != 0))
3148 if (strcmp(pvp
[1], "discard") == 0)
3151 sm_dprintf("rscheck: discard mailer selected\n");
3152 e
->e_flags
|= EF_DISCARD
;
3155 else if (strcmp(pvp
[1], "error") == 0 &&
3156 pvp
[2] != NULL
&& (pvp
[2][0] & 0377) == CANONHOST
&&
3157 pvp
[3] != NULL
&& strcmp(pvp
[3], "quarantine") == 0)
3159 if (pvp
[4] == NULL
||
3160 (pvp
[4][0] & 0377) != CANONUSER
||
3162 e
->e_quarmsg
= sm_rpool_strdup_x(e
->e_rpool
,
3166 cataddr(&(pvp
[5]), NULL
, ubuf
,
3167 sizeof(ubuf
), ' ', true);
3168 e
->e_quarmsg
= sm_rpool_strdup_x(e
->e_rpool
,
3171 macdefine(&e
->e_macro
, A_PERM
,
3172 macid("{quarantine}"), e
->e_quarmsg
);
3178 int savelogusrerrs
= LogUsrErrs
;
3179 static bool logged
= false;
3181 /* got an error -- process it */
3182 saveexitstat
= ExitStat
;
3184 (void) buildaddr(pvp
, &a1
, 0, e
);
3187 addr
->q_mailer
= a1
.q_mailer
;
3188 addr
->q_user
= a1
.q_user
;
3189 addr
->q_host
= a1
.q_host
;
3191 LogUsrErrs
= savelogusrerrs
;
3193 ExitStat
= saveexitstat
;
3196 if (bitset(RSF_COUNT
, flags
))
3197 markstats(e
, &a1
, STATS_REJECT
);
3202 if (LogLevel
> logl
)
3211 (void) sm_snprintf(p
, SPACELEFT(lbuf
, p
),
3220 relay
= macvalue('_', e
);
3223 (void) sm_snprintf(p
, SPACELEFT(lbuf
, p
),
3224 ", relay=%s", relay
);
3229 sm_syslog(LOG_NOTICE
, logid
,
3230 "ruleset=%s, arg1=%s%s, discard",
3232 else if (quarantine
)
3233 sm_syslog(LOG_NOTICE
, logid
,
3234 "ruleset=%s, arg1=%s%s, quarantine=%s",
3235 rwset
, p1
, lbuf
, ubuf
);
3237 sm_syslog(LOG_NOTICE
, logid
,
3238 "ruleset=%s, arg1=%s%s, reject=%s",
3239 rwset
, p1
, lbuf
, MsgBuf
);
3249 QuickAbort
= saveQuickAbort
;
3255 /* rulesets don't set errno */
3257 if (rstat
!= EX_OK
&& QuickAbort
)
3258 sm_exc_raisenew_x(&EtypeQuickAbort
, 2);
3262 ** RSCAP -- call rewriting set to return capabilities
3265 ** rwset -- the rewriting set to use.
3266 ** p1 -- the first string to check.
3267 ** p2 -- the second string to check -- may be null.
3268 ** e -- the current envelope.
3269 ** pvp -- pointer to token vector.
3270 ** pvpbuf -- buffer space.
3271 ** size -- size of buffer space.
3274 ** EX_UNAVAILABLE -- ruleset doesn't exist.
3275 ** EX_DATAERR -- prescan() failed.
3276 ** EX_OK -- rewrite() was successful.
3277 ** else -- return status from rewrite().
3281 rscap(rwset
, p1
, p2
, e
, pvp
, pvpbuf
, size
)
3292 int volatile rstat
= EX_OK
;
3294 bool saveQuickAbort
= QuickAbort
;
3295 bool saveSuprErrs
= SuprErrs
;
3297 extern char MsgBuf
[];
3300 sm_dprintf("rscap(%s, %s, %s)\n", rwset
, p1
,
3301 p2
== NULL
? "(NULL)" : p2
);
3303 SM_REQUIRE(pvp
!= NULL
);
3304 rsno
= strtorwset(rwset
, NULL
, ST_FIND
);
3306 return EX_UNAVAILABLE
;
3310 bufsize
= strlen(p1
) + strlen(p2
) + 2;
3311 if (bufsize
> sizeof(buf0
))
3312 buf
= sm_malloc_x(bufsize
);
3316 bufsize
= sizeof(buf0
);
3318 (void) sm_snprintf(buf
, bufsize
, "%s%c%s", p1
, CONDELSE
, p2
);
3322 bufsize
= strlen(p1
) + 1;
3323 if (bufsize
> sizeof(buf0
))
3324 buf
= sm_malloc_x(bufsize
);
3328 bufsize
= sizeof(buf0
);
3330 (void) sm_strlcpy(buf
, p1
, bufsize
);
3336 *pvp
= prescan(buf
, '\0', pvpbuf
, size
, NULL
, IntTokenTab
,
3339 rstat
= rewrite(*pvp
, rsno
, 0, e
, size
);
3343 sm_dprintf("rscap: cannot prescan input\n");
3352 SuprErrs
= saveSuprErrs
;
3353 QuickAbort
= saveQuickAbort
;
3355 /* prevent information leak, this may contain rewrite error */