1 /*
2 * Copyright (c) 1983, 1995 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * %sccs.include.redist.c%
7 */
8
9 #ifndef lint
10 static char sccsid[] = "@(#)parseaddr.c 8.73 (Berkeley) 06/19/95";
11 #endif /* not lint */
12
13 # include "sendmail.h"
14
15 /*
16 ** PARSEADDR -- Parse an address
17 **
18 ** Parses an address and breaks it up into three parts: a
19 ** net to transmit the message on, the host to transmit it
20 ** to, and a user on that host. These are loaded into an
21 ** ADDRESS header with the values squirreled away if necessary.
22 ** The "user" part may not be a real user; the process may
23 ** just reoccur on that machine. For example, on a machine
24 ** with an arpanet connection, the address
25 ** csvax.bill@berkeley
26 ** will break up to a "user" of 'csvax.bill' and a host
27 ** of 'berkeley' -- to be transmitted over the arpanet.
28 **
29 ** Parameters:
30 ** addr -- the address to parse.
31 ** a -- a pointer to the address descriptor buffer.
32 ** If NULL, a header will be created.
33 ** flags -- describe detail for parsing. See RF_ definitions
34 ** in sendmail.h.
35 ** delim -- the character to terminate the address, passed
36 ** to prescan.
37 ** delimptr -- if non-NULL, set to the location of the
38 ** delim character that was found.
39 ** e -- the envelope that will contain this address.
40 **
41 ** Returns:
42 ** A pointer to the address descriptor header (`a' if
43 ** `a' is non-NULL).
44 ** NULL on error.
45 **
46 ** Side Effects:
47 ** none
48 */
49
50 /* following delimiters are inherent to the internal algorithms */
51 # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
52
53 ADDRESS *
parseaddr(addr,a,flags,delim,delimptr,e)54 parseaddr(addr, a, flags, delim, delimptr, e)
55 char *addr;
56 register ADDRESS *a;
57 int flags;
58 int delim;
59 char **delimptr;
60 register ENVELOPE *e;
61 {
62 register char **pvp;
63 auto char *delimptrbuf;
64 bool queueup;
65 char pvpbuf[PSBUFSIZE];
66 extern ADDRESS *buildaddr();
67 extern bool invalidaddr();
68 extern void allocaddr __P((ADDRESS *, int, char *));
69
70 /*
71 ** Initialize and prescan address.
72 */
73
74 e->e_to = addr;
75 if (tTd(20, 1))
76 printf("\n--parseaddr(%s)\n", addr);
77
78 if (delimptr == NULL)
79 delimptr = &delimptrbuf;
80
81 pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
82 if (pvp == NULL)
83 {
84 if (tTd(20, 1))
85 printf("parseaddr-->NULL\n");
86 return (NULL);
87 }
88
89 if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
90 {
91 if (tTd(20, 1))
92 printf("parseaddr-->bad address\n");
93 return NULL;
94 }
95
96 /*
97 ** Save addr if we are going to have to.
98 **
99 ** We have to do this early because there is a chance that
100 ** the map lookups in the rewriting rules could clobber
101 ** static memory somewhere.
102 */
103
104 if (bitset(RF_COPYPADDR, flags) && addr != NULL)
105 {
106 char savec = **delimptr;
107
108 if (savec != '\0')
109 **delimptr = '\0';
110 e->e_to = addr = newstr(addr);
111 if (savec != '\0')
112 **delimptr = savec;
113 }
114
115 /*
116 ** Apply rewriting rules.
117 ** Ruleset 0 does basic parsing. It must resolve.
118 */
119
120 queueup = FALSE;
121 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
122 queueup = TRUE;
123 if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
124 queueup = TRUE;
125
126
127 /*
128 ** Build canonical address from pvp.
129 */
130
131 a = buildaddr(pvp, a, flags, e);
132
133 /*
134 ** Make local copies of the host & user and then
135 ** transport them out.
136 */
137
138 allocaddr(a, flags, addr);
139 if (bitset(QBADADDR, a->q_flags))
140 return a;
141
142 /*
143 ** If there was a parsing failure, mark it for queueing.
144 */
145
146 if (queueup)
147 {
148 char *msg = "Transient parse error -- message queued for future delivery";
149
150 if (tTd(20, 1))
151 printf("parseaddr: queuing message\n");
152 message(msg);
153 if (e->e_message == NULL)
154 e->e_message = newstr(msg);
155 a->q_flags |= QQUEUEUP;
156 a->q_status = "4.4.3";
157 }
158
159 /*
160 ** Compute return value.
161 */
162
163 if (tTd(20, 1))
164 {
165 printf("parseaddr-->");
166 printaddr(a, FALSE);
167 }
168
169 return (a);
170 }
171 /*
172 ** INVALIDADDR -- check for address containing meta-characters
173 **
174 ** Parameters:
175 ** addr -- the address to check.
176 **
177 ** Returns:
178 ** TRUE -- if the address has any "wierd" characters
179 ** FALSE -- otherwise.
180 */
181
182 bool
invalidaddr(addr,delimptr)183 invalidaddr(addr, delimptr)
184 register char *addr;
185 char *delimptr;
186 {
187 char savedelim = '\0';
188
189 if (delimptr != NULL)
190 {
191 savedelim = *delimptr;
192 if (savedelim != '\0')
193 *delimptr = '\0';
194 }
195 #if 0
196 /* for testing.... */
197 if (strcmp(addr, "INvalidADDR") == 0)
198 {
199 usrerr("553 INvalid ADDRess");
200 goto addrfailure;
201 }
202 #endif
203 for (; *addr != '\0'; addr++)
204 {
205 if ((*addr & 0340) == 0200)
206 break;
207 }
208 if (*addr == '\0')
209 {
210 if (delimptr != NULL && savedelim != '\0')
211 *delimptr = savedelim;
212 return FALSE;
213 }
214 setstat(EX_USAGE);
215 usrerr("553 Address contained invalid control characters");
216 addrfailure:
217 if (delimptr != NULL && savedelim != '\0')
218 *delimptr = savedelim;
219 return TRUE;
220 }
221 /*
222 ** ALLOCADDR -- do local allocations of address on demand.
223 **
224 ** Also lowercases the host name if requested.
225 **
226 ** Parameters:
227 ** a -- the address to reallocate.
228 ** flags -- the copy flag (see RF_ definitions in sendmail.h
229 ** for a description).
230 ** paddr -- the printname of the address.
231 **
232 ** Returns:
233 ** none.
234 **
235 ** Side Effects:
236 ** Copies portions of a into local buffers as requested.
237 */
238
239 void
allocaddr(a,flags,paddr)240 allocaddr(a, flags, paddr)
241 register ADDRESS *a;
242 int flags;
243 char *paddr;
244 {
245 if (tTd(24, 4))
246 printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
247
248 a->q_paddr = paddr;
249
250 if (a->q_user == NULL)
251 a->q_user = "";
252 if (a->q_host == NULL)
253 a->q_host = "";
254
255 if (bitset(RF_COPYPARSE, flags))
256 {
257 a->q_host = newstr(a->q_host);
258 if (a->q_user != a->q_paddr)
259 a->q_user = newstr(a->q_user);
260 }
261
262 if (a->q_paddr == NULL)
263 a->q_paddr = a->q_user;
264 }
265 /*
266 ** PRESCAN -- Prescan name and make it canonical
267 **
268 ** Scans a name and turns it into a set of tokens. This process
269 ** deletes blanks and comments (in parentheses).
270 **
271 ** This routine knows about quoted strings and angle brackets.
272 **
273 ** There are certain subtleties to this routine. The one that
274 ** comes to mind now is that backslashes on the ends of names
275 ** are silently stripped off; this is intentional. The problem
276 ** is that some versions of sndmsg (like at LBL) set the kill
277 ** character to something other than @ when reading addresses;
278 ** so people type "csvax.eric\@berkeley" -- which screws up the
279 ** berknet mailer.
280 **
281 ** Parameters:
282 ** addr -- the name to chomp.
283 ** delim -- the delimiter for the address, normally
284 ** '\0' or ','; \0 is accepted in any case.
285 ** If '\t' then we are reading the .cf file.
286 ** pvpbuf -- place to put the saved text -- note that
287 ** the pointers are static.
288 ** pvpbsize -- size of pvpbuf.
289 ** delimptr -- if non-NULL, set to the location of the
290 ** terminating delimiter.
291 ** toktab -- if set, a token table to use for parsing.
292 ** If NULL, use the default table.
293 **
294 ** Returns:
295 ** A pointer to a vector of tokens.
296 ** NULL on error.
297 */
298
299 /* states and character types */
300 # define OPR 0 /* operator */
301 # define ATM 1 /* atom */
302 # define QST 2 /* in quoted string */
303 # define SPC 3 /* chewing up spaces */
304 # define ONE 4 /* pick up one character */
305 # define ILL 5 /* illegal character */
306
307 # define NSTATES 6 /* number of states */
308 # define TYPE 017 /* mask to select state type */
309
310 /* meta bits for table */
311 # define M 020 /* meta character; don't pass through */
312 # define B 040 /* cause a break */
313 # define MB M|B /* meta-break */
314
315 static short StateTab[NSTATES][NSTATES] =
316 {
317 /* oldst chtype> OPR ATM QST SPC ONE ILL */
318 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB,
319 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB,
320 /*QST*/ QST, QST, OPR, QST, QST, QST,
321 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ILL|MB,
322 /*ONE*/ OPR, OPR, OPR, OPR, OPR, ILL|MB,
323 /*ILL*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M,
324 };
325
326 /* token type table -- it gets modified with $o characters */
327 static u_char TokTypeTab[256] =
328 {
329 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
330 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
331 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
332 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
333 /* sp ! " # $ % & ' ( ) * + , - . / */
334 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
335 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
336 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
337 /* @ A B C D E F G H I J K L M N O */
338 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
339 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
340 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
341 /* ` a b c d e f g h i j k l m n o */
342 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
343 /* p q r s t u v w x y z { | } ~ del */
344 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
345
346 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
347 OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
348 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
349 OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
350 /* sp ! " # $ % & ' ( ) * + , - . / */
351 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
352 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
353 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
354 /* @ A B C D E F G H I J K L M N O */
355 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
356 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
357 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
358 /* ` a b c d e f g h i j k l m n o */
359 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
360 /* p q r s t u v w x y z { | } ~ del */
361 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
362 };
363
364 /* token type table for MIME parsing */
365 u_char MimeTokenTab[256] =
366 {
367 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
368 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
369 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
370 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
371 /* sp ! " # $ % & ' ( ) * + , - . / */
372 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
373 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
374 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
375 /* @ A B C D E F G H I J K L M N O */
376 OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
377 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
378 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
379 /* ` a b c d e f g h i j k l m n o */
380 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
381 /* p q r s t u v w x y z { | } ~ del */
382 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
383
384 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
385 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
386 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
387 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
388 /* sp ! " # $ % & ' ( ) * + , - . / */
389 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
390 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
391 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
392 /* @ A B C D E F G H I J K L M N O */
393 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
394 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
395 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
396 /* ` a b c d e f g h i j k l m n o */
397 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
398 /* p q r s t u v w x y z { | } ~ del */
399 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
400 };
401
402
403 # define NOCHAR -1 /* signal nothing in lookahead token */
404
405 char **
prescan(addr,delim,pvpbuf,pvpbsize,delimptr,toktab)406 prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
407 char *addr;
408 int delim;
409 char pvpbuf[];
410 char **delimptr;
411 u_char *toktab;
412 {
413 register char *p;
414 register char *q;
415 register int c;
416 char **avp;
417 bool bslashmode;
418 int cmntcnt;
419 int anglecnt;
420 char *tok;
421 int state;
422 int newstate;
423 char *saveto = CurEnv->e_to;
424 static char *av[MAXATOM+1];
425 static char firsttime = TRUE;
426 extern int errno;
427
428 if (firsttime)
429 {
430 /* initialize the token type table */
431 char obuf[50];
432
433 firsttime = FALSE;
434 expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv);
435 strcat(obuf, DELIMCHARS);
436 for (p = obuf; *p != '\0'; p++)
437 {
438 if (TokTypeTab[*p & 0xff] == ATM)
439 TokTypeTab[*p & 0xff] = OPR;
440 }
441 }
442 if (toktab == NULL)
443 toktab = TokTypeTab;
444
445 /* make sure error messages don't have garbage on them */
446 errno = 0;
447
448 q = pvpbuf;
449 bslashmode = FALSE;
450 cmntcnt = 0;
451 anglecnt = 0;
452 avp = av;
453 state = ATM;
454 c = NOCHAR;
455 p = addr;
456 CurEnv->e_to = p;
457 if (tTd(22, 11))
458 {
459 printf("prescan: ");
460 xputs(p);
461 (void) putchar('\n');
462 }
463
464 do
465 {
466 /* read a token */
467 tok = q;
468 for (;;)
469 {
470 /* store away any old lookahead character */
471 if (c != NOCHAR && !bslashmode)
472 {
473 /* see if there is room */
474 if (q >= &pvpbuf[pvpbsize - 5])
475 {
476 usrerr("553 Address too long");
477 if (strlen(addr) > MAXNAME)
478 addr[MAXNAME] = '\0';
479 returnnull:
480 if (delimptr != NULL)
481 *delimptr = p;
482 CurEnv->e_to = saveto;
483 return (NULL);
484 }
485
486 /* squirrel it away */
487 *q++ = c;
488 }
489
490 /* read a new input character */
491 c = *p++;
492 if (c == '\0')
493 {
494 /* diagnose and patch up bad syntax */
495 if (state == QST)
496 {
497 usrerr("653 Unbalanced '\"'");
498 c = '"';
499 }
500 else if (cmntcnt > 0)
501 {
502 usrerr("653 Unbalanced '('");
503 c = ')';
504 }
505 else if (anglecnt > 0)
506 {
507 c = '>';
508 usrerr("653 Unbalanced '<'");
509 }
510 else
511 break;
512
513 p--;
514 }
515 else if (c == delim && anglecnt <= 0 &&
516 cmntcnt <= 0 && state != QST)
517 break;
518
519 if (tTd(22, 101))
520 printf("c=%c, s=%d; ", c, state);
521
522 /* chew up special characters */
523 *q = '\0';
524 if (bslashmode)
525 {
526 bslashmode = FALSE;
527
528 /* kludge \! for naive users */
529 if (cmntcnt > 0)
530 {
531 c = NOCHAR;
532 continue;
533 }
534 else if (c != '!' || state == QST)
535 {
536 *q++ = '\\';
537 continue;
538 }
539 }
540
541 if (c == '\\')
542 {
543 bslashmode = TRUE;
544 }
545 else if (state == QST)
546 {
547 /* do nothing, just avoid next clauses */
548 }
549 else if (c == '(')
550 {
551 cmntcnt++;
552 c = NOCHAR;
553 }
554 else if (c == ')')
555 {
556 if (cmntcnt <= 0)
557 {
558 usrerr("653 Unbalanced ')'");
559 c = NOCHAR;
560 }
561 else
562 cmntcnt--;
563 }
564 else if (cmntcnt > 0)
565 c = NOCHAR;
566 else if (c == '<')
567 anglecnt++;
568 else if (c == '>')
569 {
570 if (anglecnt <= 0)
571 {
572 usrerr("653 Unbalanced '>'");
573 c = NOCHAR;
574 }
575 else
576 anglecnt--;
577 }
578 else if (delim == ' ' && isascii(c) && isspace(c))
579 c = ' ';
580
581 if (c == NOCHAR)
582 continue;
583
584 /* see if this is end of input */
585 if (c == delim && anglecnt <= 0 && state != QST)
586 break;
587
588 newstate = StateTab[state][toktab[c & 0xff]];
589 if (tTd(22, 101))
590 printf("ns=%02o\n", newstate);
591 state = newstate & TYPE;
592 if (state == ILL)
593 {
594 if (isascii(c) && isprint(c))
595 usrerr("653 Illegal character %c", c);
596 else
597 usrerr("653 Illegal character 0x%02x", c);
598 }
599 if (bitset(M, newstate))
600 c = NOCHAR;
601 if (bitset(B, newstate))
602 break;
603 }
604
605 /* new token */
606 if (tok != q)
607 {
608 *q++ = '\0';
609 if (tTd(22, 36))
610 {
611 printf("tok=");
612 xputs(tok);
613 (void) putchar('\n');
614 }
615 if (avp >= &av[MAXATOM])
616 {
617 syserr("553 prescan: too many tokens");
618 goto returnnull;
619 }
620 if (q - tok > MAXNAME)
621 {
622 syserr("553 prescan: token too long");
623 goto returnnull;
624 }
625 *avp++ = tok;
626 }
627 } while (c != '\0' && (c != delim || anglecnt > 0));
628 *avp = NULL;
629 p--;
630 if (delimptr != NULL)
631 *delimptr = p;
632 if (tTd(22, 12))
633 {
634 printf("prescan==>");
635 printav(av);
636 }
637 CurEnv->e_to = saveto;
638 if (av[0] == NULL)
639 {
640 if (tTd(22, 1))
641 printf("prescan: null leading token\n");
642 return (NULL);
643 }
644 return (av);
645 }
646 /*
647 ** REWRITE -- apply rewrite rules to token vector.
648 **
649 ** This routine is an ordered production system. Each rewrite
650 ** rule has a LHS (called the pattern) and a RHS (called the
651 ** rewrite); 'rwr' points the the current rewrite rule.
652 **
653 ** For each rewrite rule, 'avp' points the address vector we
654 ** are trying to match against, and 'pvp' points to the pattern.
655 ** If pvp points to a special match value (MATCHZANY, MATCHANY,
656 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
657 ** matched is saved away in the match vector (pointed to by 'mvp').
658 **
659 ** When a match between avp & pvp does not match, we try to
660 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
661 ** we must also back out the match in mvp. If we reach a
662 ** MATCHANY or MATCHZANY we just extend the match and start
663 ** over again.
664 **
665 ** When we finally match, we rewrite the address vector
666 ** and try over again.
667 **
668 ** Parameters:
669 ** pvp -- pointer to token vector.
670 ** ruleset -- the ruleset to use for rewriting.
671 ** reclevel -- recursion level (to catch loops).
672 ** e -- the current envelope.
673 **
674 ** Returns:
675 ** A status code. If EX_TEMPFAIL, higher level code should
676 ** attempt recovery.
677 **
678 ** Side Effects:
679 ** pvp is modified.
680 */
681
682 struct match
683 {
684 char **first; /* first token matched */
685 char **last; /* last token matched */
686 char **pattern; /* pointer to pattern */
687 };
688
689 # define MAXMATCH 9 /* max params per rewrite */
690
691 # ifndef MAXRULERECURSION
692 # define MAXRULERECURSION 50 /* max recursion depth */
693 # endif
694
695
696 int
rewrite(pvp,ruleset,reclevel,e)697 rewrite(pvp, ruleset, reclevel, e)
698 char **pvp;
699 int ruleset;
700 int reclevel;
701 register ENVELOPE *e;
702 {
703 register char *ap; /* address pointer */
704 register char *rp; /* rewrite pointer */
705 register char **avp; /* address vector pointer */
706 register char **rvp; /* rewrite vector pointer */
707 register struct match *mlp; /* cur ptr into mlist */
708 register struct rewrite *rwr; /* pointer to current rewrite rule */
709 int ruleno; /* current rule number */
710 int rstat = EX_OK; /* return status */
711 int loopcount;
712 struct match mlist[MAXMATCH]; /* stores match on LHS */
713 char *npvp[MAXATOM+1]; /* temporary space for rebuild */
714
715 if (OpMode == MD_TEST || tTd(21, 1))
716 {
717 printf("rewrite: ruleset %2d input:", ruleset);
718 printav(pvp);
719 }
720 if (ruleset < 0 || ruleset >= MAXRWSETS)
721 {
722 syserr("554 rewrite: illegal ruleset number %d", ruleset);
723 return EX_CONFIG;
724 }
725 if (reclevel++ > MAXRULERECURSION)
726 {
727 syserr("rewrite: infinite recursion, ruleset %d", ruleset);
728 return EX_CONFIG;
729 }
730 if (pvp == NULL)
731 return EX_USAGE;
732
733 /*
734 ** Run through the list of rewrite rules, applying
735 ** any that match.
736 */
737
738 ruleno = 1;
739 loopcount = 0;
740 for (rwr = RewriteRules[ruleset]; rwr != NULL; )
741 {
742 if (tTd(21, 12))
743 {
744 printf("-----trying rule:");
745 printav(rwr->r_lhs);
746 }
747
748 /* try to match on this rule */
749 mlp = mlist;
750 rvp = rwr->r_lhs;
751 avp = pvp;
752 if (++loopcount > 100)
753 {
754 syserr("554 Infinite loop in ruleset %d, rule %d",
755 ruleset, ruleno);
756 if (tTd(21, 1))
757 {
758 printf("workspace: ");
759 printav(pvp);
760 }
761 break;
762 }
763
764 while ((ap = *avp) != NULL || *rvp != NULL)
765 {
766 rp = *rvp;
767 if (tTd(21, 35))
768 {
769 printf("ADVANCE rp=");
770 xputs(rp);
771 printf(", ap=");
772 xputs(ap);
773 printf("\n");
774 }
775 if (rp == NULL)
776 {
777 /* end-of-pattern before end-of-address */
778 goto backup;
779 }
780 if (ap == NULL && (*rp & 0377) != MATCHZANY &&
781 (*rp & 0377) != MATCHZERO)
782 {
783 /* end-of-input with patterns left */
784 goto backup;
785 }
786
787 switch (*rp & 0377)
788 {
789 char buf[MAXLINE];
790
791 case MATCHCLASS:
792 /* match any phrase in a class */
793 mlp->pattern = rvp;
794 mlp->first = avp;
795 extendclass:
796 ap = *avp;
797 if (ap == NULL)
798 goto backup;
799 mlp->last = avp++;
800 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
801 if (!wordinclass(buf, rp[1]))
802 {
803 if (tTd(21, 36))
804 {
805 printf("EXTEND rp=");
806 xputs(rp);
807 printf(", ap=");
808 xputs(ap);
809 printf("\n");
810 }
811 goto extendclass;
812 }
813 if (tTd(21, 36))
814 printf("CLMATCH\n");
815 mlp++;
816 break;
817
818 case MATCHNCLASS:
819 /* match any token not in a class */
820 if (wordinclass(ap, rp[1]))
821 goto backup;
822
823 /* fall through */
824
825 case MATCHONE:
826 case MATCHANY:
827 /* match exactly one token */
828 mlp->pattern = rvp;
829 mlp->first = avp;
830 mlp->last = avp++;
831 mlp++;
832 break;
833
834 case MATCHZANY:
835 /* match zero or more tokens */
836 mlp->pattern = rvp;
837 mlp->first = avp;
838 mlp->last = avp - 1;
839 mlp++;
840 break;
841
842 case MATCHZERO:
843 /* match zero tokens */
844 break;
845
846 case MACRODEXPAND:
847 /*
848 ** Match against run-time macro.
849 ** This algorithm is broken for the
850 ** general case (no recursive macros,
851 ** improper tokenization) but should
852 ** work for the usual cases.
853 */
854
855 ap = macvalue(rp[1], e);
856 mlp->first = avp;
857 if (tTd(21, 2))
858 printf("rewrite: LHS $&%c => \"%s\"\n",
859 rp[1],
860 ap == NULL ? "(NULL)" : ap);
861
862 if (ap == NULL)
863 break;
864 while (*ap != '\0')
865 {
866 if (*avp == NULL ||
867 strncasecmp(ap, *avp, strlen(*avp)) != 0)
868 {
869 /* no match */
870 avp = mlp->first;
871 goto backup;
872 }
873 ap += strlen(*avp++);
874 }
875
876 /* match */
877 break;
878
879 default:
880 /* must have exact match */
881 if (strcasecmp(rp, ap))
882 goto backup;
883 avp++;
884 break;
885 }
886
887 /* successful match on this token */
888 rvp++;
889 continue;
890
891 backup:
892 /* match failed -- back up */
893 while (--mlp >= mlist)
894 {
895 rvp = mlp->pattern;
896 rp = *rvp;
897 avp = mlp->last + 1;
898 ap = *avp;
899
900 if (tTd(21, 36))
901 {
902 printf("BACKUP rp=");
903 xputs(rp);
904 printf(", ap=");
905 xputs(ap);
906 printf("\n");
907 }
908
909 if (ap == NULL)
910 {
911 /* run off the end -- back up again */
912 continue;
913 }
914 if ((*rp & 0377) == MATCHANY ||
915 (*rp & 0377) == MATCHZANY)
916 {
917 /* extend binding and continue */
918 mlp->last = avp++;
919 rvp++;
920 mlp++;
921 break;
922 }
923 if ((*rp & 0377) == MATCHCLASS)
924 {
925 /* extend binding and try again */
926 mlp->last = avp;
927 goto extendclass;
928 }
929 }
930
931 if (mlp < mlist)
932 {
933 /* total failure to match */
934 break;
935 }
936 }
937
938 /*
939 ** See if we successfully matched
940 */
941
942 if (mlp < mlist || *rvp != NULL)
943 {
944 if (tTd(21, 10))
945 printf("----- rule fails\n");
946 rwr = rwr->r_next;
947 ruleno++;
948 loopcount = 0;
949 continue;
950 }
951
952 rvp = rwr->r_rhs;
953 if (tTd(21, 12))
954 {
955 printf("-----rule matches:");
956 printav(rvp);
957 }
958
959 rp = *rvp;
960 if ((*rp & 0377) == CANONUSER)
961 {
962 rvp++;
963 rwr = rwr->r_next;
964 ruleno++;
965 loopcount = 0;
966 }
967 else if ((*rp & 0377) == CANONHOST)
968 {
969 rvp++;
970 rwr = NULL;
971 }
972 else if ((*rp & 0377) == CANONNET)
973 rwr = NULL;
974
975 /* substitute */
976 for (avp = npvp; *rvp != NULL; rvp++)
977 {
978 register struct match *m;
979 register char **pp;
980
981 rp = *rvp;
982 if ((*rp & 0377) == MATCHREPL)
983 {
984 /* substitute from LHS */
985 m = &mlist[rp[1] - '1'];
986 if (m < mlist || m >= mlp)
987 {
988 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
989 ruleset, rp[1]);
990 return EX_CONFIG;
991 }
992 if (tTd(21, 15))
993 {
994 printf("$%c:", rp[1]);
995 pp = m->first;
996 while (pp <= m->last)
997 {
998 printf(" %x=\"", *pp);
999 (void) fflush(stdout);
1000 printf("%s\"", *pp++);
1001 }
1002 printf("\n");
1003 }
1004 pp = m->first;
1005 while (pp <= m->last)
1006 {
1007 if (avp >= &npvp[MAXATOM])
1008 {
1009 syserr("554 rewrite: expansion too long");
1010 return EX_DATAERR;
1011 }
1012 *avp++ = *pp++;
1013 }
1014 }
1015 else
1016 {
1017 /* vanilla replacement */
1018 if (avp >= &npvp[MAXATOM])
1019 {
1020 toolong:
1021 syserr("554 rewrite: expansion too long");
1022 return EX_DATAERR;
1023 }
1024 if ((*rp & 0377) != MACRODEXPAND)
1025 *avp++ = rp;
1026 else
1027 {
1028 *avp = macvalue(rp[1], e);
1029 if (tTd(21, 2))
1030 printf("rewrite: RHS $&%c => \"%s\"\n",
1031 rp[1],
1032 *avp == NULL ? "(NULL)" : *avp);
1033 if (*avp != NULL)
1034 avp++;
1035 }
1036 }
1037 }
1038 *avp++ = NULL;
1039
1040 /*
1041 ** Check for any hostname/keyword lookups.
1042 */
1043
1044 for (rvp = npvp; *rvp != NULL; rvp++)
1045 {
1046 char **hbrvp;
1047 char **xpvp;
1048 int trsize;
1049 char *replac;
1050 int endtoken;
1051 STAB *map;
1052 char *mapname;
1053 char **key_rvp;
1054 char **arg_rvp;
1055 char **default_rvp;
1056 char buf[MAXNAME + 1];
1057 char *pvpb1[MAXATOM + 1];
1058 char *argvect[10];
1059 char pvpbuf[PSBUFSIZE];
1060 char *nullpvp[1];
1061
1062 if ((**rvp & 0377) != HOSTBEGIN &&
1063 (**rvp & 0377) != LOOKUPBEGIN)
1064 continue;
1065
1066 /*
1067 ** Got a hostname/keyword lookup.
1068 **
1069 ** This could be optimized fairly easily.
1070 */
1071
1072 hbrvp = rvp;
1073 if ((**rvp & 0377) == HOSTBEGIN)
1074 {
1075 endtoken = HOSTEND;
1076 mapname = "host";
1077 }
1078 else
1079 {
1080 endtoken = LOOKUPEND;
1081 mapname = *++rvp;
1082 }
1083 map = stab(mapname, ST_MAP, ST_FIND);
1084 if (map == NULL)
1085 syserr("554 rewrite: map %s not found", mapname);
1086
1087 /* extract the match part */
1088 key_rvp = ++rvp;
1089 default_rvp = NULL;
1090 arg_rvp = argvect;
1091 xpvp = NULL;
1092 replac = pvpbuf;
1093 while (*rvp != NULL && (**rvp & 0377) != endtoken)
1094 {
1095 int nodetype = **rvp & 0377;
1096
1097 if (nodetype != CANONHOST && nodetype != CANONUSER)
1098 {
1099 rvp++;
1100 continue;
1101 }
1102
1103 *rvp++ = NULL;
1104
1105 if (xpvp != NULL)
1106 {
1107 cataddr(xpvp, NULL, replac,
1108 &pvpbuf[sizeof pvpbuf] - replac,
1109 '\0');
1110 *++arg_rvp = replac;
1111 replac += strlen(replac) + 1;
1112 xpvp = NULL;
1113 }
1114 switch (nodetype)
1115 {
1116 case CANONHOST:
1117 xpvp = rvp;
1118 break;
1119
1120 case CANONUSER:
1121 default_rvp = rvp;
1122 break;
1123 }
1124 }
1125 if (*rvp != NULL)
1126 *rvp++ = NULL;
1127 if (xpvp != NULL)
1128 {
1129 cataddr(xpvp, NULL, replac,
1130 &pvpbuf[sizeof pvpbuf] - replac,
1131 '\0');
1132 *++arg_rvp = replac;
1133 }
1134 *++arg_rvp = NULL;
1135
1136 /* save the remainder of the input string */
1137 trsize = (int) (avp - rvp + 1) * sizeof *rvp;
1138 bcopy((char *) rvp, (char *) pvpb1, trsize);
1139
1140 /* look it up */
1141 cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
1142 argvect[0] = buf;
1143 if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
1144 {
1145 auto int stat = EX_OK;
1146
1147 if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags))
1148 stripquotes(buf);
1149
1150 /* XXX should try to auto-open the map here */
1151
1152 if (tTd(60, 1))
1153 printf("map_lookup(%s, %s) => ",
1154 mapname, buf);
1155 replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
1156 buf, argvect, &stat);
1157 if (tTd(60, 1))
1158 printf("%s (%d)\n",
1159 replac ? replac : "NOT FOUND",
1160 stat);
1161
1162 /* should recover if stat == EX_TEMPFAIL */
1163 if (stat == EX_TEMPFAIL)
1164 {
1165 rstat = EX_TEMPFAIL;
1166 if (tTd(60, 1))
1167 printf("map_lookup(%s, %s) failed (stat = %d)\n",
1168 mapname, buf, stat);
1169 if (e->e_message == NULL)
1170 {
1171 char mbuf[300];
1172
1173 sprintf(mbuf, "map %s: lookup (%s) failed",
1174 mapname, buf);
1175 e->e_message = newstr(mbuf);
1176 }
1177 }
1178 }
1179 else
1180 replac = NULL;
1181
1182 /* if no replacement, use default */
1183 if (replac == NULL && default_rvp != NULL)
1184 {
1185 /* create the default */
1186 cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
1187 replac = buf;
1188 }
1189
1190 if (replac == NULL)
1191 {
1192 xpvp = key_rvp;
1193 }
1194 else if (*replac == '\0')
1195 {
1196 /* null replacement */
1197 nullpvp[0] = NULL;
1198 xpvp = nullpvp;
1199 }
1200 else
1201 {
1202 /* scan the new replacement */
1203 xpvp = prescan(replac, '\0', pvpbuf,
1204 sizeof pvpbuf, NULL, NULL);
1205 if (xpvp == NULL)
1206 {
1207 /* prescan already printed error */
1208 return EX_DATAERR;
1209 }
1210 }
1211
1212 /* append it to the token list */
1213 for (avp = hbrvp; *xpvp != NULL; xpvp++)
1214 {
1215 *avp++ = newstr(*xpvp);
1216 if (avp >= &npvp[MAXATOM])
1217 goto toolong;
1218 }
1219
1220 /* restore the old trailing information */
1221 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
1222 if (avp >= &npvp[MAXATOM])
1223 goto toolong;
1224
1225 break;
1226 }
1227
1228 /*
1229 ** Check for subroutine calls.
1230 */
1231
1232 if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
1233 {
1234 int stat;
1235
1236 if (npvp[1] == NULL)
1237 {
1238 syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
1239 ruleset, ruleno);
1240 *pvp = NULL;
1241 }
1242 else
1243 {
1244 int ruleset;
1245 STAB *s;
1246
1247 bcopy((char *) &npvp[2], (char *) pvp,
1248 (int) (avp - npvp - 2) * sizeof *avp);
1249 if (tTd(21, 3))
1250 printf("-----callsubr %s\n", npvp[1]);
1251 ruleset = strtorwset(npvp[1], NULL, ST_FIND);
1252 stat = rewrite(pvp, ruleset, reclevel, e);
1253 if (rstat == EX_OK || stat == EX_TEMPFAIL)
1254 rstat = stat;
1255 if (*pvp != NULL && (**pvp & 0377) == CANONNET)
1256 rwr = NULL;
1257 }
1258 }
1259 else
1260 {
1261 bcopy((char *) npvp, (char *) pvp,
1262 (int) (avp - npvp) * sizeof *avp);
1263 }
1264 if (tTd(21, 4))
1265 {
1266 printf("rewritten as:");
1267 printav(pvp);
1268 }
1269 }
1270
1271 if (OpMode == MD_TEST || tTd(21, 1))
1272 {
1273 printf("rewrite: ruleset %2d returns:", ruleset);
1274 printav(pvp);
1275 }
1276
1277 return rstat;
1278 }
1279 /*
1280 ** BUILDADDR -- build address from token vector.
1281 **
1282 ** Parameters:
1283 ** tv -- token vector.
1284 ** a -- pointer to address descriptor to fill.
1285 ** If NULL, one will be allocated.
1286 ** flags -- info regarding whether this is a sender or
1287 ** a recipient.
1288 ** e -- the current envelope.
1289 **
1290 ** Returns:
1291 ** NULL if there was an error.
1292 ** 'a' otherwise.
1293 **
1294 ** Side Effects:
1295 ** fills in 'a'
1296 */
1297
1298 struct errcodes
1299 {
1300 char *ec_name; /* name of error code */
1301 int ec_code; /* numeric code */
1302 } ErrorCodes[] =
1303 {
1304 "usage", EX_USAGE,
1305 "nouser", EX_NOUSER,
1306 "nohost", EX_NOHOST,
1307 "unavailable", EX_UNAVAILABLE,
1308 "software", EX_SOFTWARE,
1309 "tempfail", EX_TEMPFAIL,
1310 "protocol", EX_PROTOCOL,
1311 #ifdef EX_CONFIG
1312 "config", EX_CONFIG,
1313 #endif
1314 NULL, EX_UNAVAILABLE,
1315 };
1316
1317 ADDRESS *
buildaddr(tv,a,flags,e)1318 buildaddr(tv, a, flags, e)
1319 register char **tv;
1320 register ADDRESS *a;
1321 int flags;
1322 register ENVELOPE *e;
1323 {
1324 struct mailer **mp;
1325 register struct mailer *m;
1326 register char *p;
1327 char *mname;
1328 char **hostp;
1329 char hbuf[MAXNAME + 1];
1330 static MAILER errormailer;
1331 static char *errorargv[] = { "ERROR", NULL };
1332 static char ubuf[MAXNAME + 1];
1333
1334 if (tTd(24, 5))
1335 {
1336 printf("buildaddr, flags=%x, tv=", flags);
1337 printav(tv);
1338 }
1339
1340 if (a == NULL)
1341 a = (ADDRESS *) xalloc(sizeof *a);
1342 bzero((char *) a, sizeof *a);
1343
1344 /* set up default error return flags */
1345 a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
1346
1347 /* figure out what net/mailer to use */
1348 if (*tv == NULL || (**tv & 0377) != CANONNET)
1349 {
1350 syserr("554 buildaddr: no net");
1351 badaddr:
1352 a->q_flags |= QBADADDR;
1353 a->q_mailer = &errormailer;
1354 if (errormailer.m_name == NULL)
1355 {
1356 /* initialize the bogus mailer */
1357 errormailer.m_name = "*error*";
1358 errormailer.m_mailer = "ERROR";
1359 errormailer.m_argv = errorargv;
1360 }
1361 return a;
1362 }
1363 mname = *++tv;
1364
1365 /* extract host and user portions */
1366 if ((**++tv & 0377) == CANONHOST)
1367 hostp = ++tv;
1368 else
1369 hostp = NULL;
1370 while (*tv != NULL && (**tv & 0377) != CANONUSER)
1371 tv++;
1372 if (*tv == NULL)
1373 {
1374 syserr("554 buildaddr: no user");
1375 goto badaddr;
1376 }
1377 if (hostp != NULL)
1378 cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
1379 cataddr(++tv, NULL, ubuf, sizeof ubuf, '\0');
1380
1381 /* save away the host name */
1382 if (strcasecmp(mname, "error") == 0)
1383 {
1384 if (hostp != NULL)
1385 {
1386 register struct errcodes *ep;
1387
1388 if (strchr(hbuf, '.') != NULL)
1389 {
1390 a->q_status = newstr(hbuf);
1391 setstat(dsntoexitstat(hbuf));
1392 }
1393 else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
1394 {
1395 setstat(atoi(hbuf));
1396 }
1397 else
1398 {
1399 for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
1400 if (strcasecmp(ep->ec_name, hbuf) == 0)
1401 break;
1402 setstat(ep->ec_code);
1403 }
1404 }
1405 else
1406 setstat(EX_UNAVAILABLE);
1407 stripquotes(ubuf);
1408 if (isascii(ubuf[0]) && isdigit(ubuf[0]) &&
1409 isascii(ubuf[1]) && isdigit(ubuf[1]) &&
1410 isascii(ubuf[2]) && isdigit(ubuf[2]) &&
1411 ubuf[3] == ' ')
1412 {
1413 char fmt[10];
1414
1415 strncpy(fmt, ubuf, 3);
1416 strcpy(&fmt[3], " %s");
1417 usrerr(fmt, ubuf + 4);
1418
1419 /*
1420 ** If this is a 4xx code and we aren't running
1421 ** SMTP on our input, bounce this message;
1422 ** otherwise it disappears without a trace.
1423 */
1424
1425 if (fmt[0] == '4' && OpMode != MD_SMTP &&
1426 OpMode != MD_DAEMON)
1427 {
1428 e->e_flags |= EF_FATALERRS;
1429 }
1430 }
1431 else
1432 {
1433 usrerr("553 %s", ubuf);
1434 }
1435 goto badaddr;
1436 }
1437
1438 for (mp = Mailer; (m = *mp++) != NULL; )
1439 {
1440 if (strcasecmp(m->m_name, mname) == 0)
1441 break;
1442 }
1443 if (m == NULL)
1444 {
1445 syserr("554 buildaddr: unknown mailer %s", mname);
1446 goto badaddr;
1447 }
1448 a->q_mailer = m;
1449
1450 /* figure out what host (if any) */
1451 if (hostp == NULL)
1452 {
1453 if (!bitnset(M_LOCALMAILER, m->m_flags))
1454 {
1455 syserr("554 buildaddr: no host");
1456 goto badaddr;
1457 }
1458 a->q_host = NULL;
1459 }
1460 else
1461 a->q_host = newstr(hbuf);
1462
1463 /* figure out the user */
1464 p = ubuf;
1465 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
1466 {
1467 p++;
1468 tv++;
1469 a->q_flags |= QNOTREMOTE;
1470 }
1471
1472 /* do special mapping for local mailer */
1473 if (*p == '"')
1474 p++;
1475 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
1476 a->q_mailer = m = ProgMailer;
1477 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
1478 a->q_mailer = m = FileMailer;
1479 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
1480 {
1481 /* may be :include: */
1482 stripquotes(ubuf);
1483 if (strncasecmp(ubuf, ":include:", 9) == 0)
1484 {
1485 /* if :include:, don't need further rewriting */
1486 a->q_mailer = m = InclMailer;
1487 a->q_user = newstr(&ubuf[9]);
1488 return a;
1489 }
1490 }
1491
1492 /* rewrite according recipient mailer rewriting rules */
1493 define('h', a->q_host, e);
1494 if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
1495 {
1496 /* sender addresses done later */
1497 (void) rewrite(tv, 2, 0, e);
1498 if (m->m_re_rwset > 0)
1499 (void) rewrite(tv, m->m_re_rwset, 0, e);
1500 }
1501 (void) rewrite(tv, 4, 0, e);
1502
1503 /* save the result for the command line/RCPT argument */
1504 cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
1505 a->q_user = ubuf;
1506
1507 /*
1508 ** Do mapping to lower case as requested by mailer
1509 */
1510
1511 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
1512 makelower(a->q_host);
1513 if (!bitnset(M_USR_UPPER, m->m_flags))
1514 makelower(a->q_user);
1515
1516 return a;
1517 }
1518 /*
1519 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
1520 **
1521 ** Parameters:
1522 ** pvp -- parameter vector to rebuild.
1523 ** evp -- last parameter to include. Can be NULL to
1524 ** use entire pvp.
1525 ** buf -- buffer to build the string into.
1526 ** sz -- size of buf.
1527 ** spacesub -- the space separator character; if null,
1528 ** use SpaceSub.
1529 **
1530 ** Returns:
1531 ** none.
1532 **
1533 ** Side Effects:
1534 ** Destroys buf.
1535 */
1536
1537 void
cataddr(pvp,evp,buf,sz,spacesub)1538 cataddr(pvp, evp, buf, sz, spacesub)
1539 char **pvp;
1540 char **evp;
1541 char *buf;
1542 register int sz;
1543 int spacesub;
1544 {
1545 bool oatomtok = FALSE;
1546 bool natomtok = FALSE;
1547 register int i;
1548 register char *p;
1549
1550 if (spacesub == '\0')
1551 spacesub = SpaceSub;
1552
1553 if (pvp == NULL)
1554 {
1555 (void) strcpy(buf, "");
1556 return;
1557 }
1558 p = buf;
1559 sz -= 2;
1560 while (*pvp != NULL && (i = strlen(*pvp)) < sz)
1561 {
1562 natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
1563 if (oatomtok && natomtok)
1564 *p++ = spacesub;
1565 (void) strcpy(p, *pvp);
1566 oatomtok = natomtok;
1567 p += i;
1568 sz -= i + 1;
1569 if (pvp++ == evp)
1570 break;
1571 }
1572 *p = '\0';
1573 }
1574 /*
1575 ** SAMEADDR -- Determine if two addresses are the same
1576 **
1577 ** This is not just a straight comparison -- if the mailer doesn't
1578 ** care about the host we just ignore it, etc.
1579 **
1580 ** Parameters:
1581 ** a, b -- pointers to the internal forms to compare.
1582 **
1583 ** Returns:
1584 ** TRUE -- they represent the same mailbox.
1585 ** FALSE -- they don't.
1586 **
1587 ** Side Effects:
1588 ** none.
1589 */
1590
1591 bool
sameaddr(a,b)1592 sameaddr(a, b)
1593 register ADDRESS *a;
1594 register ADDRESS *b;
1595 {
1596 register ADDRESS *ca, *cb;
1597
1598 /* if they don't have the same mailer, forget it */
1599 if (a->q_mailer != b->q_mailer)
1600 return (FALSE);
1601
1602 /* if the user isn't the same, we can drop out */
1603 if (strcmp(a->q_user, b->q_user) != 0)
1604 return (FALSE);
1605
1606 /* if we have good uids for both but they differ, these are different */
1607 if (a->q_mailer == ProgMailer)
1608 {
1609 ca = getctladdr(a);
1610 cb = getctladdr(b);
1611 if (ca != NULL && cb != NULL &&
1612 bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
1613 ca->q_uid != cb->q_uid)
1614 return (FALSE);
1615 }
1616
1617 /* otherwise compare hosts (but be careful for NULL ptrs) */
1618 if (a->q_host == b->q_host)
1619 {
1620 /* probably both null pointers */
1621 return (TRUE);
1622 }
1623 if (a->q_host == NULL || b->q_host == NULL)
1624 {
1625 /* only one is a null pointer */
1626 return (FALSE);
1627 }
1628 if (strcmp(a->q_host, b->q_host) != 0)
1629 return (FALSE);
1630
1631 return (TRUE);
1632 }
1633 /*
1634 ** PRINTADDR -- print address (for debugging)
1635 **
1636 ** Parameters:
1637 ** a -- the address to print
1638 ** follow -- follow the q_next chain.
1639 **
1640 ** Returns:
1641 ** none.
1642 **
1643 ** Side Effects:
1644 ** none.
1645 */
1646
1647 struct qflags
1648 {
1649 char *qf_name;
1650 u_long qf_bit;
1651 };
1652
1653 struct qflags AddressFlags[] =
1654 {
1655 "QDONTSEND", QDONTSEND,
1656 "QBADADDR", QBADADDR,
1657 "QGOODUID", QGOODUID,
1658 "QPRIMARY", QPRIMARY,
1659 "QQUEUEUP", QQUEUEUP,
1660 "QSENT", QSENT,
1661 "QNOTREMOTE", QNOTREMOTE,
1662 "QSELFREF", QSELFREF,
1663 "QVERIFIED", QVERIFIED,
1664 "QBOGUSSHELL", QBOGUSSHELL,
1665 "QUNSAFEADDR", QUNSAFEADDR,
1666 "QPINGONSUCCESS", QPINGONSUCCESS,
1667 "QPINGONFAILURE", QPINGONFAILURE,
1668 "QPINGONDELAY", QPINGONDELAY,
1669 "QHASNOTIFY", QHASNOTIFY,
1670 "QRELAYED", QRELAYED,
1671 "QEXPANDED", QEXPANDED,
1672 "QDELIVERED", QDELIVERED,
1673 "QDELAYED", QDELAYED,
1674 "QTHISPASS", QTHISPASS,
1675 NULL
1676 };
1677
1678 void
printaddr(a,follow)1679 printaddr(a, follow)
1680 register ADDRESS *a;
1681 bool follow;
1682 {
1683 register MAILER *m;
1684 MAILER pseudomailer;
1685 register struct qflags *qfp;
1686 bool firstone;
1687
1688 if (a == NULL)
1689 {
1690 printf("[NULL]\n");
1691 return;
1692 }
1693
1694 while (a != NULL)
1695 {
1696 printf("%x=", a);
1697 (void) fflush(stdout);
1698
1699 /* find the mailer -- carefully */
1700 m = a->q_mailer;
1701 if (m == NULL)
1702 {
1703 m = &pseudomailer;
1704 m->m_mno = -1;
1705 m->m_name = "NULL";
1706 }
1707
1708 printf("%s:\n\tmailer %d (%s), host `%s'\n",
1709 a->q_paddr, m->m_mno, m->m_name,
1710 a->q_host == NULL ? "<null>" : a->q_host);
1711 printf("\tuser `%s', ruser `%s'\n",
1712 a->q_user,
1713 a->q_ruser == NULL ? "<null>" : a->q_ruser);
1714 printf("\tnext=%x, alias %x, uid %d, gid %d\n",
1715 a->q_next, a->q_alias, a->q_uid, a->q_gid);
1716 printf("\tflags=%lx<", a->q_flags);
1717 firstone = TRUE;
1718 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
1719 {
1720 if (!bitset(qfp->qf_bit, a->q_flags))
1721 continue;
1722 if (!firstone)
1723 printf(",");
1724 firstone = FALSE;
1725 printf("%s", qfp->qf_name);
1726 }
1727 printf(">\n");
1728 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
1729 a->q_owner == NULL ? "(none)" : a->q_owner,
1730 a->q_home == NULL ? "(none)" : a->q_home,
1731 a->q_fullname == NULL ? "(none)" : a->q_fullname);
1732 printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n",
1733 a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
1734 a->q_statmta == NULL ? "(none)" : a->q_statmta,
1735 a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
1736
1737 if (!follow)
1738 return;
1739 a = a->q_next;
1740 }
1741 }
1742 /*
1743 ** EMPTYADDR -- return TRUE if this address is empty (``<>'')
1744 **
1745 ** Parameters:
1746 ** a -- pointer to the address
1747 **
1748 ** Returns:
1749 ** TRUE -- if this address is "empty" (i.e., no one should
1750 ** ever generate replies to it.
1751 ** FALSE -- if it is a "regular" (read: replyable) address.
1752 */
1753
1754 bool
emptyaddr(a)1755 emptyaddr(a)
1756 register ADDRESS *a;
1757 {
1758 return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
1759 }
1760 /*
1761 ** REMOTENAME -- return the name relative to the current mailer
1762 **
1763 ** Parameters:
1764 ** name -- the name to translate.
1765 ** m -- the mailer that we want to do rewriting relative
1766 ** to.
1767 ** flags -- fine tune operations.
1768 ** pstat -- pointer to status word.
1769 ** e -- the current envelope.
1770 **
1771 ** Returns:
1772 ** the text string representing this address relative to
1773 ** the receiving mailer.
1774 **
1775 ** Side Effects:
1776 ** none.
1777 **
1778 ** Warnings:
1779 ** The text string returned is tucked away locally;
1780 ** copy it if you intend to save it.
1781 */
1782
1783 char *
remotename(name,m,flags,pstat,e)1784 remotename(name, m, flags, pstat, e)
1785 char *name;
1786 struct mailer *m;
1787 int flags;
1788 int *pstat;
1789 register ENVELOPE *e;
1790 {
1791 register char **pvp;
1792 char *fancy;
1793 char *oldg = macvalue('g', e);
1794 int rwset;
1795 static char buf[MAXNAME + 1];
1796 char lbuf[MAXNAME + 1];
1797 char pvpbuf[PSBUFSIZE];
1798 extern char *crackaddr();
1799
1800 if (tTd(12, 1))
1801 printf("remotename(%s)\n", name);
1802
1803 /* don't do anything if we are tagging it as special */
1804 if (bitset(RF_SENDERADDR, flags))
1805 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
1806 : m->m_se_rwset;
1807 else
1808 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
1809 : m->m_re_rwset;
1810 if (rwset < 0)
1811 return (name);
1812
1813 /*
1814 ** Do a heuristic crack of this name to extract any comment info.
1815 ** This will leave the name as a comment and a $g macro.
1816 */
1817
1818 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
1819 fancy = "\201g";
1820 else
1821 fancy = crackaddr(name);
1822
1823 /*
1824 ** Turn the name into canonical form.
1825 ** Normally this will be RFC 822 style, i.e., "user@domain".
1826 ** If this only resolves to "user", and the "C" flag is
1827 ** specified in the sending mailer, then the sender's
1828 ** domain will be appended.
1829 */
1830
1831 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
1832 if (pvp == NULL)
1833 return (name);
1834 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1835 *pstat = EX_TEMPFAIL;
1836 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
1837 {
1838 /* append from domain to this address */
1839 register char **pxp = pvp;
1840
1841 /* see if there is an "@domain" in the current name */
1842 while (*pxp != NULL && strcmp(*pxp, "@") != 0)
1843 pxp++;
1844 if (*pxp == NULL)
1845 {
1846 /* no.... append the "@domain" from the sender */
1847 register char **qxq = e->e_fromdomain;
1848
1849 while ((*pxp++ = *qxq++) != NULL)
1850 continue;
1851 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
1852 *pstat = EX_TEMPFAIL;
1853 }
1854 }
1855
1856 /*
1857 ** Do more specific rewriting.
1858 ** Rewrite using ruleset 1 or 2 depending on whether this is
1859 ** a sender address or not.
1860 ** Then run it through any receiving-mailer-specific rulesets.
1861 */
1862
1863 if (bitset(RF_SENDERADDR, flags))
1864 {
1865 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
1866 *pstat = EX_TEMPFAIL;
1867 }
1868 else
1869 {
1870 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
1871 *pstat = EX_TEMPFAIL;
1872 }
1873 if (rwset > 0)
1874 {
1875 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
1876 *pstat = EX_TEMPFAIL;
1877 }
1878
1879 /*
1880 ** Do any final sanitation the address may require.
1881 ** This will normally be used to turn internal forms
1882 ** (e.g., user@host.LOCAL) into external form. This
1883 ** may be used as a default to the above rules.
1884 */
1885
1886 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
1887 *pstat = EX_TEMPFAIL;
1888
1889 /*
1890 ** Now restore the comment information we had at the beginning.
1891 */
1892
1893 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
1894 define('g', lbuf, e);
1895
1896 /* need to make sure route-addrs have <angle brackets> */
1897 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
1898 expand("<\201g>", buf, sizeof buf, e);
1899 else
1900 expand(fancy, buf, sizeof buf, e);
1901
1902 define('g', oldg, e);
1903
1904 if (tTd(12, 1))
1905 printf("remotename => `%s'\n", buf);
1906 return (buf);
1907 }
1908 /*
1909 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
1910 **
1911 ** Parameters:
1912 ** a -- the address to map (but just the user name part).
1913 ** sendq -- the sendq in which to install any replacement
1914 ** addresses.
1915 ** aliaslevel -- the alias nesting depth.
1916 ** e -- the envelope.
1917 **
1918 ** Returns:
1919 ** none.
1920 */
1921
1922 void
maplocaluser(a,sendq,aliaslevel,e)1923 maplocaluser(a, sendq, aliaslevel, e)
1924 register ADDRESS *a;
1925 ADDRESS **sendq;
1926 int aliaslevel;
1927 ENVELOPE *e;
1928 {
1929 register char **pvp;
1930 register ADDRESS *a1 = NULL;
1931 auto char *delimptr;
1932 char pvpbuf[PSBUFSIZE];
1933
1934 if (tTd(29, 1))
1935 {
1936 printf("maplocaluser: ");
1937 printaddr(a, FALSE);
1938 }
1939 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
1940 if (pvp == NULL)
1941 return;
1942
1943 (void) rewrite(pvp, 5, 0, e);
1944 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
1945 return;
1946
1947 /* if non-null, mailer destination specified -- has it changed? */
1948 a1 = buildaddr(pvp, NULL, 0, e);
1949 if (a1 == NULL || sameaddr(a, a1))
1950 return;
1951
1952 /* mark old address as dead; insert new address */
1953 a->q_flags |= QDONTSEND;
1954 if (tTd(29, 5))
1955 {
1956 printf("maplocaluser: QDONTSEND ");
1957 printaddr(a, FALSE);
1958 }
1959 a1->q_alias = a;
1960 allocaddr(a1, RF_COPYALL, NULL);
1961 (void) recipient(a1, sendq, aliaslevel, e);
1962 }
1963 /*
1964 ** DEQUOTE_INIT -- initialize dequote map
1965 **
1966 ** This is a no-op.
1967 **
1968 ** Parameters:
1969 ** map -- the internal map structure.
1970 ** args -- arguments.
1971 **
1972 ** Returns:
1973 ** TRUE.
1974 */
1975
1976 bool
dequote_init(map,args)1977 dequote_init(map, args)
1978 MAP *map;
1979 char *args;
1980 {
1981 register char *p = args;
1982
1983 map->map_mflags |= MF_KEEPQUOTES;
1984 for (;;)
1985 {
1986 while (isascii(*p) && isspace(*p))
1987 p++;
1988 if (*p != '-')
1989 break;
1990 switch (*++p)
1991 {
1992 case 'a':
1993 map->map_app = ++p;
1994 break;
1995
1996 case 's':
1997 map->map_coldelim = *++p;
1998 break;
1999 }
2000 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
2001 p++;
2002 if (*p != '\0')
2003 *p = '\0';
2004 }
2005 if (map->map_app != NULL)
2006 map->map_app = newstr(map->map_app);
2007
2008 return TRUE;
2009 }
2010 /*
2011 ** DEQUOTE_MAP -- unquote an address
2012 **
2013 ** Parameters:
2014 ** map -- the internal map structure (ignored).
2015 ** name -- the name to dequote.
2016 ** av -- arguments (ignored).
2017 ** statp -- pointer to status out-parameter.
2018 **
2019 ** Returns:
2020 ** NULL -- if there were no quotes, or if the resulting
2021 ** unquoted buffer would not be acceptable to prescan.
2022 ** else -- The dequoted buffer.
2023 */
2024
2025 char *
dequote_map(map,name,av,statp)2026 dequote_map(map, name, av, statp)
2027 MAP *map;
2028 char *name;
2029 char **av;
2030 int *statp;
2031 {
2032 register char *p;
2033 register char *q;
2034 register char c;
2035 int anglecnt = 0;
2036 int cmntcnt = 0;
2037 int quotecnt = 0;
2038 int spacecnt = 0;
2039 bool quotemode = FALSE;
2040 bool bslashmode = FALSE;
2041 char spacesub = map->map_coldelim;
2042
2043 for (p = q = name; (c = *p++) != '\0'; )
2044 {
2045 if (bslashmode)
2046 {
2047 bslashmode = FALSE;
2048 *q++ = c;
2049 continue;
2050 }
2051
2052 if (c == ' ' && spacesub != '\0')
2053 c = spacesub;
2054
2055 switch (c)
2056 {
2057 case '\\':
2058 bslashmode = TRUE;
2059 break;
2060
2061 case '(':
2062 cmntcnt++;
2063 break;
2064
2065 case ')':
2066 if (cmntcnt-- <= 0)
2067 return NULL;
2068 break;
2069
2070 case ' ':
2071 spacecnt++;
2072 break;
2073 }
2074
2075 if (cmntcnt > 0)
2076 {
2077 *q++ = c;
2078 continue;
2079 }
2080
2081 switch (c)
2082 {
2083 case '"':
2084 quotemode = !quotemode;
2085 quotecnt++;
2086 continue;
2087
2088 case '<':
2089 anglecnt++;
2090 break;
2091
2092 case '>':
2093 if (anglecnt-- <= 0)
2094 return NULL;
2095 break;
2096 }
2097 *q++ = c;
2098 }
2099
2100 if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
2101 quotemode || quotecnt <= 0 || spacecnt != 0)
2102 return NULL;
2103 *q++ = '\0';
2104 return name;
2105 }
2106