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