1 /*
2 * Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14 #pragma ident "%Z%%M% %I% %E% SMI"
15
16 #include <sendmail.h>
17
18 SM_RCSID("@(#)$Id: parseaddr.c,v 8.403 2008/02/08 02:27:35 ca Exp $")
19
20 #include <sm/sendmail.h>
21 #include "map.h"
22
23 static void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *));
24 static int callsubr __P((char**, int, ENVELOPE *));
25 static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
26 static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
27 static bool hasctrlchar __P((register char *, bool, bool));
28
29 /* replacement for illegal characters in addresses */
30 #define BAD_CHAR_REPLACEMENT '?'
31
32 /*
33 ** PARSEADDR -- Parse an address
34 **
35 ** Parses an address and breaks it up into three parts: a
36 ** net to transmit the message on, the host to transmit it
37 ** to, and a user on that host. These are loaded into an
38 ** ADDRESS header with the values squirreled away if necessary.
39 ** The "user" part may not be a real user; the process may
40 ** just reoccur on that machine. For example, on a machine
41 ** with an arpanet connection, the address
42 ** csvax.bill@berkeley
43 ** will break up to a "user" of 'csvax.bill' and a host
44 ** of 'berkeley' -- to be transmitted over the arpanet.
45 **
46 ** Parameters:
47 ** addr -- the address to parse.
48 ** a -- a pointer to the address descriptor buffer.
49 ** If NULL, an address will be created.
50 ** flags -- describe detail for parsing. See RF_ definitions
51 ** in sendmail.h.
52 ** delim -- the character to terminate the address, passed
53 ** to prescan.
54 ** delimptr -- if non-NULL, set to the location of the
55 ** delim character that was found.
56 ** e -- the envelope that will contain this address.
57 ** isrcpt -- true if the address denotes a recipient; false
58 ** indicates a sender.
59 **
60 ** Returns:
61 ** A pointer to the address descriptor header (`a' if
62 ** `a' is non-NULL).
63 ** NULL on error.
64 **
65 ** Side Effects:
66 ** e->e_to = addr
67 */
68
69 /* following delimiters are inherent to the internal algorithms */
70 #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
71
72 ADDRESS *
parseaddr(addr,a,flags,delim,delimptr,e,isrcpt)73 parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
74 char *addr;
75 register ADDRESS *a;
76 int flags;
77 int delim;
78 char **delimptr;
79 register ENVELOPE *e;
80 bool isrcpt;
81 {
82 char **pvp;
83 auto char *delimptrbuf;
84 bool qup;
85 char pvpbuf[PSBUFSIZE];
86
87 /*
88 ** Initialize and prescan address.
89 */
90
91 e->e_to = addr;
92 if (tTd(20, 1))
93 sm_dprintf("\n--parseaddr(%s)\n", addr);
94
95 if (delimptr == NULL)
96 delimptr = &delimptrbuf;
97
98 pvp = prescan(addr, delim, pvpbuf, sizeof(pvpbuf), delimptr,
99 ExtTokenTab, false);
100 if (pvp == NULL)
101 {
102 if (tTd(20, 1))
103 sm_dprintf("parseaddr-->NULL\n");
104 return NULL;
105 }
106
107 if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt))
108 {
109 if (tTd(20, 1))
110 sm_dprintf("parseaddr-->bad address\n");
111 return NULL;
112 }
113
114 /*
115 ** Save addr if we are going to have to.
116 **
117 ** We have to do this early because there is a chance that
118 ** the map lookups in the rewriting rules could clobber
119 ** static memory somewhere.
120 */
121
122 if (bitset(RF_COPYPADDR, flags) && addr != NULL)
123 {
124 char savec = **delimptr;
125
126 if (savec != '\0')
127 **delimptr = '\0';
128 e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr);
129 if (savec != '\0')
130 **delimptr = savec;
131 }
132
133 /*
134 ** Apply rewriting rules.
135 ** Ruleset 0 does basic parsing. It must resolve.
136 */
137
138 qup = false;
139 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
140 qup = true;
141 if (REWRITE(pvp, 0, e) == EX_TEMPFAIL)
142 qup = true;
143
144 /*
145 ** Build canonical address from pvp.
146 */
147
148 a = buildaddr(pvp, a, flags, e);
149
150 if (hasctrlchar(a->q_user, isrcpt, true))
151 {
152 if (tTd(20, 1))
153 sm_dprintf("parseaddr-->bad q_user\n");
154
155 /*
156 ** Just mark the address as bad so DSNs work.
157 ** hasctrlchar() has to make sure that the address
158 ** has been sanitized, e.g., shortened.
159 */
160
161 a->q_state = QS_BADADDR;
162 }
163
164 /*
165 ** Make local copies of the host & user and then
166 ** transport them out.
167 */
168
169 allocaddr(a, flags, addr, e);
170 if (QS_IS_BADADDR(a->q_state))
171 {
172 /* weed out bad characters in the printable address too */
173 (void) hasctrlchar(a->q_paddr, isrcpt, false);
174 return a;
175 }
176
177 /*
178 ** Select a queue directory for recipient addresses.
179 ** This is done here and in split_across_queue_groups(),
180 ** but the latter applies to addresses after aliasing,
181 ** and only if splitting is done.
182 */
183
184 if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) &&
185 !bitset(RF_SENDERADDR|RF_HEADERADDR|RF_RM_ADDR, flags) &&
186 OpMode != MD_INITALIAS)
187 {
188 int r;
189
190 /* call ruleset which should return a queue group name */
191 r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf,
192 sizeof(pvpbuf));
193 if (r == EX_OK &&
194 pvp != NULL && pvp[0] != NULL &&
195 (pvp[0][0] & 0377) == CANONNET &&
196 pvp[1] != NULL && pvp[1][0] != '\0')
197 {
198 r = name2qid(pvp[1]);
199 if (r == NOQGRP && LogLevel > 10)
200 sm_syslog(LOG_INFO, NOQID,
201 "can't find queue group name %s, selection ignored",
202 pvp[1]);
203 if (tTd(20, 4) && r != NOQGRP)
204 sm_syslog(LOG_INFO, NOQID,
205 "queue group name %s -> %d",
206 pvp[1], r);
207 a->q_qgrp = r == NOQGRP ? ENVQGRP : r;
208 }
209 }
210
211 /*
212 ** If there was a parsing failure, mark it for queueing.
213 */
214
215 if (qup && OpMode != MD_INITALIAS)
216 {
217 char *msg = "Transient parse error -- message queued for future delivery";
218
219 if (e->e_sendmode == SM_DEFER)
220 msg = "Deferring message until queue run";
221 if (tTd(20, 1))
222 sm_dprintf("parseaddr: queueing message\n");
223 message(msg);
224 if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
225 e->e_message = sm_rpool_strdup_x(e->e_rpool, msg);
226 a->q_state = QS_QUEUEUP;
227 a->q_status = "4.4.3";
228 }
229
230 /*
231 ** Compute return value.
232 */
233
234 if (tTd(20, 1))
235 {
236 sm_dprintf("parseaddr-->");
237 printaddr(sm_debug_file(), a, false);
238 }
239
240 return a;
241 }
242 /*
243 ** INVALIDADDR -- check for address containing characters used for macros
244 **
245 ** Parameters:
246 ** addr -- the address to check.
247 ** delimptr -- if non-NULL: end of address to check, i.e.,
248 ** a pointer in the address string.
249 ** isrcpt -- true iff the address is for a recipient.
250 **
251 ** Returns:
252 ** true -- if the address has characters that are reservered
253 ** for macros or is too long.
254 ** false -- otherwise.
255 */
256
257 bool
invalidaddr(addr,delimptr,isrcpt)258 invalidaddr(addr, delimptr, isrcpt)
259 register char *addr;
260 char *delimptr;
261 bool isrcpt;
262 {
263 bool result = false;
264 char savedelim = '\0';
265 char *b = addr;
266 int len = 0;
267
268 if (delimptr != NULL)
269 {
270 /* delimptr points to the end of the address to test */
271 savedelim = *delimptr;
272 if (savedelim != '\0') /* if that isn't '\0' already: */
273 *delimptr = '\0'; /* set it */
274 }
275 for (; *addr != '\0'; addr++)
276 {
277 if (!EightBitAddrOK && (*addr & 0340) == 0200)
278 {
279 setstat(EX_USAGE);
280 result = true;
281 *addr = BAD_CHAR_REPLACEMENT;
282 }
283 if (++len > MAXNAME - 1)
284 {
285 char saved = *addr;
286
287 *addr = '\0';
288 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
289 b, MAXNAME - 1);
290 *addr = saved;
291 result = true;
292 goto delim;
293 }
294 }
295 if (result)
296 {
297 if (isrcpt)
298 usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"",
299 b);
300 else
301 usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"",
302 b);
303 }
304 delim:
305 if (delimptr != NULL && savedelim != '\0')
306 *delimptr = savedelim; /* restore old character at delimptr */
307 return result;
308 }
309 /*
310 ** HASCTRLCHAR -- check for address containing meta-characters
311 **
312 ** Checks that the address contains no meta-characters, and contains
313 ** no "non-printable" characters unless they are quoted or escaped.
314 ** Quoted or escaped characters are literals.
315 **
316 ** Parameters:
317 ** addr -- the address to check.
318 ** isrcpt -- true if the address is for a recipient; false
319 ** indicates a from.
320 ** complain -- true if an error should issued if the address
321 ** is invalid and should be "repaired".
322 **
323 ** Returns:
324 ** true -- if the address has any "wierd" characters or
325 ** non-printable characters or if a quote is unbalanced.
326 ** false -- otherwise.
327 */
328
329 static bool
hasctrlchar(addr,isrcpt,complain)330 hasctrlchar(addr, isrcpt, complain)
331 register char *addr;
332 bool isrcpt, complain;
333 {
334 bool quoted = false;
335 int len = 0;
336 char *result = NULL;
337 char *b = addr;
338
339 if (addr == NULL)
340 return false;
341 for (; *addr != '\0'; addr++)
342 {
343 if (++len > MAXNAME - 1)
344 {
345 if (complain)
346 {
347 (void) shorten_rfc822_string(b, MAXNAME - 1);
348 usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
349 b, MAXNAME - 1);
350 return true;
351 }
352 result = "too long";
353 }
354 if (!EightBitAddrOK && !quoted && (*addr < 32 || *addr == 127))
355 {
356 result = "non-printable character";
357 *addr = BAD_CHAR_REPLACEMENT;
358 continue;
359 }
360 if (*addr == '"')
361 quoted = !quoted;
362 else if (*addr == '\\')
363 {
364 /* XXX Generic problem: no '\0' in strings. */
365 if (*++addr == '\0')
366 {
367 result = "trailing \\ character";
368 *--addr = BAD_CHAR_REPLACEMENT;
369 break;
370 }
371 }
372 if (!EightBitAddrOK && (*addr & 0340) == 0200)
373 {
374 setstat(EX_USAGE);
375 result = "8-bit character";
376 *addr = BAD_CHAR_REPLACEMENT;
377 continue;
378 }
379 }
380 if (quoted)
381 result = "unbalanced quote"; /* unbalanced quote */
382 if (result != NULL && complain)
383 {
384 if (isrcpt)
385 usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)",
386 b, result);
387 else
388 usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)",
389 b, result);
390 }
391 return result != NULL;
392 }
393 /*
394 ** ALLOCADDR -- do local allocations of address on demand.
395 **
396 ** Also lowercases the host name if requested.
397 **
398 ** Parameters:
399 ** a -- the address to reallocate.
400 ** flags -- the copy flag (see RF_ definitions in sendmail.h
401 ** for a description).
402 ** paddr -- the printname of the address.
403 ** e -- envelope
404 **
405 ** Returns:
406 ** none.
407 **
408 ** Side Effects:
409 ** Copies portions of a into local buffers as requested.
410 */
411
412 static void
allocaddr(a,flags,paddr,e)413 allocaddr(a, flags, paddr, e)
414 register ADDRESS *a;
415 int flags;
416 char *paddr;
417 ENVELOPE *e;
418 {
419 if (tTd(24, 4))
420 sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
421
422 a->q_paddr = paddr;
423
424 if (a->q_user == NULL)
425 a->q_user = "";
426 if (a->q_host == NULL)
427 a->q_host = "";
428
429 if (bitset(RF_COPYPARSE, flags))
430 {
431 a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host);
432 if (a->q_user != a->q_paddr)
433 a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user);
434 }
435
436 if (a->q_paddr == NULL)
437 a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
438 a->q_qgrp = NOAQGRP;
439 }
440
441 /*
442 ** PRESCAN -- Prescan name and make it canonical
443 **
444 ** Scans a name and turns it into a set of tokens. This process
445 ** deletes blanks and comments (in parentheses) (if the token type
446 ** for left paren is SPC).
447 **
448 ** This routine knows about quoted strings and angle brackets.
449 **
450 ** There are certain subtleties to this routine. The one that
451 ** comes to mind now is that backslashes on the ends of names
452 ** are silently stripped off; this is intentional. The problem
453 ** is that some versions of sndmsg (like at LBL) set the kill
454 ** character to something other than @ when reading addresses;
455 ** so people type "csvax.eric\@berkeley" -- which screws up the
456 ** berknet mailer.
457 **
458 ** Parameters:
459 ** addr -- the name to chomp.
460 ** delim -- the delimiter for the address, normally
461 ** '\0' or ','; \0 is accepted in any case.
462 ** If '\t' then we are reading the .cf file.
463 ** pvpbuf -- place to put the saved text -- note that
464 ** the pointers are static.
465 ** pvpbsize -- size of pvpbuf.
466 ** delimptr -- if non-NULL, set to the location of the
467 ** terminating delimiter.
468 ** toktab -- if set, a token table to use for parsing.
469 ** If NULL, use the default table.
470 ** ignore -- if true, ignore unbalanced addresses
471 **
472 ** Returns:
473 ** A pointer to a vector of tokens.
474 ** NULL on error.
475 */
476
477 /* states and character types */
478 #define OPR 0 /* operator */
479 #define ATM 1 /* atom */
480 #define QST 2 /* in quoted string */
481 #define SPC 3 /* chewing up spaces */
482 #define ONE 4 /* pick up one character */
483 #define ILL 5 /* illegal character */
484
485 #define NSTATES 6 /* number of states */
486 #define TYPE 017 /* mask to select state type */
487
488 /* meta bits for table */
489 #define M 020 /* meta character; don't pass through */
490 #define B 040 /* cause a break */
491 #define MB M|B /* meta-break */
492
493 static short StateTab[NSTATES][NSTATES] =
494 {
495 /* oldst chtype> OPR ATM QST SPC ONE ILL */
496 /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB },
497 /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB },
498 /*QST*/ { QST, QST, OPR, QST, QST, QST },
499 /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB },
500 /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB },
501 /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }
502 };
503
504 /* these all get modified with the OperatorChars */
505
506 /* token type table for external strings */
507 unsigned char ExtTokenTab[256] =
508 {
509 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
510 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
511 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
512 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
513 /* sp ! " # $ % & ' ( ) * + , - . / */
514 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
515 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
516 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
517 /* @ A B C D E F G H I J K L M N O */
518 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
519 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
520 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
521 /* ` a b c d e f g h i j k l m n o */
522 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
523 /* p q r s t u v w x y z { | } ~ del */
524 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
525
526 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
527 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
528 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
529 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
530 /* sp ! " # $ % & ' ( ) * + , - . / */
531 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
532 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
533 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
534 /* @ A B C D E F G H I J K L M N O */
535 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
536 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
537 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
538 /* ` a b c d e f g h i j k l m n o */
539 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
540 /* p q r s t u v w x y z { | } ~ del */
541 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM
542 };
543
544 /* token type table for internal strings */
545 unsigned char IntTokenTab[256] =
546 {
547 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
548 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
549 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
550 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
551 /* sp ! " # $ % & ' ( ) * + , - . / */
552 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
553 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
554 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
555 /* @ A B C D E F G H I J K L M N O */
556 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
557 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
558 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
559 /* ` a b c d e f g h i j k l m n o */
560 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
561 /* p q r s t u v w x y z { | } ~ del */
562 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
563
564 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
565 OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
566 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
567 OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
568 /* sp ! " # $ % & ' ( ) * + , - . / */
569 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
570 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
571 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
572 /* @ A B C D E F G H I J K L M N O */
573 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
574 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
575 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
576 /* ` a b c d e f g h i j k l m n o */
577 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
578 /* p q r s t u v w x y z { | } ~ del */
579 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE
580 };
581
582 /* token type table for MIME parsing */
583 unsigned char MimeTokenTab[256] =
584 {
585 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
586 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
587 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
588 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
589 /* sp ! " # $ % & ' ( ) * + , - . / */
590 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
591 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
592 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
593 /* @ A B C D E F G H I J K L M N O */
594 OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
595 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
596 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
597 /* ` a b c d e f g h i j k l m n o */
598 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
599 /* p q r s t u v w x y z { | } ~ del */
600 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
601
602 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
603 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
604 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
605 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
606 /* sp ! " # $ % & ' ( ) * + , - . / */
607 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
608 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
609 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
610 /* @ A B C D E F G H I J K L M N O */
611 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
612 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
613 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
614 /* ` a b c d e f g h i j k l m n o */
615 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
616 /* p q r s t u v w x y z { | } ~ del */
617 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ONE
618 };
619
620 /* token type table: don't strip comments */
621 unsigned char TokTypeNoC[256] =
622 {
623 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
624 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
625 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
626 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
627 /* sp ! " # $ % & ' ( ) * + , - . / */
628 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM,
629 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
630 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
631 /* @ A B C D E F G H I J K L M N O */
632 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
633 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
634 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
635 /* ` a b c d e f g h i j k l m n o */
636 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
637 /* p q r s t u v w x y z { | } ~ del */
638 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
639
640 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
641 OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
642 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
643 OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
644 /* sp ! " # $ % & ' ( ) * + , - . / */
645 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
646 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
647 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
648 /* @ A B C D E F G H I J K L M N O */
649 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
650 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
651 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
652 /* ` a b c d e f g h i j k l m n o */
653 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
654 /* p q r s t u v w x y z { | } ~ del */
655 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE
656 };
657
658
659 #define NOCHAR (-1) /* signal nothing in lookahead token */
660
661 char **
prescan(addr,delim,pvpbuf,pvpbsize,delimptr,toktab,ignore)662 prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore)
663 char *addr;
664 int delim;
665 char pvpbuf[];
666 int pvpbsize;
667 char **delimptr;
668 unsigned char *toktab;
669 bool ignore;
670 {
671 register char *p;
672 register char *q;
673 register int c;
674 char **avp;
675 bool bslashmode;
676 bool route_syntax;
677 int cmntcnt;
678 int anglecnt;
679 char *tok;
680 int state;
681 int newstate;
682 char *saveto = CurEnv->e_to;
683 static char *av[MAXATOM + 1];
684 static bool firsttime = true;
685
686 if (firsttime)
687 {
688 /* initialize the token type table */
689 char obuf[50];
690
691 firsttime = false;
692 if (OperatorChars == NULL)
693 {
694 if (ConfigLevel < 7)
695 OperatorChars = macvalue('o', CurEnv);
696 if (OperatorChars == NULL)
697 OperatorChars = ".:@[]";
698 }
699 expand(OperatorChars, obuf, sizeof(obuf) - sizeof(DELIMCHARS),
700 CurEnv);
701 (void) sm_strlcat(obuf, DELIMCHARS, sizeof(obuf));
702 for (p = obuf; *p != '\0'; p++)
703 {
704 if (IntTokenTab[*p & 0xff] == ATM)
705 IntTokenTab[*p & 0xff] = OPR;
706 if (ExtTokenTab[*p & 0xff] == ATM)
707 ExtTokenTab[*p & 0xff] = OPR;
708 if (TokTypeNoC[*p & 0xff] == ATM)
709 TokTypeNoC[*p & 0xff] = OPR;
710 }
711 }
712 if (toktab == NULL)
713 toktab = ExtTokenTab;
714
715 /* make sure error messages don't have garbage on them */
716 errno = 0;
717
718 q = pvpbuf;
719 bslashmode = false;
720 route_syntax = false;
721 cmntcnt = 0;
722 anglecnt = 0;
723 avp = av;
724 state = ATM;
725 c = NOCHAR;
726 p = addr;
727 CurEnv->e_to = p;
728 if (tTd(22, 11))
729 {
730 sm_dprintf("prescan: ");
731 xputs(sm_debug_file(), p);
732 sm_dprintf("\n");
733 }
734
735 do
736 {
737 /* read a token */
738 tok = q;
739 for (;;)
740 {
741 /* store away any old lookahead character */
742 if (c != NOCHAR && !bslashmode)
743 {
744 /* see if there is room */
745 if (q >= &pvpbuf[pvpbsize - 5])
746 {
747 addrtoolong:
748 usrerr("553 5.1.1 Address too long");
749 if (strlen(addr) > MAXNAME)
750 addr[MAXNAME] = '\0';
751 returnnull:
752 if (delimptr != NULL)
753 {
754 if (p > addr)
755 --p;
756 *delimptr = p;
757 }
758 CurEnv->e_to = saveto;
759 return NULL;
760 }
761
762 /* squirrel it away */
763 #if !ALLOW_255
764 if ((char) c == (char) -1 && !tTd(82, 101) &&
765 !EightBitAddrOK)
766 c &= 0x7f;
767 #endif /* !ALLOW_255 */
768 *q++ = c;
769 }
770
771 /* read a new input character */
772 c = (*p++) & 0x00ff;
773 if (c == '\0')
774 {
775 /* diagnose and patch up bad syntax */
776 if (ignore)
777 break;
778 else if (state == QST)
779 {
780 usrerr("553 Unbalanced '\"'");
781 c = '"';
782 }
783 else if (cmntcnt > 0)
784 {
785 usrerr("553 Unbalanced '('");
786 c = ')';
787 }
788 else if (anglecnt > 0)
789 {
790 c = '>';
791 usrerr("553 Unbalanced '<'");
792 }
793 else
794 break;
795
796 p--;
797 }
798 else if (c == delim && cmntcnt <= 0 && state != QST)
799 {
800 if (anglecnt <= 0)
801 break;
802
803 /* special case for better error management */
804 if (delim == ',' && !route_syntax && !ignore)
805 {
806 usrerr("553 Unbalanced '<'");
807 c = '>';
808 p--;
809 }
810 }
811
812 if (tTd(22, 101))
813 sm_dprintf("c=%c, s=%d; ", c, state);
814
815 /* chew up special characters */
816 *q = '\0';
817 if (bslashmode)
818 {
819 bslashmode = false;
820
821 /* kludge \! for naive users */
822 if (cmntcnt > 0)
823 {
824 c = NOCHAR;
825 continue;
826 }
827 else if (c != '!' || state == QST)
828 {
829 /* see if there is room */
830 if (q >= &pvpbuf[pvpbsize - 5])
831 goto addrtoolong;
832 *q++ = '\\';
833 continue;
834 }
835 }
836
837 if (c == '\\')
838 {
839 bslashmode = true;
840 }
841 else if (state == QST)
842 {
843 /* EMPTY */
844 /* do nothing, just avoid next clauses */
845 }
846 else if (c == '(' && toktab['('] == SPC)
847 {
848 cmntcnt++;
849 c = NOCHAR;
850 }
851 else if (c == ')' && toktab['('] == SPC)
852 {
853 if (cmntcnt <= 0)
854 {
855 if (!ignore)
856 {
857 usrerr("553 Unbalanced ')'");
858 c = NOCHAR;
859 }
860 }
861 else
862 cmntcnt--;
863 }
864 else if (cmntcnt > 0)
865 {
866 c = NOCHAR;
867 }
868 else if (c == '<')
869 {
870 char *ptr = p;
871
872 anglecnt++;
873 while (isascii(*ptr) && isspace(*ptr))
874 ptr++;
875 if (*ptr == '@')
876 route_syntax = true;
877 }
878 else if (c == '>')
879 {
880 if (anglecnt <= 0)
881 {
882 if (!ignore)
883 {
884 usrerr("553 Unbalanced '>'");
885 c = NOCHAR;
886 }
887 }
888 else
889 anglecnt--;
890 route_syntax = false;
891 }
892 else if (delim == ' ' && isascii(c) && isspace(c))
893 c = ' ';
894
895 if (c == NOCHAR)
896 continue;
897
898 /* see if this is end of input */
899 if (c == delim && anglecnt <= 0 && state != QST)
900 break;
901
902 newstate = StateTab[state][toktab[c & 0xff]];
903 if (tTd(22, 101))
904 sm_dprintf("ns=%02o\n", newstate);
905 state = newstate & TYPE;
906 if (state == ILL)
907 {
908 if (isascii(c) && isprint(c))
909 usrerr("553 Illegal character %c", c);
910 else
911 usrerr("553 Illegal character 0x%02x",
912 c & 0x0ff);
913 }
914 if (bitset(M, newstate))
915 c = NOCHAR;
916 if (bitset(B, newstate))
917 break;
918 }
919
920 /* new token */
921 if (tok != q)
922 {
923 /* see if there is room */
924 if (q >= &pvpbuf[pvpbsize - 5])
925 goto addrtoolong;
926 *q++ = '\0';
927 if (tTd(22, 36))
928 {
929 sm_dprintf("tok=");
930 xputs(sm_debug_file(), tok);
931 sm_dprintf("\n");
932 }
933 if (avp >= &av[MAXATOM])
934 {
935 usrerr("553 5.1.0 prescan: too many tokens");
936 goto returnnull;
937 }
938 if (q - tok > MAXNAME)
939 {
940 usrerr("553 5.1.0 prescan: token too long");
941 goto returnnull;
942 }
943 *avp++ = tok;
944 }
945 } while (c != '\0' && (c != delim || anglecnt > 0));
946 *avp = NULL;
947 if (delimptr != NULL)
948 {
949 if (p > addr)
950 p--;
951 *delimptr = p;
952 }
953 if (tTd(22, 12))
954 {
955 sm_dprintf("prescan==>");
956 printav(sm_debug_file(), av);
957 }
958 CurEnv->e_to = saveto;
959 if (av[0] == NULL)
960 {
961 if (tTd(22, 1))
962 sm_dprintf("prescan: null leading token\n");
963 return NULL;
964 }
965 return av;
966 }
967 /*
968 ** REWRITE -- apply rewrite rules to token vector.
969 **
970 ** This routine is an ordered production system. Each rewrite
971 ** rule has a LHS (called the pattern) and a RHS (called the
972 ** rewrite); 'rwr' points the the current rewrite rule.
973 **
974 ** For each rewrite rule, 'avp' points the address vector we
975 ** are trying to match against, and 'pvp' points to the pattern.
976 ** If pvp points to a special match value (MATCHZANY, MATCHANY,
977 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
978 ** matched is saved away in the match vector (pointed to by 'mvp').
979 **
980 ** When a match between avp & pvp does not match, we try to
981 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
982 ** we must also back out the match in mvp. If we reach a
983 ** MATCHANY or MATCHZANY we just extend the match and start
984 ** over again.
985 **
986 ** When we finally match, we rewrite the address vector
987 ** and try over again.
988 **
989 ** Parameters:
990 ** pvp -- pointer to token vector.
991 ** ruleset -- the ruleset to use for rewriting.
992 ** reclevel -- recursion level (to catch loops).
993 ** e -- the current envelope.
994 ** maxatom -- maximum length of buffer (usually MAXATOM)
995 **
996 ** Returns:
997 ** A status code. If EX_TEMPFAIL, higher level code should
998 ** attempt recovery.
999 **
1000 ** Side Effects:
1001 ** pvp is modified.
1002 */
1003
1004 struct match
1005 {
1006 char **match_first; /* first token matched */
1007 char **match_last; /* last token matched */
1008 char **match_pattern; /* pointer to pattern */
1009 };
1010
1011 int
rewrite(pvp,ruleset,reclevel,e,maxatom)1012 rewrite(pvp, ruleset, reclevel, e, maxatom)
1013 char **pvp;
1014 int ruleset;
1015 int reclevel;
1016 register ENVELOPE *e;
1017 int maxatom;
1018 {
1019 register char *ap; /* address pointer */
1020 register char *rp; /* rewrite pointer */
1021 register char *rulename; /* ruleset name */
1022 register char *prefix;
1023 register char **avp; /* address vector pointer */
1024 register char **rvp; /* rewrite vector pointer */
1025 register struct match *mlp; /* cur ptr into mlist */
1026 register struct rewrite *rwr; /* pointer to current rewrite rule */
1027 int ruleno; /* current rule number */
1028 int rstat = EX_OK; /* return status */
1029 int loopcount;
1030 struct match mlist[MAXMATCH]; /* stores match on LHS */
1031 char *npvp[MAXATOM + 1]; /* temporary space for rebuild */
1032 char buf[MAXLINE];
1033 char name[6];
1034
1035 /*
1036 ** mlp will not exceed mlist[] because readcf enforces
1037 ** the upper limit of entries when reading rulesets.
1038 */
1039
1040 if (ruleset < 0 || ruleset >= MAXRWSETS)
1041 {
1042 syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset);
1043 return EX_CONFIG;
1044 }
1045 rulename = RuleSetNames[ruleset];
1046 if (rulename == NULL)
1047 {
1048 (void) sm_snprintf(name, sizeof(name), "%d", ruleset);
1049 rulename = name;
1050 }
1051 if (OpMode == MD_TEST)
1052 prefix = "";
1053 else
1054 prefix = "rewrite: ruleset ";
1055 if (OpMode == MD_TEST)
1056 {
1057 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1058 "%s%-16.16s input:", prefix, rulename);
1059 printav(smioout, pvp);
1060 }
1061 else if (tTd(21, 1))
1062 {
1063 sm_dprintf("%s%-16.16s input:", prefix, rulename);
1064 printav(sm_debug_file(), pvp);
1065 }
1066 if (reclevel++ > MaxRuleRecursion)
1067 {
1068 syserr("rewrite: excessive recursion (max %d), ruleset %s",
1069 MaxRuleRecursion, rulename);
1070 return EX_CONFIG;
1071 }
1072 if (pvp == NULL)
1073 return EX_USAGE;
1074 if (maxatom <= 0)
1075 return EX_USAGE;
1076
1077 /*
1078 ** Run through the list of rewrite rules, applying
1079 ** any that match.
1080 */
1081
1082 ruleno = 1;
1083 loopcount = 0;
1084 for (rwr = RewriteRules[ruleset]; rwr != NULL; )
1085 {
1086 int status;
1087
1088 /* if already canonical, quit now */
1089 if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET)
1090 break;
1091
1092 if (tTd(21, 12))
1093 {
1094 if (tTd(21, 15))
1095 sm_dprintf("-----trying rule (line %d):",
1096 rwr->r_line);
1097 else
1098 sm_dprintf("-----trying rule:");
1099 printav(sm_debug_file(), rwr->r_lhs);
1100 }
1101
1102 /* try to match on this rule */
1103 mlp = mlist;
1104 rvp = rwr->r_lhs;
1105 avp = pvp;
1106 if (++loopcount > 100)
1107 {
1108 syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
1109 rulename, ruleno);
1110 if (tTd(21, 1))
1111 {
1112 sm_dprintf("workspace: ");
1113 printav(sm_debug_file(), pvp);
1114 }
1115 break;
1116 }
1117
1118 while ((ap = *avp) != NULL || *rvp != NULL)
1119 {
1120 rp = *rvp;
1121 if (tTd(21, 35))
1122 {
1123 sm_dprintf("ADVANCE rp=");
1124 xputs(sm_debug_file(), rp);
1125 sm_dprintf(", ap=");
1126 xputs(sm_debug_file(), ap);
1127 sm_dprintf("\n");
1128 }
1129 if (rp == NULL)
1130 {
1131 /* end-of-pattern before end-of-address */
1132 goto backup;
1133 }
1134 if (ap == NULL &&
1135 (rp[0] & 0377) != MATCHZANY &&
1136 (rp[0] & 0377) != MATCHZERO)
1137 {
1138 /* end-of-input with patterns left */
1139 goto backup;
1140 }
1141
1142 switch (rp[0] & 0377)
1143 {
1144 case MATCHCLASS:
1145 /* match any phrase in a class */
1146 mlp->match_pattern = rvp;
1147 mlp->match_first = avp;
1148 extendclass:
1149 ap = *avp;
1150 if (ap == NULL)
1151 goto backup;
1152 mlp->match_last = avp++;
1153 cataddr(mlp->match_first, mlp->match_last,
1154 buf, sizeof(buf), '\0', true);
1155 if (!wordinclass(buf, rp[1]))
1156 {
1157 if (tTd(21, 36))
1158 {
1159 sm_dprintf("EXTEND rp=");
1160 xputs(sm_debug_file(), rp);
1161 sm_dprintf(", ap=");
1162 xputs(sm_debug_file(), ap);
1163 sm_dprintf("\n");
1164 }
1165 goto extendclass;
1166 }
1167 if (tTd(21, 36))
1168 sm_dprintf("CLMATCH\n");
1169 mlp++;
1170 break;
1171
1172 case MATCHNCLASS:
1173 /* match any token not in a class */
1174 if (wordinclass(ap, rp[1]))
1175 goto backup;
1176
1177 /* FALLTHROUGH */
1178
1179 case MATCHONE:
1180 case MATCHANY:
1181 /* match exactly one token */
1182 mlp->match_pattern = rvp;
1183 mlp->match_first = avp;
1184 mlp->match_last = avp++;
1185 mlp++;
1186 break;
1187
1188 case MATCHZANY:
1189 /* match zero or more tokens */
1190 mlp->match_pattern = rvp;
1191 mlp->match_first = avp;
1192 mlp->match_last = avp - 1;
1193 mlp++;
1194 break;
1195
1196 case MATCHZERO:
1197 /* match zero tokens */
1198 break;
1199
1200 case MACRODEXPAND:
1201 /*
1202 ** Match against run-time macro.
1203 ** This algorithm is broken for the
1204 ** general case (no recursive macros,
1205 ** improper tokenization) but should
1206 ** work for the usual cases.
1207 */
1208
1209 ap = macvalue(rp[1], e);
1210 mlp->match_first = avp;
1211 if (tTd(21, 2))
1212 sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n",
1213 macname(rp[1]),
1214 ap == NULL ? "(NULL)" : ap);
1215
1216 if (ap == NULL)
1217 break;
1218 while (*ap != '\0')
1219 {
1220 if (*avp == NULL ||
1221 sm_strncasecmp(ap, *avp,
1222 strlen(*avp)) != 0)
1223 {
1224 /* no match */
1225 avp = mlp->match_first;
1226 goto backup;
1227 }
1228 ap += strlen(*avp++);
1229 }
1230
1231 /* match */
1232 break;
1233
1234 default:
1235 /* must have exact match */
1236 if (sm_strcasecmp(rp, ap))
1237 goto backup;
1238 avp++;
1239 break;
1240 }
1241
1242 /* successful match on this token */
1243 rvp++;
1244 continue;
1245
1246 backup:
1247 /* match failed -- back up */
1248 while (--mlp >= mlist)
1249 {
1250 rvp = mlp->match_pattern;
1251 rp = *rvp;
1252 avp = mlp->match_last + 1;
1253 ap = *avp;
1254
1255 if (tTd(21, 36))
1256 {
1257 sm_dprintf("BACKUP rp=");
1258 xputs(sm_debug_file(), rp);
1259 sm_dprintf(", ap=");
1260 xputs(sm_debug_file(), ap);
1261 sm_dprintf("\n");
1262 }
1263
1264 if (ap == NULL)
1265 {
1266 /* run off the end -- back up again */
1267 continue;
1268 }
1269
1270 if ((rp[0] & 0377) == MATCHANY ||
1271 (rp[0] & 0377) == MATCHZANY)
1272 {
1273 /* extend binding and continue */
1274 mlp->match_last = avp++;
1275 rvp++;
1276 mlp++;
1277 break;
1278 }
1279 if ((rp[0] & 0377) == MATCHCLASS)
1280 {
1281 /* extend binding and try again */
1282 mlp->match_last = avp;
1283 goto extendclass;
1284 }
1285 }
1286
1287 if (mlp < mlist)
1288 {
1289 /* total failure to match */
1290 break;
1291 }
1292 }
1293
1294 /*
1295 ** See if we successfully matched
1296 */
1297
1298 if (mlp < mlist || *rvp != NULL)
1299 {
1300 if (tTd(21, 10))
1301 sm_dprintf("----- rule fails\n");
1302 rwr = rwr->r_next;
1303 ruleno++;
1304 loopcount = 0;
1305 continue;
1306 }
1307
1308 rvp = rwr->r_rhs;
1309 if (tTd(21, 12))
1310 {
1311 sm_dprintf("-----rule matches:");
1312 printav(sm_debug_file(), rvp);
1313 }
1314
1315 rp = *rvp;
1316 if (rp != NULL)
1317 {
1318 if ((rp[0] & 0377) == CANONUSER)
1319 {
1320 rvp++;
1321 rwr = rwr->r_next;
1322 ruleno++;
1323 loopcount = 0;
1324 }
1325 else if ((rp[0] & 0377) == CANONHOST)
1326 {
1327 rvp++;
1328 rwr = NULL;
1329 }
1330 }
1331
1332 /* substitute */
1333 for (avp = npvp; *rvp != NULL; rvp++)
1334 {
1335 register struct match *m;
1336 register char **pp;
1337
1338 rp = *rvp;
1339 if ((rp[0] & 0377) == MATCHREPL)
1340 {
1341 /* substitute from LHS */
1342 m = &mlist[rp[1] - '1'];
1343 if (m < mlist || m >= mlp)
1344 {
1345 syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
1346 rulename, rp[1]);
1347 return EX_CONFIG;
1348 }
1349 if (tTd(21, 15))
1350 {
1351 sm_dprintf("$%c:", rp[1]);
1352 pp = m->match_first;
1353 while (pp <= m->match_last)
1354 {
1355 sm_dprintf(" %p=\"", *pp);
1356 sm_dflush();
1357 sm_dprintf("%s\"", *pp++);
1358 }
1359 sm_dprintf("\n");
1360 }
1361 pp = m->match_first;
1362 while (pp <= m->match_last)
1363 {
1364 if (avp >= &npvp[maxatom])
1365 goto toolong;
1366 *avp++ = *pp++;
1367 }
1368 }
1369 else
1370 {
1371 /* some sort of replacement */
1372 if (avp >= &npvp[maxatom])
1373 {
1374 toolong:
1375 syserr("554 5.3.0 rewrite: expansion too long");
1376 if (LogLevel > 9)
1377 sm_syslog(LOG_ERR, e->e_id,
1378 "rewrite: expansion too long, ruleset=%s, ruleno=%d",
1379 rulename, ruleno);
1380 return EX_DATAERR;
1381 }
1382 if ((rp[0] & 0377) != MACRODEXPAND)
1383 {
1384 /* vanilla replacement from RHS */
1385 *avp++ = rp;
1386 }
1387 else
1388 {
1389 /* $&{x} replacement */
1390 char *mval = macvalue(rp[1], e);
1391 char **xpvp;
1392 size_t trsize = 0;
1393 static size_t pvpb1_size = 0;
1394 static char **pvpb1 = NULL;
1395 char pvpbuf[PSBUFSIZE];
1396
1397 if (tTd(21, 2))
1398 sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n",
1399 macname(rp[1]),
1400 mval == NULL ? "(NULL)" : mval);
1401 if (mval == NULL || *mval == '\0')
1402 continue;
1403
1404 /* save the remainder of the input */
1405 for (xpvp = pvp; *xpvp != NULL; xpvp++)
1406 trsize += sizeof(*xpvp);
1407 if (trsize > pvpb1_size)
1408 {
1409 if (pvpb1 != NULL)
1410 sm_free(pvpb1);
1411 pvpb1 = (char **)
1412 sm_pmalloc_x(trsize);
1413 pvpb1_size = trsize;
1414 }
1415
1416 memmove((char *) pvpb1,
1417 (char *) pvp,
1418 trsize);
1419
1420 /* scan the new replacement */
1421 xpvp = prescan(mval, '\0', pvpbuf,
1422 sizeof(pvpbuf), NULL,
1423 NULL, false);
1424 if (xpvp == NULL)
1425 {
1426 /* prescan pre-printed error */
1427 return EX_DATAERR;
1428 }
1429
1430 /* insert it into the output stream */
1431 while (*xpvp != NULL)
1432 {
1433 if (tTd(21, 19))
1434 sm_dprintf(" ... %s\n",
1435 *xpvp);
1436 *avp++ = sm_rpool_strdup_x(
1437 e->e_rpool, *xpvp);
1438 if (avp >= &npvp[maxatom])
1439 goto toolong;
1440 xpvp++;
1441 }
1442 if (tTd(21, 19))
1443 sm_dprintf(" ... DONE\n");
1444
1445 /* restore the old trailing input */
1446 memmove((char *) pvp,
1447 (char *) pvpb1,
1448 trsize);
1449 }
1450 }
1451 }
1452 *avp++ = NULL;
1453
1454 /*
1455 ** Check for any hostname/keyword lookups.
1456 */
1457
1458 for (rvp = npvp; *rvp != NULL; rvp++)
1459 {
1460 char **hbrvp;
1461 char **xpvp;
1462 size_t trsize;
1463 char *replac;
1464 int endtoken;
1465 bool external;
1466 STAB *map;
1467 char *mapname;
1468 char **key_rvp;
1469 char **arg_rvp;
1470 char **default_rvp;
1471 char cbuf[MAXKEY];
1472 char *pvpb1[MAXATOM + 1];
1473 char *argvect[MAX_MAP_ARGS];
1474 char pvpbuf[PSBUFSIZE];
1475 char *nullpvp[1];
1476
1477 hbrvp = rvp;
1478 if ((rvp[0][0] & 0377) == HOSTBEGIN)
1479 {
1480 endtoken = HOSTEND;
1481 mapname = "host";
1482 }
1483 else if ((rvp[0][0] & 0377) == LOOKUPBEGIN)
1484 {
1485 endtoken = LOOKUPEND;
1486 mapname = *++rvp;
1487 if (mapname == NULL)
1488 {
1489 syserr("554 5.3.0 rewrite: missing mapname");
1490 /* NOTREACHED */
1491 SM_ASSERT(0);
1492 }
1493 }
1494 else
1495 continue;
1496
1497 /*
1498 ** Got a hostname/keyword lookup.
1499 **
1500 ** This could be optimized fairly easily.
1501 */
1502
1503 map = stab(mapname, ST_MAP, ST_FIND);
1504 if (map == NULL)
1505 syserr("554 5.3.0 rewrite: map %s not found",
1506 mapname);
1507
1508 /* extract the match part */
1509 key_rvp = ++rvp;
1510 if (key_rvp == NULL)
1511 {
1512 syserr("554 5.3.0 rewrite: missing key for map %s",
1513 mapname);
1514 /* NOTREACHED */
1515 SM_ASSERT(0);
1516 }
1517 default_rvp = NULL;
1518 arg_rvp = argvect;
1519 xpvp = NULL;
1520 replac = pvpbuf;
1521 while (*rvp != NULL && ((rvp[0][0] & 0377) != endtoken))
1522 {
1523 int nodetype = rvp[0][0] & 0377;
1524
1525 if (nodetype != CANONHOST &&
1526 nodetype != CANONUSER)
1527 {
1528 rvp++;
1529 continue;
1530 }
1531
1532 *rvp++ = NULL;
1533
1534 if (xpvp != NULL)
1535 {
1536 cataddr(xpvp, NULL, replac,
1537 &pvpbuf[sizeof(pvpbuf)] - replac,
1538 '\0', false);
1539 if (arg_rvp <
1540 &argvect[MAX_MAP_ARGS - 1])
1541 *++arg_rvp = replac;
1542 replac += strlen(replac) + 1;
1543 xpvp = NULL;
1544 }
1545 switch (nodetype)
1546 {
1547 case CANONHOST:
1548 xpvp = rvp;
1549 break;
1550
1551 case CANONUSER:
1552 default_rvp = rvp;
1553 break;
1554 }
1555 }
1556 if (*rvp != NULL)
1557 *rvp++ = NULL;
1558 if (xpvp != NULL)
1559 {
1560 cataddr(xpvp, NULL, replac,
1561 &pvpbuf[sizeof(pvpbuf)] - replac,
1562 '\0', false);
1563 if (arg_rvp < &argvect[MAX_MAP_ARGS - 1])
1564 *++arg_rvp = replac;
1565 }
1566 if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1])
1567 argvect[MAX_MAP_ARGS - 1] = NULL;
1568 else
1569 *++arg_rvp = NULL;
1570
1571 /* save the remainder of the input string */
1572 trsize = (avp - rvp + 1) * sizeof(*rvp);
1573 memmove((char *) pvpb1, (char *) rvp, trsize);
1574
1575 /* look it up */
1576 cataddr(key_rvp, NULL, cbuf, sizeof(cbuf),
1577 map == NULL ? '\0' : map->s_map.map_spacesub,
1578 true);
1579 argvect[0] = cbuf;
1580 replac = map_lookup(map, cbuf, argvect, &rstat, e);
1581 external = replac != NULL;
1582
1583 /* if no replacement, use default */
1584 if (replac == NULL && default_rvp != NULL)
1585 {
1586 /* create the default */
1587 cataddr(default_rvp, NULL, cbuf, sizeof(cbuf),
1588 '\0', false);
1589 replac = cbuf;
1590 }
1591
1592 if (replac == NULL)
1593 {
1594 xpvp = key_rvp;
1595 }
1596 else if (*replac == '\0')
1597 {
1598 /* null replacement */
1599 nullpvp[0] = NULL;
1600 xpvp = nullpvp;
1601 }
1602 else
1603 {
1604 /* scan the new replacement */
1605 xpvp = prescan(replac, '\0', pvpbuf,
1606 sizeof(pvpbuf), NULL,
1607 external ? NULL : IntTokenTab,
1608 false);
1609 if (xpvp == NULL)
1610 {
1611 /* prescan already printed error */
1612 return EX_DATAERR;
1613 }
1614 }
1615
1616 /* append it to the token list */
1617 for (avp = hbrvp; *xpvp != NULL; xpvp++)
1618 {
1619 *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp);
1620 if (avp >= &npvp[maxatom])
1621 goto toolong;
1622 }
1623
1624 /* restore the old trailing information */
1625 rvp = avp - 1;
1626 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
1627 if (avp >= &npvp[maxatom])
1628 goto toolong;
1629 }
1630
1631 /*
1632 ** Check for subroutine calls.
1633 */
1634
1635 status = callsubr(npvp, reclevel, e);
1636 if (rstat == EX_OK || status == EX_TEMPFAIL)
1637 rstat = status;
1638
1639 /* copy vector back into original space. */
1640 for (avp = npvp; *avp++ != NULL;)
1641 continue;
1642 memmove((char *) pvp, (char *) npvp,
1643 (int) (avp - npvp) * sizeof(*avp));
1644
1645 if (tTd(21, 4))
1646 {
1647 sm_dprintf("rewritten as:");
1648 printav(sm_debug_file(), pvp);
1649 }
1650 }
1651
1652 if (OpMode == MD_TEST)
1653 {
1654 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
1655 "%s%-16.16s returns:", prefix, rulename);
1656 printav(smioout, pvp);
1657 }
1658 else if (tTd(21, 1))
1659 {
1660 sm_dprintf("%s%-16.16s returns:", prefix, rulename);
1661 printav(sm_debug_file(), pvp);
1662 }
1663 return rstat;
1664 }
1665 /*
1666 ** CALLSUBR -- call subroutines in rewrite vector
1667 **
1668 ** Parameters:
1669 ** pvp -- pointer to token vector.
1670 ** reclevel -- the current recursion level.
1671 ** e -- the current envelope.
1672 **
1673 ** Returns:
1674 ** The status from the subroutine call.
1675 **
1676 ** Side Effects:
1677 ** pvp is modified.
1678 */
1679
1680 static int
callsubr(pvp,reclevel,e)1681 callsubr(pvp, reclevel, e)
1682 char **pvp;
1683 int reclevel;
1684 ENVELOPE *e;
1685 {
1686 char **avp;
1687 register int i;
1688 int subr, j;
1689 int nsubr;
1690 int status;
1691 int rstat = EX_OK;
1692 #define MAX_SUBR 16
1693 int subrnumber[MAX_SUBR];
1694 int subrindex[MAX_SUBR];
1695
1696 nsubr = 0;
1697
1698 /*
1699 ** Look for subroutine calls in pvp, collect them into subr*[]
1700 ** We will perform the calls in the next loop, because we will
1701 ** call the "last" subroutine first to avoid recursive calls
1702 ** and too much copying.
1703 */
1704
1705 for (avp = pvp, j = 0; *avp != NULL; avp++, j++)
1706 {
1707 if ((avp[0][0] & 0377) == CALLSUBR && avp[1] != NULL)
1708 {
1709 stripquotes(avp[1]);
1710 subr = strtorwset(avp[1], NULL, ST_FIND);
1711 if (subr < 0)
1712 {
1713 syserr("554 5.3.5 Unknown ruleset %s", avp[1]);
1714 return EX_CONFIG;
1715 }
1716
1717 /*
1718 ** XXX instead of doing this we could optimize
1719 ** the rules after reading them: just remove
1720 ** calls to empty rulesets
1721 */
1722
1723 /* subroutine is an empty ruleset? don't call it */
1724 if (RewriteRules[subr] == NULL)
1725 {
1726 if (tTd(21, 3))
1727 sm_dprintf("-----skip subr %s (%d)\n",
1728 avp[1], subr);
1729 for (i = 2; avp[i] != NULL; i++)
1730 avp[i - 2] = avp[i];
1731 avp[i - 2] = NULL;
1732 continue;
1733 }
1734 if (++nsubr >= MAX_SUBR)
1735 {
1736 syserr("554 5.3.0 Too many subroutine calls (%d max)",
1737 MAX_SUBR);
1738 return EX_CONFIG;
1739 }
1740 subrnumber[nsubr] = subr;
1741 subrindex[nsubr] = j;
1742 }
1743 }
1744
1745 /*
1746 ** Perform the actual subroutines calls, "last" one first, i.e.,
1747 ** go from the right to the left through all calls,
1748 ** do the rewriting in place.
1749 */
1750
1751 for (; nsubr > 0; nsubr--)
1752 {
1753 subr = subrnumber[nsubr];
1754 avp = pvp + subrindex[nsubr];
1755
1756 /* remove the subroutine call and name */
1757 for (i = 2; avp[i] != NULL; i++)
1758 avp[i - 2] = avp[i];
1759 avp[i - 2] = NULL;
1760
1761 /*
1762 ** Now we need to call the ruleset specified for
1763 ** the subroutine. We can do this in place since
1764 ** we call the "last" subroutine first.
1765 */
1766
1767 status = rewrite(avp, subr, reclevel, e,
1768 MAXATOM - subrindex[nsubr]);
1769 if (status != EX_OK && status != EX_TEMPFAIL)
1770 return status;
1771 if (rstat == EX_OK || status == EX_TEMPFAIL)
1772 rstat = status;
1773 }
1774 return rstat;
1775 }
1776 /*
1777 ** MAP_LOOKUP -- do lookup in map
1778 **
1779 ** Parameters:
1780 ** smap -- the map to use for the lookup.
1781 ** key -- the key to look up.
1782 ** argvect -- arguments to pass to the map lookup.
1783 ** pstat -- a pointer to an integer in which to store the
1784 ** status from the lookup.
1785 ** e -- the current envelope.
1786 **
1787 ** Returns:
1788 ** The result of the lookup.
1789 ** NULL -- if there was no data for the given key.
1790 */
1791
1792 static char *
map_lookup(smap,key,argvect,pstat,e)1793 map_lookup(smap, key, argvect, pstat, e)
1794 STAB *smap;
1795 char key[];
1796 char **argvect;
1797 int *pstat;
1798 ENVELOPE *e;
1799 {
1800 auto int status = EX_OK;
1801 MAP *map;
1802 char *replac;
1803
1804 if (smap == NULL)
1805 return NULL;
1806
1807 map = &smap->s_map;
1808 DYNOPENMAP(map);
1809
1810 if (e->e_sendmode == SM_DEFER &&
1811 bitset(MF_DEFER, map->map_mflags))
1812 {
1813 /* don't do any map lookups */
1814 if (tTd(60, 1))
1815 sm_dprintf("map_lookup(%s, %s) => DEFERRED\n",
1816 smap->s_name, key);
1817 *pstat = EX_TEMPFAIL;
1818 return NULL;
1819 }
1820
1821 if (!bitset(MF_KEEPQUOTES, map->map_mflags))
1822 stripquotes(key);
1823
1824 if (tTd(60, 1))
1825 {
1826 sm_dprintf("map_lookup(%s, ", smap->s_name);
1827 xputs(sm_debug_file(), key);
1828 if (tTd(60, 5))
1829 {
1830 int i;
1831
1832 for (i = 0; argvect[i] != NULL; i++)
1833 sm_dprintf(", %%%d=%s", i, argvect[i]);
1834 }
1835 sm_dprintf(") => ");
1836 }
1837 replac = (*map->map_class->map_lookup)(map, key, argvect, &status);
1838 if (tTd(60, 1))
1839 sm_dprintf("%s (%d)\n",
1840 replac != NULL ? replac : "NOT FOUND",
1841 status);
1842
1843 /* should recover if status == EX_TEMPFAIL */
1844 if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags))
1845 {
1846 *pstat = EX_TEMPFAIL;
1847 if (tTd(60, 1))
1848 sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
1849 smap->s_name, key, errno);
1850 if (e->e_message == NULL)
1851 {
1852 char mbuf[320];
1853
1854 (void) sm_snprintf(mbuf, sizeof(mbuf),
1855 "%.80s map: lookup (%s): deferred",
1856 smap->s_name,
1857 shortenstring(key, MAXSHORTSTR));
1858 e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf);
1859 }
1860 }
1861 if (status == EX_TEMPFAIL && map->map_tapp != NULL)
1862 {
1863 size_t i = strlen(key) + strlen(map->map_tapp) + 1;
1864 static char *rwbuf = NULL;
1865 static size_t rwbuflen = 0;
1866
1867 if (i > rwbuflen)
1868 {
1869 if (rwbuf != NULL)
1870 sm_free(rwbuf);
1871 rwbuflen = i;
1872 rwbuf = (char *) sm_pmalloc_x(rwbuflen);
1873 }
1874 (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp);
1875 if (tTd(60, 4))
1876 sm_dprintf("map_lookup tempfail: returning \"%s\"\n",
1877 rwbuf);
1878 return rwbuf;
1879 }
1880 return replac;
1881 }
1882 /*
1883 ** INITERRMAILERS -- initialize error and discard mailers
1884 **
1885 ** Parameters:
1886 ** none.
1887 **
1888 ** Returns:
1889 ** none.
1890 **
1891 ** Side Effects:
1892 ** initializes error and discard mailers.
1893 */
1894
1895 static MAILER discardmailer;
1896 static MAILER errormailer;
1897 static char *discardargv[] = { "DISCARD", NULL };
1898 static char *errorargv[] = { "ERROR", NULL };
1899
1900 void
initerrmailers()1901 initerrmailers()
1902 {
1903 if (discardmailer.m_name == NULL)
1904 {
1905 /* initialize the discard mailer */
1906 discardmailer.m_name = "*discard*";
1907 discardmailer.m_mailer = "DISCARD";
1908 discardmailer.m_argv = discardargv;
1909 }
1910 if (errormailer.m_name == NULL)
1911 {
1912 /* initialize the bogus mailer */
1913 errormailer.m_name = "*error*";
1914 errormailer.m_mailer = "ERROR";
1915 errormailer.m_argv = errorargv;
1916 }
1917 }
1918 /*
1919 ** BUILDADDR -- build address from token vector.
1920 **
1921 ** Parameters:
1922 ** tv -- token vector.
1923 ** a -- pointer to address descriptor to fill.
1924 ** If NULL, one will be allocated.
1925 ** flags -- info regarding whether this is a sender or
1926 ** a recipient.
1927 ** e -- the current envelope.
1928 **
1929 ** Returns:
1930 ** NULL if there was an error.
1931 ** 'a' otherwise.
1932 **
1933 ** Side Effects:
1934 ** fills in 'a'
1935 */
1936
1937 static struct errcodes
1938 {
1939 char *ec_name; /* name of error code */
1940 int ec_code; /* numeric code */
1941 } ErrorCodes[] =
1942 {
1943 { "usage", EX_USAGE },
1944 { "nouser", EX_NOUSER },
1945 { "nohost", EX_NOHOST },
1946 { "unavailable", EX_UNAVAILABLE },
1947 { "software", EX_SOFTWARE },
1948 { "tempfail", EX_TEMPFAIL },
1949 { "protocol", EX_PROTOCOL },
1950 { "config", EX_CONFIG },
1951 { NULL, EX_UNAVAILABLE }
1952 };
1953
1954 static ADDRESS *
buildaddr(tv,a,flags,e)1955 buildaddr(tv, a, flags, e)
1956 register char **tv;
1957 register ADDRESS *a;
1958 int flags;
1959 register ENVELOPE *e;
1960 {
1961 bool tempfail = false;
1962 int maxatom;
1963 struct mailer **mp;
1964 register struct mailer *m;
1965 register char *p;
1966 char *mname;
1967 char **hostp;
1968 char hbuf[MAXNAME + 1];
1969 static char ubuf[MAXNAME + 2];
1970
1971 if (tTd(24, 5))
1972 {
1973 sm_dprintf("buildaddr, flags=%x, tv=", flags);
1974 printav(sm_debug_file(), tv);
1975 }
1976
1977 maxatom = MAXATOM;
1978 if (a == NULL)
1979 a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a));
1980 memset((char *) a, '\0', sizeof(*a));
1981 hbuf[0] = '\0';
1982
1983 /* set up default error return flags */
1984 a->q_flags |= DefaultNotify;
1985
1986 /* figure out what net/mailer to use */
1987 if (*tv == NULL || (**tv & 0377) != CANONNET)
1988 {
1989 syserr("554 5.3.5 buildaddr: no mailer in parsed address");
1990 badaddr:
1991 /*
1992 ** ExitStat may have been set by an earlier map open
1993 ** failure (to a permanent error (EX_OSERR) in syserr())
1994 ** so we also need to check if this particular $#error
1995 ** return wanted a 4XX failure.
1996 **
1997 ** XXX the real fix is probably to set ExitStat correctly,
1998 ** i.e., to EX_TEMPFAIL if the map open is just a temporary
1999 ** error.
2000 */
2001
2002 if (ExitStat == EX_TEMPFAIL || tempfail)
2003 a->q_state = QS_QUEUEUP;
2004 else
2005 {
2006 a->q_state = QS_BADADDR;
2007 a->q_mailer = &errormailer;
2008 }
2009 return a;
2010 }
2011 mname = *++tv;
2012 --maxatom;
2013
2014 /* extract host and user portions */
2015 if (*++tv != NULL && (**tv & 0377) == CANONHOST)
2016 {
2017 hostp = ++tv;
2018 --maxatom;
2019 }
2020 else
2021 hostp = NULL;
2022 --maxatom;
2023 while (*tv != NULL && (**tv & 0377) != CANONUSER)
2024 {
2025 tv++;
2026 --maxatom;
2027 }
2028 if (*tv == NULL)
2029 {
2030 syserr("554 5.3.5 buildaddr: no user");
2031 goto badaddr;
2032 }
2033 if (tv == hostp)
2034 hostp = NULL;
2035 else if (hostp != NULL)
2036 cataddr(hostp, tv - 1, hbuf, sizeof(hbuf), '\0', false);
2037 cataddr(++tv, NULL, ubuf, sizeof(ubuf), ' ', false);
2038 --maxatom;
2039
2040 /* save away the host name */
2041 if (sm_strcasecmp(mname, "error") == 0)
2042 {
2043 /* Set up triplet for use by -bv */
2044 a->q_mailer = &errormailer;
2045 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
2046 /* XXX wrong place? */
2047
2048 if (hostp != NULL)
2049 {
2050 register struct errcodes *ep;
2051
2052 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
2053 if (strchr(hbuf, '.') != NULL)
2054 {
2055 a->q_status = sm_rpool_strdup_x(e->e_rpool,
2056 hbuf);
2057 setstat(dsntoexitstat(hbuf));
2058 }
2059 else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
2060 {
2061 setstat(atoi(hbuf));
2062 }
2063 else
2064 {
2065 for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
2066 if (sm_strcasecmp(ep->ec_name, hbuf) == 0)
2067 break;
2068 setstat(ep->ec_code);
2069 }
2070 }
2071 else
2072 {
2073 a->q_host = NULL;
2074 setstat(EX_UNAVAILABLE);
2075 }
2076 stripquotes(ubuf);
2077 if (ISSMTPCODE(ubuf) && ubuf[3] == ' ')
2078 {
2079 char fmt[16];
2080 int off;
2081
2082 if ((off = isenhsc(ubuf + 4, ' ')) > 0)
2083 {
2084 ubuf[off + 4] = '\0';
2085 off += 5;
2086 }
2087 else
2088 {
2089 off = 4;
2090 ubuf[3] = '\0';
2091 }
2092 (void) sm_strlcpyn(fmt, sizeof(fmt), 2, ubuf, " %s");
2093 if (off > 4)
2094 usrerr(fmt, ubuf + off);
2095 else if (isenhsc(hbuf, '\0') > 0)
2096 usrerrenh(hbuf, fmt, ubuf + off);
2097 else
2098 usrerr(fmt, ubuf + off);
2099 /* XXX ubuf[off - 1] = ' '; */
2100 if (ubuf[0] == '4')
2101 tempfail = true;
2102 }
2103 else
2104 {
2105 usrerr("553 5.3.0 %s", ubuf);
2106 }
2107 goto badaddr;
2108 }
2109
2110 for (mp = Mailer; (m = *mp++) != NULL; )
2111 {
2112 if (sm_strcasecmp(m->m_name, mname) == 0)
2113 break;
2114 }
2115 if (m == NULL)
2116 {
2117 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname);
2118 goto badaddr;
2119 }
2120 a->q_mailer = m;
2121
2122 /* figure out what host (if any) */
2123 if (hostp == NULL)
2124 {
2125 if (!bitnset(M_LOCALMAILER, m->m_flags))
2126 {
2127 syserr("554 5.3.5 buildaddr: no host");
2128 goto badaddr;
2129 }
2130 a->q_host = NULL;
2131 }
2132 else
2133 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
2134
2135 /* figure out the user */
2136 p = ubuf;
2137 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
2138 {
2139 p++;
2140 tv++;
2141 --maxatom;
2142 a->q_flags |= QNOTREMOTE;
2143 }
2144
2145 /* do special mapping for local mailer */
2146 if (*p == '"')
2147 p++;
2148 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
2149 a->q_mailer = m = ProgMailer;
2150 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
2151 a->q_mailer = m = FileMailer;
2152 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
2153 {
2154 /* may be :include: */
2155 stripquotes(ubuf);
2156 if (sm_strncasecmp(ubuf, ":include:", 9) == 0)
2157 {
2158 /* if :include:, don't need further rewriting */
2159 a->q_mailer = m = InclMailer;
2160 a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]);
2161 return a;
2162 }
2163 }
2164
2165 /* rewrite according recipient mailer rewriting rules */
2166 macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
2167
2168 if (ConfigLevel >= 10 ||
2169 !bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
2170 {
2171 /* sender addresses done later */
2172 (void) rewrite(tv, 2, 0, e, maxatom);
2173 if (m->m_re_rwset > 0)
2174 (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom);
2175 }
2176 (void) rewrite(tv, 4, 0, e, maxatom);
2177
2178 /* save the result for the command line/RCPT argument */
2179 cataddr(tv, NULL, ubuf, sizeof(ubuf), '\0', true);
2180 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
2181
2182 /*
2183 ** Do mapping to lower case as requested by mailer
2184 */
2185
2186 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
2187 makelower(a->q_host);
2188 if (!bitnset(M_USR_UPPER, m->m_flags))
2189 makelower(a->q_user);
2190
2191 if (tTd(24, 6))
2192 {
2193 sm_dprintf("buildaddr => ");
2194 printaddr(sm_debug_file(), a, false);
2195 }
2196 return a;
2197 }
2198
2199 /*
2200 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
2201 **
2202 ** Parameters:
2203 ** pvp -- parameter vector to rebuild.
2204 ** evp -- last parameter to include. Can be NULL to
2205 ** use entire pvp.
2206 ** buf -- buffer to build the string into.
2207 ** sz -- size of buf.
2208 ** spacesub -- the space separator character; if '\0',
2209 ** use SpaceSub.
2210 ** external -- convert to external form?
2211 ** (no metacharacters; METAQUOTEs removed, see below)
2212 **
2213 ** Returns:
2214 ** none.
2215 **
2216 ** Side Effects:
2217 ** Destroys buf.
2218 **
2219 ** Notes:
2220 ** There are two formats for strings: internal and external.
2221 ** The external format is just an eight-bit clean string (no
2222 ** null bytes, everything else OK). The internal format can
2223 ** include sendmail metacharacters. The special character
2224 ** METAQUOTE essentially quotes the character following, stripping
2225 ** it of all special semantics.
2226 **
2227 ** The cataddr routine needs to be aware of whether it is producing
2228 ** an internal or external form as output (it only takes internal
2229 ** form as input).
2230 **
2231 ** The parseaddr routine has a similar issue on input, but that
2232 ** is flagged on the basis of which token table is passed in.
2233 */
2234
2235 void
cataddr(pvp,evp,buf,sz,spacesub,external)2236 cataddr(pvp, evp, buf, sz, spacesub, external)
2237 char **pvp;
2238 char **evp;
2239 char *buf;
2240 register int sz;
2241 int spacesub;
2242 bool external;
2243 {
2244 bool oatomtok, natomtok;
2245 char *p;
2246
2247 oatomtok = natomtok = false;
2248 if (tTd(59, 14))
2249 {
2250 sm_dprintf("cataddr(%d) <==", external);
2251 printav(sm_debug_file(), pvp);
2252 }
2253
2254 if (sz <= 0)
2255 return;
2256
2257 if (spacesub == '\0')
2258 spacesub = SpaceSub;
2259
2260 if (pvp == NULL)
2261 {
2262 *buf = '\0';
2263 return;
2264 }
2265 p = buf;
2266 sz -= 2;
2267 while (*pvp != NULL && sz > 0)
2268 {
2269 char *q;
2270
2271 natomtok = (IntTokenTab[**pvp & 0xff] == ATM);
2272 if (oatomtok && natomtok)
2273 {
2274 *p++ = spacesub;
2275 if (--sz <= 0)
2276 break;
2277 }
2278 for (q = *pvp; *q != '\0'; )
2279 {
2280 int c;
2281
2282 if (--sz <= 0)
2283 break;
2284 *p++ = c = *q++;
2285
2286 /*
2287 ** If the current character (c) is METAQUOTE and we
2288 ** want the "external" form and the next character
2289 ** is not NUL, then overwrite METAQUOTE with that
2290 ** character (i.e., METAQUOTE ch is changed to
2291 ** ch). p[-1] is used because p is advanced (above).
2292 */
2293
2294 if ((c & 0377) == METAQUOTE && external && *q != '\0')
2295 p[-1] = *q++;
2296 }
2297 if (sz <= 0)
2298 break;
2299 oatomtok = natomtok;
2300 if (pvp++ == evp)
2301 break;
2302 }
2303
2304 #if 0
2305 /*
2306 ** Silently truncate long strings: even though this doesn't
2307 ** seem like a good idea it is necessary because header checks
2308 ** send the whole header value to rscheck() and hence rewrite().
2309 ** The latter however sometimes uses a "short" buffer (e.g.,
2310 ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this
2311 ** error function. One possible fix to the problem is to pass
2312 ** flags to rscheck() and rewrite() to distinguish the various
2313 ** calls and only trigger the error if necessary. For now just
2314 ** undo the change from 8.13.0.
2315 */
2316
2317 if (sz <= 0)
2318 usrerr("cataddr: string too long");
2319 #endif
2320 *p = '\0';
2321
2322 if (tTd(59, 14))
2323 sm_dprintf(" cataddr => %s\n", str2prt(buf));
2324 }
2325
2326 /*
2327 ** SAMEADDR -- Determine if two addresses are the same
2328 **
2329 ** This is not just a straight comparison -- if the mailer doesn't
2330 ** care about the host we just ignore it, etc.
2331 **
2332 ** Parameters:
2333 ** a, b -- pointers to the internal forms to compare.
2334 **
2335 ** Returns:
2336 ** true -- they represent the same mailbox.
2337 ** false -- they don't.
2338 **
2339 ** Side Effects:
2340 ** none.
2341 */
2342
2343 bool
sameaddr(a,b)2344 sameaddr(a, b)
2345 register ADDRESS *a;
2346 register ADDRESS *b;
2347 {
2348 register ADDRESS *ca, *cb;
2349
2350 /* if they don't have the same mailer, forget it */
2351 if (a->q_mailer != b->q_mailer)
2352 return false;
2353
2354 /* if the user isn't the same, we can drop out */
2355 if (strcmp(a->q_user, b->q_user) != 0)
2356 return false;
2357
2358 /* if we have good uids for both but they differ, these are different */
2359 if (a->q_mailer == ProgMailer)
2360 {
2361 ca = getctladdr(a);
2362 cb = getctladdr(b);
2363 if (ca != NULL && cb != NULL &&
2364 bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
2365 ca->q_uid != cb->q_uid)
2366 return false;
2367 }
2368
2369 /* otherwise compare hosts (but be careful for NULL ptrs) */
2370 if (a->q_host == b->q_host)
2371 {
2372 /* probably both null pointers */
2373 return true;
2374 }
2375 if (a->q_host == NULL || b->q_host == NULL)
2376 {
2377 /* only one is a null pointer */
2378 return false;
2379 }
2380 if (strcmp(a->q_host, b->q_host) != 0)
2381 return false;
2382
2383 return true;
2384 }
2385 /*
2386 ** PRINTADDR -- print address (for debugging)
2387 **
2388 ** Parameters:
2389 ** a -- the address to print
2390 ** follow -- follow the q_next chain.
2391 **
2392 ** Returns:
2393 ** none.
2394 **
2395 ** Side Effects:
2396 ** none.
2397 */
2398
2399 struct qflags
2400 {
2401 char *qf_name;
2402 unsigned long qf_bit;
2403 };
2404
2405 static struct qflags AddressFlags[] =
2406 {
2407 { "QGOODUID", QGOODUID },
2408 { "QPRIMARY", QPRIMARY },
2409 { "QNOTREMOTE", QNOTREMOTE },
2410 { "QSELFREF", QSELFREF },
2411 { "QBOGUSSHELL", QBOGUSSHELL },
2412 { "QUNSAFEADDR", QUNSAFEADDR },
2413 { "QPINGONSUCCESS", QPINGONSUCCESS },
2414 { "QPINGONFAILURE", QPINGONFAILURE },
2415 { "QPINGONDELAY", QPINGONDELAY },
2416 { "QHASNOTIFY", QHASNOTIFY },
2417 { "QRELAYED", QRELAYED },
2418 { "QEXPANDED", QEXPANDED },
2419 { "QDELIVERED", QDELIVERED },
2420 { "QDELAYED", QDELAYED },
2421 { "QTHISPASS", QTHISPASS },
2422 { "QRCPTOK", QRCPTOK },
2423 { NULL, 0 }
2424 };
2425
2426 void
printaddr(fp,a,follow)2427 printaddr(fp, a, follow)
2428 SM_FILE_T *fp;
2429 register ADDRESS *a;
2430 bool follow;
2431 {
2432 register MAILER *m;
2433 MAILER pseudomailer;
2434 register struct qflags *qfp;
2435 bool firstone;
2436
2437 if (a == NULL)
2438 {
2439 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n");
2440 return;
2441 }
2442
2443 while (a != NULL)
2444 {
2445 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a);
2446 (void) sm_io_flush(fp, SM_TIME_DEFAULT);
2447
2448 /* find the mailer -- carefully */
2449 m = a->q_mailer;
2450 if (m == NULL)
2451 {
2452 m = &pseudomailer;
2453 m->m_mno = -1;
2454 m->m_name = "NULL";
2455 }
2456
2457 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2458 "%s:\n\tmailer %d (%s), host `%s'\n",
2459 a->q_paddr == NULL ? "<null>" : a->q_paddr,
2460 m->m_mno, m->m_name,
2461 a->q_host == NULL ? "<null>" : a->q_host);
2462 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2463 "\tuser `%s', ruser `%s'\n",
2464 a->q_user,
2465 a->q_ruser == NULL ? "<null>" : a->q_ruser);
2466 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate=");
2467 switch (a->q_state)
2468 {
2469 case QS_OK:
2470 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK");
2471 break;
2472
2473 case QS_DONTSEND:
2474 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2475 "DONTSEND");
2476 break;
2477
2478 case QS_BADADDR:
2479 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2480 "BADADDR");
2481 break;
2482
2483 case QS_QUEUEUP:
2484 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2485 "QUEUEUP");
2486 break;
2487
2488 case QS_RETRY:
2489 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY");
2490 break;
2491
2492 case QS_SENT:
2493 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT");
2494 break;
2495
2496 case QS_VERIFIED:
2497 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2498 "VERIFIED");
2499 break;
2500
2501 case QS_EXPANDED:
2502 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2503 "EXPANDED");
2504 break;
2505
2506 case QS_SENDER:
2507 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2508 "SENDER");
2509 break;
2510
2511 case QS_CLONED:
2512 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2513 "CLONED");
2514 break;
2515
2516 case QS_DISCARDED:
2517 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2518 "DISCARDED");
2519 break;
2520
2521 case QS_REPLACED:
2522 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2523 "REPLACED");
2524 break;
2525
2526 case QS_REMOVED:
2527 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2528 "REMOVED");
2529 break;
2530
2531 case QS_DUPLICATE:
2532 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2533 "DUPLICATE");
2534 break;
2535
2536 case QS_INCLUDED:
2537 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2538 "INCLUDED");
2539 break;
2540
2541 default:
2542 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2543 "%d", a->q_state);
2544 break;
2545 }
2546 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2547 ", next=%p, alias %p, uid %d, gid %d\n",
2548 a->q_next, a->q_alias,
2549 (int) a->q_uid, (int) a->q_gid);
2550 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<",
2551 a->q_flags);
2552 firstone = true;
2553 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
2554 {
2555 if (!bitset(qfp->qf_bit, a->q_flags))
2556 continue;
2557 if (!firstone)
2558 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2559 ",");
2560 firstone = false;
2561 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
2562 qfp->qf_name);
2563 }
2564 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n");
2565 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2566 "\towner=%s, home=\"%s\", fullname=\"%s\"\n",
2567 a->q_owner == NULL ? "(none)" : a->q_owner,
2568 a->q_home == NULL ? "(none)" : a->q_home,
2569 a->q_fullname == NULL ? "(none)" : a->q_fullname);
2570 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2571 "\torcpt=\"%s\", statmta=%s, status=%s\n",
2572 a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
2573 a->q_statmta == NULL ? "(none)" : a->q_statmta,
2574 a->q_status == NULL ? "(none)" : a->q_status);
2575 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2576 "\tfinalrcpt=\"%s\"\n",
2577 a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt);
2578 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2579 "\trstatus=\"%s\"\n",
2580 a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
2581 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
2582 "\tstatdate=%s\n",
2583 a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate));
2584
2585 if (!follow)
2586 return;
2587 a = a->q_next;
2588 }
2589 }
2590 /*
2591 ** EMPTYADDR -- return true if this address is empty (``<>'')
2592 **
2593 ** Parameters:
2594 ** a -- pointer to the address
2595 **
2596 ** Returns:
2597 ** true -- if this address is "empty" (i.e., no one should
2598 ** ever generate replies to it.
2599 ** false -- if it is a "regular" (read: replyable) address.
2600 */
2601
2602 bool
emptyaddr(a)2603 emptyaddr(a)
2604 register ADDRESS *a;
2605 {
2606 return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
2607 a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
2608 }
2609 /*
2610 ** REMOTENAME -- return the name relative to the current mailer
2611 **
2612 ** Parameters:
2613 ** name -- the name to translate.
2614 ** m -- the mailer that we want to do rewriting relative to.
2615 ** flags -- fine tune operations.
2616 ** pstat -- pointer to status word.
2617 ** e -- the current envelope.
2618 **
2619 ** Returns:
2620 ** the text string representing this address relative to
2621 ** the receiving mailer.
2622 **
2623 ** Side Effects:
2624 ** none.
2625 **
2626 ** Warnings:
2627 ** The text string returned is tucked away locally;
2628 ** copy it if you intend to save it.
2629 */
2630
2631 char *
remotename(name,m,flags,pstat,e)2632 remotename(name, m, flags, pstat, e)
2633 char *name;
2634 struct mailer *m;
2635 int flags;
2636 int *pstat;
2637 register ENVELOPE *e;
2638 {
2639 register char **pvp;
2640 char *SM_NONVOLATILE fancy;
2641 char *oldg;
2642 int rwset;
2643 static char buf[MAXNAME + 1];
2644 char lbuf[MAXNAME + 1];
2645 char pvpbuf[PSBUFSIZE];
2646 char addrtype[4];
2647
2648 if (tTd(12, 1))
2649 {
2650 sm_dprintf("remotename(");
2651 xputs(sm_debug_file(), name);
2652 sm_dprintf(")\n");
2653 }
2654
2655 /* don't do anything if we are tagging it as special */
2656 if (bitset(RF_SENDERADDR, flags))
2657 {
2658 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
2659 : m->m_se_rwset;
2660 addrtype[2] = 's';
2661 }
2662 else
2663 {
2664 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
2665 : m->m_re_rwset;
2666 addrtype[2] = 'r';
2667 }
2668 if (rwset < 0)
2669 return name;
2670 addrtype[1] = ' ';
2671 addrtype[3] = '\0';
2672 addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e';
2673 macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype);
2674
2675 /*
2676 ** Do a heuristic crack of this name to extract any comment info.
2677 ** This will leave the name as a comment and a $g macro.
2678 */
2679
2680 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
2681 fancy = "\201g";
2682 else
2683 fancy = crackaddr(name, e);
2684
2685 /*
2686 ** Turn the name into canonical form.
2687 ** Normally this will be RFC 822 style, i.e., "user@domain".
2688 ** If this only resolves to "user", and the "C" flag is
2689 ** specified in the sending mailer, then the sender's
2690 ** domain will be appended.
2691 */
2692
2693 pvp = prescan(name, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, false);
2694 if (pvp == NULL)
2695 return name;
2696 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
2697 *pstat = EX_TEMPFAIL;
2698 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
2699 {
2700 /* append from domain to this address */
2701 register char **pxp = pvp;
2702 int l = MAXATOM; /* size of buffer for pvp */
2703
2704 /* see if there is an "@domain" in the current name */
2705 while (*pxp != NULL && strcmp(*pxp, "@") != 0)
2706 {
2707 pxp++;
2708 --l;
2709 }
2710 if (*pxp == NULL)
2711 {
2712 /* no.... append the "@domain" from the sender */
2713 register char **qxq = e->e_fromdomain;
2714
2715 while ((*pxp++ = *qxq++) != NULL)
2716 {
2717 if (--l <= 0)
2718 {
2719 *--pxp = NULL;
2720 usrerr("553 5.1.0 remotename: too many tokens");
2721 *pstat = EX_UNAVAILABLE;
2722 break;
2723 }
2724 }
2725 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
2726 *pstat = EX_TEMPFAIL;
2727 }
2728 }
2729
2730 /*
2731 ** Do more specific rewriting.
2732 ** Rewrite using ruleset 1 or 2 depending on whether this is
2733 ** a sender address or not.
2734 ** Then run it through any receiving-mailer-specific rulesets.
2735 */
2736
2737 if (bitset(RF_SENDERADDR, flags))
2738 {
2739 if (REWRITE(pvp, 1, e) == EX_TEMPFAIL)
2740 *pstat = EX_TEMPFAIL;
2741 }
2742 else
2743 {
2744 if (REWRITE(pvp, 2, e) == EX_TEMPFAIL)
2745 *pstat = EX_TEMPFAIL;
2746 }
2747 if (rwset > 0)
2748 {
2749 if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL)
2750 *pstat = EX_TEMPFAIL;
2751 }
2752
2753 /*
2754 ** Do any final sanitation the address may require.
2755 ** This will normally be used to turn internal forms
2756 ** (e.g., user@host.LOCAL) into external form. This
2757 ** may be used as a default to the above rules.
2758 */
2759
2760 if (REWRITE(pvp, 4, e) == EX_TEMPFAIL)
2761 *pstat = EX_TEMPFAIL;
2762
2763 /*
2764 ** Now restore the comment information we had at the beginning.
2765 */
2766
2767 cataddr(pvp, NULL, lbuf, sizeof(lbuf), '\0', false);
2768 oldg = macget(&e->e_macro, 'g');
2769 macset(&e->e_macro, 'g', lbuf);
2770
2771 SM_TRY
2772 /* need to make sure route-addrs have <angle brackets> */
2773 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
2774 expand("<\201g>", buf, sizeof(buf), e);
2775 else
2776 expand(fancy, buf, sizeof(buf), e);
2777 SM_FINALLY
2778 macset(&e->e_macro, 'g', oldg);
2779 SM_END_TRY
2780
2781 if (tTd(12, 1))
2782 {
2783 sm_dprintf("remotename => `");
2784 xputs(sm_debug_file(), buf);
2785 sm_dprintf("'\n");
2786 }
2787 return buf;
2788 }
2789 /*
2790 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
2791 **
2792 ** Parameters:
2793 ** a -- the address to map (but just the user name part).
2794 ** sendq -- the sendq in which to install any replacement
2795 ** addresses.
2796 ** aliaslevel -- the alias nesting depth.
2797 ** e -- the envelope.
2798 **
2799 ** Returns:
2800 ** none.
2801 */
2802
2803 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
2804 Q_PINGFLAGS|QHASNOTIFY|\
2805 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\
2806 QBYTRACE|QBYNDELAY|QBYNRELAY)
2807
2808 void
maplocaluser(a,sendq,aliaslevel,e)2809 maplocaluser(a, sendq, aliaslevel, e)
2810 register ADDRESS *a;
2811 ADDRESS **sendq;
2812 int aliaslevel;
2813 ENVELOPE *e;
2814 {
2815 register char **pvp;
2816 register ADDRESS *SM_NONVOLATILE a1 = NULL;
2817 char pvpbuf[PSBUFSIZE];
2818
2819 if (tTd(29, 1))
2820 {
2821 sm_dprintf("maplocaluser: ");
2822 printaddr(sm_debug_file(), a, false);
2823 }
2824 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL,
2825 false);
2826 if (pvp == NULL)
2827 {
2828 if (tTd(29, 9))
2829 sm_dprintf("maplocaluser: cannot prescan %s\n",
2830 a->q_user);
2831 return;
2832 }
2833
2834 macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
2835 macdefine(&e->e_macro, A_PERM, 'u', a->q_user);
2836 macdefine(&e->e_macro, A_PERM, 'z', a->q_home);
2837
2838 macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
2839 if (REWRITE(pvp, 5, e) == EX_TEMPFAIL)
2840 {
2841 if (tTd(29, 9))
2842 sm_dprintf("maplocaluser: rewrite tempfail\n");
2843 a->q_state = QS_QUEUEUP;
2844 a->q_status = "4.4.3";
2845 return;
2846 }
2847 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
2848 {
2849 if (tTd(29, 9))
2850 sm_dprintf("maplocaluser: doesn't resolve\n");
2851 return;
2852 }
2853
2854 SM_TRY
2855 a1 = buildaddr(pvp, NULL, 0, e);
2856 SM_EXCEPT(exc, "E:mta.quickabort")
2857
2858 /*
2859 ** mark address as bad, S5 returned an error
2860 ** and we gave that back to the SMTP client.
2861 */
2862
2863 a->q_state = QS_DONTSEND;
2864 sm_exc_raisenew_x(&EtypeQuickAbort, 2);
2865 SM_END_TRY
2866
2867 /* if non-null, mailer destination specified -- has it changed? */
2868 if (a1 == NULL || sameaddr(a, a1))
2869 {
2870 if (tTd(29, 9))
2871 sm_dprintf("maplocaluser: address unchanged\n");
2872 return;
2873 }
2874
2875 /* make new address take on flags and print attributes of old */
2876 a1->q_flags &= ~Q_COPYFLAGS;
2877 a1->q_flags |= a->q_flags & Q_COPYFLAGS;
2878 a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr);
2879 a1->q_finalrcpt = a->q_finalrcpt;
2880 a1->q_orcpt = a->q_orcpt;
2881
2882 /* mark old address as dead; insert new address */
2883 a->q_state = QS_REPLACED;
2884 if (tTd(29, 5))
2885 {
2886 sm_dprintf("maplocaluser: QS_REPLACED ");
2887 printaddr(sm_debug_file(), a, false);
2888 }
2889 a1->q_alias = a;
2890 allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e);
2891 (void) recipient(a1, sendq, aliaslevel, e);
2892 }
2893 /*
2894 ** DEQUOTE_INIT -- initialize dequote map
2895 **
2896 ** Parameters:
2897 ** map -- the internal map structure.
2898 ** args -- arguments.
2899 **
2900 ** Returns:
2901 ** true.
2902 */
2903
2904 bool
dequote_init(map,args)2905 dequote_init(map, args)
2906 MAP *map;
2907 char *args;
2908 {
2909 register char *p = args;
2910
2911 /* there is no check whether there is really an argument */
2912 map->map_mflags |= MF_KEEPQUOTES;
2913 for (;;)
2914 {
2915 while (isascii(*p) && isspace(*p))
2916 p++;
2917 if (*p != '-')
2918 break;
2919 switch (*++p)
2920 {
2921 case 'a':
2922 map->map_app = ++p;
2923 break;
2924
2925 case 'D':
2926 map->map_mflags |= MF_DEFER;
2927 break;
2928
2929 case 'S':
2930 case 's':
2931 map->map_spacesub = *++p;
2932 break;
2933 }
2934 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2935 p++;
2936 if (*p != '\0')
2937 *p = '\0';
2938 }
2939 if (map->map_app != NULL)
2940 map->map_app = newstr(map->map_app);
2941
2942 return true;
2943 }
2944 /*
2945 ** DEQUOTE_MAP -- unquote an address
2946 **
2947 ** Parameters:
2948 ** map -- the internal map structure (ignored).
2949 ** name -- the name to dequote.
2950 ** av -- arguments (ignored).
2951 ** statp -- pointer to status out-parameter.
2952 **
2953 ** Returns:
2954 ** NULL -- if there were no quotes, or if the resulting
2955 ** unquoted buffer would not be acceptable to prescan.
2956 ** else -- The dequoted buffer.
2957 */
2958
2959 /* ARGSUSED2 */
2960 char *
dequote_map(map,name,av,statp)2961 dequote_map(map, name, av, statp)
2962 MAP *map;
2963 char *name;
2964 char **av;
2965 int *statp;
2966 {
2967 register char *p;
2968 register char *q;
2969 register char c;
2970 int anglecnt = 0;
2971 int cmntcnt = 0;
2972 int quotecnt = 0;
2973 int spacecnt = 0;
2974 bool quotemode = false;
2975 bool bslashmode = false;
2976 char spacesub = map->map_spacesub;
2977
2978 for (p = q = name; (c = *p++) != '\0'; )
2979 {
2980 if (bslashmode)
2981 {
2982 bslashmode = false;
2983 *q++ = c;
2984 continue;
2985 }
2986
2987 if (c == ' ' && spacesub != '\0')
2988 c = spacesub;
2989
2990 switch (c)
2991 {
2992 case '\\':
2993 bslashmode = true;
2994 break;
2995
2996 case '(':
2997 cmntcnt++;
2998 break;
2999
3000 case ')':
3001 if (cmntcnt-- <= 0)
3002 return NULL;
3003 break;
3004
3005 case ' ':
3006 case '\t':
3007 spacecnt++;
3008 break;
3009 }
3010
3011 if (cmntcnt > 0)
3012 {
3013 *q++ = c;
3014 continue;
3015 }
3016
3017 switch (c)
3018 {
3019 case '"':
3020 quotemode = !quotemode;
3021 quotecnt++;
3022 continue;
3023
3024 case '<':
3025 anglecnt++;
3026 break;
3027
3028 case '>':
3029 if (anglecnt-- <= 0)
3030 return NULL;
3031 break;
3032 }
3033 *q++ = c;
3034 }
3035
3036 if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
3037 quotemode || quotecnt <= 0 || spacecnt != 0)
3038 return NULL;
3039 *q++ = '\0';
3040 return map_rewrite(map, name, strlen(name), NULL);
3041 }
3042 /*
3043 ** RSCHECK -- check string(s) for validity using rewriting sets
3044 **
3045 ** Parameters:
3046 ** rwset -- the rewriting set to use.
3047 ** p1 -- the first string to check.
3048 ** p2 -- the second string to check -- may be null.
3049 ** e -- the current envelope.
3050 ** flags -- control some behavior, see RSF_ in sendmail.h
3051 ** logl -- logging level.
3052 ** host -- NULL or relay host.
3053 ** logid -- id for sm_syslog.
3054 ** addr -- if not NULL and ruleset returns $#error:
3055 ** store mailer triple here.
3056 **
3057 ** Returns:
3058 ** EX_OK -- if the rwset doesn't resolve to $#error
3059 ** else -- the failure status (message printed)
3060 */
3061
3062 int
rscheck(rwset,p1,p2,e,flags,logl,host,logid,addr)3063 rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr)
3064 char *rwset;
3065 char *p1;
3066 char *p2;
3067 ENVELOPE *e;
3068 int flags;
3069 int logl;
3070 char *host;
3071 char *logid;
3072 ADDRESS *addr;
3073 {
3074 char *volatile buf;
3075 size_t bufsize;
3076 int saveexitstat;
3077 int volatile rstat = EX_OK;
3078 char **pvp;
3079 int rsno;
3080 bool volatile discard = false;
3081 bool saveQuickAbort = QuickAbort;
3082 bool saveSuprErrs = SuprErrs;
3083 bool quarantine = false;
3084 char ubuf[BUFSIZ * 2];
3085 char buf0[MAXLINE];
3086 char pvpbuf[PSBUFSIZE];
3087 extern char MsgBuf[];
3088
3089 if (tTd(48, 2))
3090 sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1,
3091 p2 == NULL ? "(NULL)" : p2);
3092
3093 rsno = strtorwset(rwset, NULL, ST_FIND);
3094 if (rsno < 0)
3095 return EX_OK;
3096
3097 if (p2 != NULL)
3098 {
3099 bufsize = strlen(p1) + strlen(p2) + 2;
3100 if (bufsize > sizeof(buf0))
3101 buf = sm_malloc_x(bufsize);
3102 else
3103 {
3104 buf = buf0;
3105 bufsize = sizeof(buf0);
3106 }
3107 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
3108 }
3109 else
3110 {
3111 bufsize = strlen(p1) + 1;
3112 if (bufsize > sizeof(buf0))
3113 buf = sm_malloc_x(bufsize);
3114 else
3115 {
3116 buf = buf0;
3117 bufsize = sizeof(buf0);
3118 }
3119 (void) sm_strlcpy(buf, p1, bufsize);
3120 }
3121 SM_TRY
3122 {
3123 SuprErrs = true;
3124 QuickAbort = false;
3125 pvp = prescan(buf, '\0', pvpbuf, sizeof(pvpbuf), NULL,
3126 bitset(RSF_RMCOMM, flags) ?
3127 IntTokenTab : TokTypeNoC,
3128 bitset(RSF_RMCOMM, flags) ? false : true);
3129 SuprErrs = saveSuprErrs;
3130 if (pvp == NULL)
3131 {
3132 if (tTd(48, 2))
3133 sm_dprintf("rscheck: cannot prescan input\n");
3134 /*
3135 syserr("rscheck: cannot prescan input: \"%s\"",
3136 shortenstring(buf, MAXSHORTSTR));
3137 rstat = EX_DATAERR;
3138 */
3139 goto finis;
3140 }
3141 if (bitset(RSF_UNSTRUCTURED, flags))
3142 SuprErrs = true;
3143 (void) REWRITE(pvp, rsno, e);
3144 if (bitset(RSF_UNSTRUCTURED, flags))
3145 SuprErrs = saveSuprErrs;
3146 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
3147 pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
3148 strcmp(pvp[1], "discard") != 0))
3149 {
3150 goto finis;
3151 }
3152
3153 if (strcmp(pvp[1], "discard") == 0)
3154 {
3155 if (tTd(48, 2))
3156 sm_dprintf("rscheck: discard mailer selected\n");
3157 e->e_flags |= EF_DISCARD;
3158 discard = true;
3159 }
3160 else if (strcmp(pvp[1], "error") == 0 &&
3161 pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST &&
3162 pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0)
3163 {
3164 if (pvp[4] == NULL ||
3165 (pvp[4][0] & 0377) != CANONUSER ||
3166 pvp[5] == NULL)
3167 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
3168 rwset);
3169 else
3170 {
3171 cataddr(&(pvp[5]), NULL, ubuf,
3172 sizeof(ubuf), ' ', true);
3173 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
3174 ubuf);
3175 }
3176 macdefine(&e->e_macro, A_PERM,
3177 macid("{quarantine}"), e->e_quarmsg);
3178 quarantine = true;
3179 }
3180 else
3181 {
3182 auto ADDRESS a1;
3183 int savelogusrerrs = LogUsrErrs;
3184 static bool logged = false;
3185
3186 /* got an error -- process it */
3187 saveexitstat = ExitStat;
3188 LogUsrErrs = false;
3189 (void) buildaddr(pvp, &a1, 0, e);
3190 if (addr != NULL)
3191 {
3192 addr->q_mailer = a1.q_mailer;
3193 addr->q_user = a1.q_user;
3194 addr->q_host = a1.q_host;
3195 }
3196 LogUsrErrs = savelogusrerrs;
3197 rstat = ExitStat;
3198 ExitStat = saveexitstat;
3199 if (!logged)
3200 {
3201 if (bitset(RSF_COUNT, flags))
3202 markstats(e, &a1, STATS_REJECT);
3203 logged = true;
3204 }
3205 }
3206
3207 if (LogLevel > logl)
3208 {
3209 char *relay;
3210 char *p;
3211 char lbuf[MAXLINE];
3212
3213 p = lbuf;
3214 if (p2 != NULL)
3215 {
3216 (void) sm_snprintf(p, SPACELEFT(lbuf, p),
3217 ", arg2=%s",
3218 p2);
3219 p += strlen(p);
3220 }
3221
3222 if (host != NULL)
3223 relay = host;
3224 else
3225 relay = macvalue('_', e);
3226 if (relay != NULL)
3227 {
3228 (void) sm_snprintf(p, SPACELEFT(lbuf, p),
3229 ", relay=%s", relay);
3230 p += strlen(p);
3231 }
3232 *p = '\0';
3233 if (discard)
3234 sm_syslog(LOG_NOTICE, logid,
3235 "ruleset=%s, arg1=%s%s, discard",
3236 rwset, p1, lbuf);
3237 else if (quarantine)
3238 sm_syslog(LOG_NOTICE, logid,
3239 "ruleset=%s, arg1=%s%s, quarantine=%s",
3240 rwset, p1, lbuf, ubuf);
3241 else
3242 sm_syslog(LOG_NOTICE, logid,
3243 "ruleset=%s, arg1=%s%s, reject=%s",
3244 rwset, p1, lbuf, MsgBuf);
3245 }
3246
3247 finis: ;
3248 }
3249 SM_FINALLY
3250 {
3251 /* clean up */
3252 if (buf != buf0)
3253 sm_free(buf);
3254 QuickAbort = saveQuickAbort;
3255 }
3256 SM_END_TRY
3257
3258 setstat(rstat);
3259
3260 /* rulesets don't set errno */
3261 errno = 0;
3262 if (rstat != EX_OK && QuickAbort)
3263 sm_exc_raisenew_x(&EtypeQuickAbort, 2);
3264 return rstat;
3265 }
3266 /*
3267 ** RSCAP -- call rewriting set to return capabilities
3268 **
3269 ** Parameters:
3270 ** rwset -- the rewriting set to use.
3271 ** p1 -- the first string to check.
3272 ** p2 -- the second string to check -- may be null.
3273 ** e -- the current envelope.
3274 ** pvp -- pointer to token vector.
3275 ** pvpbuf -- buffer space.
3276 ** size -- size of buffer space.
3277 **
3278 ** Returns:
3279 ** EX_UNAVAILABLE -- ruleset doesn't exist.
3280 ** EX_DATAERR -- prescan() failed.
3281 ** EX_OK -- rewrite() was successful.
3282 ** else -- return status from rewrite().
3283 */
3284
3285 int
rscap(rwset,p1,p2,e,pvp,pvpbuf,size)3286 rscap(rwset, p1, p2, e, pvp, pvpbuf, size)
3287 char *rwset;
3288 char *p1;
3289 char *p2;
3290 ENVELOPE *e;
3291 char ***pvp;
3292 char *pvpbuf;
3293 int size;
3294 {
3295 char *volatile buf;
3296 size_t bufsize;
3297 int volatile rstat = EX_OK;
3298 int rsno;
3299 bool saveQuickAbort = QuickAbort;
3300 bool saveSuprErrs = SuprErrs;
3301 char buf0[MAXLINE];
3302 extern char MsgBuf[];
3303
3304 if (tTd(48, 2))
3305 sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1,
3306 p2 == NULL ? "(NULL)" : p2);
3307
3308 SM_REQUIRE(pvp != NULL);
3309 rsno = strtorwset(rwset, NULL, ST_FIND);
3310 if (rsno < 0)
3311 return EX_UNAVAILABLE;
3312
3313 if (p2 != NULL)
3314 {
3315 bufsize = strlen(p1) + strlen(p2) + 2;
3316 if (bufsize > sizeof(buf0))
3317 buf = sm_malloc_x(bufsize);
3318 else
3319 {
3320 buf = buf0;
3321 bufsize = sizeof(buf0);
3322 }
3323 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
3324 }
3325 else
3326 {
3327 bufsize = strlen(p1) + 1;
3328 if (bufsize > sizeof(buf0))
3329 buf = sm_malloc_x(bufsize);
3330 else
3331 {
3332 buf = buf0;
3333 bufsize = sizeof(buf0);
3334 }
3335 (void) sm_strlcpy(buf, p1, bufsize);
3336 }
3337 SM_TRY
3338 {
3339 SuprErrs = true;
3340 QuickAbort = false;
3341 *pvp = prescan(buf, '\0', pvpbuf, size, NULL, IntTokenTab,
3342 false);
3343 if (*pvp != NULL)
3344 rstat = rewrite(*pvp, rsno, 0, e, size);
3345 else
3346 {
3347 if (tTd(48, 2))
3348 sm_dprintf("rscap: cannot prescan input\n");
3349 rstat = EX_DATAERR;
3350 }
3351 }
3352 SM_FINALLY
3353 {
3354 /* clean up */
3355 if (buf != buf0)
3356 sm_free(buf);
3357 SuprErrs = saveSuprErrs;
3358 QuickAbort = saveQuickAbort;
3359
3360 /* prevent information leak, this may contain rewrite error */
3361 MsgBuf[0] = '\0';
3362 }
3363 SM_END_TRY
3364 return rstat;
3365 }
3366