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.70 (Berkeley) 05/28/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 * 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 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 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 ** 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 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(50, 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 s = stab(npvp[1], ST_RULESET, ST_FIND); 1252 if (s == NULL) 1253 ruleset = atoi(npvp[1]); 1254 else 1255 ruleset = s->s_ruleset; 1256 stat = rewrite(pvp, ruleset, reclevel, e); 1257 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1258 rstat = stat; 1259 if (*pvp != NULL && (**pvp & 0377) == CANONNET) 1260 rwr = NULL; 1261 } 1262 } 1263 else 1264 { 1265 bcopy((char *) npvp, (char *) pvp, 1266 (int) (avp - npvp) * sizeof *avp); 1267 } 1268 if (tTd(21, 4)) 1269 { 1270 printf("rewritten as:"); 1271 printav(pvp); 1272 } 1273 } 1274 1275 if (OpMode == MD_TEST || tTd(21, 1)) 1276 { 1277 printf("rewrite: ruleset %2d returns:", ruleset); 1278 printav(pvp); 1279 } 1280 1281 return rstat; 1282 } 1283 /* 1284 ** BUILDADDR -- build address from token vector. 1285 ** 1286 ** Parameters: 1287 ** tv -- token vector. 1288 ** a -- pointer to address descriptor to fill. 1289 ** If NULL, one will be allocated. 1290 ** flags -- info regarding whether this is a sender or 1291 ** a recipient. 1292 ** e -- the current envelope. 1293 ** 1294 ** Returns: 1295 ** NULL if there was an error. 1296 ** 'a' otherwise. 1297 ** 1298 ** Side Effects: 1299 ** fills in 'a' 1300 */ 1301 1302 struct errcodes 1303 { 1304 char *ec_name; /* name of error code */ 1305 int ec_code; /* numeric code */ 1306 } ErrorCodes[] = 1307 { 1308 "usage", EX_USAGE, 1309 "nouser", EX_NOUSER, 1310 "nohost", EX_NOHOST, 1311 "unavailable", EX_UNAVAILABLE, 1312 "software", EX_SOFTWARE, 1313 "tempfail", EX_TEMPFAIL, 1314 "protocol", EX_PROTOCOL, 1315 #ifdef EX_CONFIG 1316 "config", EX_CONFIG, 1317 #endif 1318 NULL, EX_UNAVAILABLE, 1319 }; 1320 1321 ADDRESS * 1322 buildaddr(tv, a, flags, e) 1323 register char **tv; 1324 register ADDRESS *a; 1325 int flags; 1326 register ENVELOPE *e; 1327 { 1328 struct mailer **mp; 1329 register struct mailer *m; 1330 register char *p; 1331 char *mname; 1332 char **hostp; 1333 char hbuf[MAXNAME + 1]; 1334 static MAILER errormailer; 1335 static char *errorargv[] = { "ERROR", NULL }; 1336 static char ubuf[MAXNAME + 1]; 1337 1338 if (tTd(24, 5)) 1339 { 1340 printf("buildaddr, flags=%x, tv=", flags); 1341 printav(tv); 1342 } 1343 1344 if (a == NULL) 1345 a = (ADDRESS *) xalloc(sizeof *a); 1346 bzero((char *) a, sizeof *a); 1347 1348 /* set up default error return flags */ 1349 a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 1350 1351 /* figure out what net/mailer to use */ 1352 if (*tv == NULL || (**tv & 0377) != CANONNET) 1353 { 1354 syserr("554 buildaddr: no net"); 1355 badaddr: 1356 a->q_flags |= QBADADDR; 1357 a->q_mailer = &errormailer; 1358 if (errormailer.m_name == NULL) 1359 { 1360 /* initialize the bogus mailer */ 1361 errormailer.m_name = "*error*"; 1362 errormailer.m_mailer = "ERROR"; 1363 errormailer.m_argv = errorargv; 1364 } 1365 return a; 1366 } 1367 mname = *++tv; 1368 1369 /* extract host and user portions */ 1370 if ((**++tv & 0377) == CANONHOST) 1371 hostp = ++tv; 1372 else 1373 hostp = NULL; 1374 while (*tv != NULL && (**tv & 0377) != CANONUSER) 1375 tv++; 1376 if (*tv == NULL) 1377 { 1378 syserr("554 buildaddr: no user"); 1379 goto badaddr; 1380 } 1381 if (hostp != NULL) 1382 cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1383 cataddr(++tv, NULL, ubuf, sizeof ubuf, '\0'); 1384 1385 /* save away the host name */ 1386 if (strcasecmp(mname, "error") == 0) 1387 { 1388 if (hostp != NULL) 1389 { 1390 register struct errcodes *ep; 1391 1392 if (strchr(hbuf, '.') != NULL) 1393 { 1394 a->q_status = newstr(hbuf); 1395 setstat(dsntoexitstat(hbuf)); 1396 } 1397 else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 1398 { 1399 setstat(atoi(hbuf)); 1400 } 1401 else 1402 { 1403 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1404 if (strcasecmp(ep->ec_name, hbuf) == 0) 1405 break; 1406 setstat(ep->ec_code); 1407 } 1408 } 1409 else 1410 setstat(EX_UNAVAILABLE); 1411 stripquotes(ubuf); 1412 if (isascii(ubuf[0]) && isdigit(ubuf[0]) && 1413 isascii(ubuf[1]) && isdigit(ubuf[1]) && 1414 isascii(ubuf[2]) && isdigit(ubuf[2]) && 1415 ubuf[3] == ' ') 1416 { 1417 char fmt[10]; 1418 1419 strncpy(fmt, ubuf, 3); 1420 strcpy(&fmt[3], " %s"); 1421 usrerr(fmt, ubuf + 4); 1422 1423 /* 1424 ** If this is a 4xx code and we aren't running 1425 ** SMTP on our input, bounce this message; 1426 ** otherwise it disappears without a trace. 1427 */ 1428 1429 if (fmt[0] == '4' && OpMode != MD_SMTP && 1430 OpMode != MD_DAEMON) 1431 { 1432 e->e_flags |= EF_FATALERRS; 1433 } 1434 } 1435 else 1436 { 1437 usrerr("553 %s", ubuf); 1438 } 1439 goto badaddr; 1440 } 1441 1442 for (mp = Mailer; (m = *mp++) != NULL; ) 1443 { 1444 if (strcasecmp(m->m_name, mname) == 0) 1445 break; 1446 } 1447 if (m == NULL) 1448 { 1449 syserr("554 buildaddr: unknown mailer %s", mname); 1450 goto badaddr; 1451 } 1452 a->q_mailer = m; 1453 1454 /* figure out what host (if any) */ 1455 if (hostp == NULL) 1456 { 1457 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1458 { 1459 syserr("554 buildaddr: no host"); 1460 goto badaddr; 1461 } 1462 a->q_host = NULL; 1463 } 1464 else 1465 a->q_host = newstr(hbuf); 1466 1467 /* figure out the user */ 1468 p = ubuf; 1469 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 1470 { 1471 p++; 1472 tv++; 1473 a->q_flags |= QNOTREMOTE; 1474 } 1475 1476 /* do special mapping for local mailer */ 1477 if (*p == '"') 1478 p++; 1479 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 1480 a->q_mailer = m = ProgMailer; 1481 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 1482 a->q_mailer = m = FileMailer; 1483 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 1484 { 1485 /* may be :include: */ 1486 stripquotes(ubuf); 1487 if (strncasecmp(ubuf, ":include:", 9) == 0) 1488 { 1489 /* if :include:, don't need further rewriting */ 1490 a->q_mailer = m = InclMailer; 1491 a->q_user = newstr(&ubuf[9]); 1492 return a; 1493 } 1494 } 1495 1496 /* rewrite according recipient mailer rewriting rules */ 1497 define('h', a->q_host, e); 1498 if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1499 { 1500 /* sender addresses done later */ 1501 (void) rewrite(tv, 2, 0, e); 1502 if (m->m_re_rwset > 0) 1503 (void) rewrite(tv, m->m_re_rwset, 0, e); 1504 } 1505 (void) rewrite(tv, 4, 0, e); 1506 1507 /* save the result for the command line/RCPT argument */ 1508 cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 1509 a->q_user = ubuf; 1510 1511 /* 1512 ** Do mapping to lower case as requested by mailer 1513 */ 1514 1515 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1516 makelower(a->q_host); 1517 if (!bitnset(M_USR_UPPER, m->m_flags)) 1518 makelower(a->q_user); 1519 1520 return a; 1521 } 1522 /* 1523 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1524 ** 1525 ** Parameters: 1526 ** pvp -- parameter vector to rebuild. 1527 ** evp -- last parameter to include. Can be NULL to 1528 ** use entire pvp. 1529 ** buf -- buffer to build the string into. 1530 ** sz -- size of buf. 1531 ** spacesub -- the space separator character; if null, 1532 ** use SpaceSub. 1533 ** 1534 ** Returns: 1535 ** none. 1536 ** 1537 ** Side Effects: 1538 ** Destroys buf. 1539 */ 1540 1541 void 1542 cataddr(pvp, evp, buf, sz, spacesub) 1543 char **pvp; 1544 char **evp; 1545 char *buf; 1546 register int sz; 1547 int spacesub; 1548 { 1549 bool oatomtok = FALSE; 1550 bool natomtok = FALSE; 1551 register int i; 1552 register char *p; 1553 1554 if (spacesub == '\0') 1555 spacesub = SpaceSub; 1556 1557 if (pvp == NULL) 1558 { 1559 (void) strcpy(buf, ""); 1560 return; 1561 } 1562 p = buf; 1563 sz -= 2; 1564 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1565 { 1566 natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 1567 if (oatomtok && natomtok) 1568 *p++ = spacesub; 1569 (void) strcpy(p, *pvp); 1570 oatomtok = natomtok; 1571 p += i; 1572 sz -= i + 1; 1573 if (pvp++ == evp) 1574 break; 1575 } 1576 *p = '\0'; 1577 } 1578 /* 1579 ** SAMEADDR -- Determine if two addresses are the same 1580 ** 1581 ** This is not just a straight comparison -- if the mailer doesn't 1582 ** care about the host we just ignore it, etc. 1583 ** 1584 ** Parameters: 1585 ** a, b -- pointers to the internal forms to compare. 1586 ** 1587 ** Returns: 1588 ** TRUE -- they represent the same mailbox. 1589 ** FALSE -- they don't. 1590 ** 1591 ** Side Effects: 1592 ** none. 1593 */ 1594 1595 bool 1596 sameaddr(a, b) 1597 register ADDRESS *a; 1598 register ADDRESS *b; 1599 { 1600 register ADDRESS *ca, *cb; 1601 1602 /* if they don't have the same mailer, forget it */ 1603 if (a->q_mailer != b->q_mailer) 1604 return (FALSE); 1605 1606 /* if the user isn't the same, we can drop out */ 1607 if (strcmp(a->q_user, b->q_user) != 0) 1608 return (FALSE); 1609 1610 /* if we have good uids for both but they differ, these are different */ 1611 if (a->q_mailer == ProgMailer) 1612 { 1613 ca = getctladdr(a); 1614 cb = getctladdr(b); 1615 if (ca != NULL && cb != NULL && 1616 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1617 ca->q_uid != cb->q_uid) 1618 return (FALSE); 1619 } 1620 1621 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1622 if (a->q_host == b->q_host) 1623 { 1624 /* probably both null pointers */ 1625 return (TRUE); 1626 } 1627 if (a->q_host == NULL || b->q_host == NULL) 1628 { 1629 /* only one is a null pointer */ 1630 return (FALSE); 1631 } 1632 if (strcmp(a->q_host, b->q_host) != 0) 1633 return (FALSE); 1634 1635 return (TRUE); 1636 } 1637 /* 1638 ** PRINTADDR -- print address (for debugging) 1639 ** 1640 ** Parameters: 1641 ** a -- the address to print 1642 ** follow -- follow the q_next chain. 1643 ** 1644 ** Returns: 1645 ** none. 1646 ** 1647 ** Side Effects: 1648 ** none. 1649 */ 1650 1651 struct qflags 1652 { 1653 char *qf_name; 1654 u_long qf_bit; 1655 }; 1656 1657 struct qflags AddressFlags[] = 1658 { 1659 "QDONTSEND", QDONTSEND, 1660 "QBADADDR", QBADADDR, 1661 "QGOODUID", QGOODUID, 1662 "QPRIMARY", QPRIMARY, 1663 "QQUEUEUP", QQUEUEUP, 1664 "QSENT", QSENT, 1665 "QNOTREMOTE", QNOTREMOTE, 1666 "QSELFREF", QSELFREF, 1667 "QVERIFIED", QVERIFIED, 1668 "QBOGUSSHELL", QBOGUSSHELL, 1669 "QUNSAFEADDR", QUNSAFEADDR, 1670 "QPINGONSUCCESS", QPINGONSUCCESS, 1671 "QPINGONFAILURE", QPINGONFAILURE, 1672 "QPINGONDELAY", QPINGONDELAY, 1673 "QHASNOTIFY", QHASNOTIFY, 1674 "QRELAYED", QRELAYED, 1675 "QEXPANDED", QEXPANDED, 1676 "QDELIVERED", QDELIVERED, 1677 "QDELAYED", QDELAYED, 1678 "QTHISPASS", QTHISPASS, 1679 NULL 1680 }; 1681 1682 void 1683 printaddr(a, follow) 1684 register ADDRESS *a; 1685 bool follow; 1686 { 1687 register MAILER *m; 1688 MAILER pseudomailer; 1689 register struct qflags *qfp; 1690 bool firstone; 1691 1692 if (a == NULL) 1693 { 1694 printf("[NULL]\n"); 1695 return; 1696 } 1697 1698 while (a != NULL) 1699 { 1700 printf("%x=", a); 1701 (void) fflush(stdout); 1702 1703 /* find the mailer -- carefully */ 1704 m = a->q_mailer; 1705 if (m == NULL) 1706 { 1707 m = &pseudomailer; 1708 m->m_mno = -1; 1709 m->m_name = "NULL"; 1710 } 1711 1712 printf("%s:\n\tmailer %d (%s), host `%s'\n", 1713 a->q_paddr, m->m_mno, m->m_name, 1714 a->q_host == NULL ? "<null>" : a->q_host); 1715 printf("\tuser `%s', ruser `%s'\n", 1716 a->q_user, 1717 a->q_ruser == NULL ? "<null>" : a->q_ruser); 1718 printf("\tnext=%x, alias %x, uid %d, gid %d\n", 1719 a->q_next, a->q_alias, a->q_uid, a->q_gid); 1720 printf("\tflags=%lx<", a->q_flags); 1721 firstone = TRUE; 1722 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 1723 { 1724 if (!bitset(qfp->qf_bit, a->q_flags)) 1725 continue; 1726 if (!firstone) 1727 printf(","); 1728 firstone = FALSE; 1729 printf("%s", qfp->qf_name); 1730 } 1731 printf(">\n"); 1732 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1733 a->q_owner == NULL ? "(none)" : a->q_owner, 1734 a->q_home == NULL ? "(none)" : a->q_home, 1735 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1736 printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 1737 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 1738 a->q_statmta == NULL ? "(none)" : a->q_statmta, 1739 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 1740 1741 if (!follow) 1742 return; 1743 a = a->q_next; 1744 } 1745 } 1746 /* 1747 ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 1748 ** 1749 ** Parameters: 1750 ** a -- pointer to the address 1751 ** 1752 ** Returns: 1753 ** TRUE -- if this address is "empty" (i.e., no one should 1754 ** ever generate replies to it. 1755 ** FALSE -- if it is a "regular" (read: replyable) address. 1756 */ 1757 1758 bool 1759 emptyaddr(a) 1760 register ADDRESS *a; 1761 { 1762 return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 1763 } 1764 /* 1765 ** REMOTENAME -- return the name relative to the current mailer 1766 ** 1767 ** Parameters: 1768 ** name -- the name to translate. 1769 ** m -- the mailer that we want to do rewriting relative 1770 ** to. 1771 ** flags -- fine tune operations. 1772 ** pstat -- pointer to status word. 1773 ** e -- the current envelope. 1774 ** 1775 ** Returns: 1776 ** the text string representing this address relative to 1777 ** the receiving mailer. 1778 ** 1779 ** Side Effects: 1780 ** none. 1781 ** 1782 ** Warnings: 1783 ** The text string returned is tucked away locally; 1784 ** copy it if you intend to save it. 1785 */ 1786 1787 char * 1788 remotename(name, m, flags, pstat, e) 1789 char *name; 1790 struct mailer *m; 1791 int flags; 1792 int *pstat; 1793 register ENVELOPE *e; 1794 { 1795 register char **pvp; 1796 char *fancy; 1797 char *oldg = macvalue('g', e); 1798 int rwset; 1799 static char buf[MAXNAME + 1]; 1800 char lbuf[MAXNAME + 1]; 1801 char pvpbuf[PSBUFSIZE]; 1802 extern char *crackaddr(); 1803 1804 if (tTd(12, 1)) 1805 printf("remotename(%s)\n", name); 1806 1807 /* don't do anything if we are tagging it as special */ 1808 if (bitset(RF_SENDERADDR, flags)) 1809 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1810 : m->m_se_rwset; 1811 else 1812 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1813 : m->m_re_rwset; 1814 if (rwset < 0) 1815 return (name); 1816 1817 /* 1818 ** Do a heuristic crack of this name to extract any comment info. 1819 ** This will leave the name as a comment and a $g macro. 1820 */ 1821 1822 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1823 fancy = "\201g"; 1824 else 1825 fancy = crackaddr(name); 1826 1827 /* 1828 ** Turn the name into canonical form. 1829 ** Normally this will be RFC 822 style, i.e., "user@domain". 1830 ** If this only resolves to "user", and the "C" flag is 1831 ** specified in the sending mailer, then the sender's 1832 ** domain will be appended. 1833 */ 1834 1835 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 1836 if (pvp == NULL) 1837 return (name); 1838 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1839 *pstat = EX_TEMPFAIL; 1840 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1841 { 1842 /* append from domain to this address */ 1843 register char **pxp = pvp; 1844 1845 /* see if there is an "@domain" in the current name */ 1846 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1847 pxp++; 1848 if (*pxp == NULL) 1849 { 1850 /* no.... append the "@domain" from the sender */ 1851 register char **qxq = e->e_fromdomain; 1852 1853 while ((*pxp++ = *qxq++) != NULL) 1854 continue; 1855 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1856 *pstat = EX_TEMPFAIL; 1857 } 1858 } 1859 1860 /* 1861 ** Do more specific rewriting. 1862 ** Rewrite using ruleset 1 or 2 depending on whether this is 1863 ** a sender address or not. 1864 ** Then run it through any receiving-mailer-specific rulesets. 1865 */ 1866 1867 if (bitset(RF_SENDERADDR, flags)) 1868 { 1869 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 1870 *pstat = EX_TEMPFAIL; 1871 } 1872 else 1873 { 1874 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 1875 *pstat = EX_TEMPFAIL; 1876 } 1877 if (rwset > 0) 1878 { 1879 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 1880 *pstat = EX_TEMPFAIL; 1881 } 1882 1883 /* 1884 ** Do any final sanitation the address may require. 1885 ** This will normally be used to turn internal forms 1886 ** (e.g., user@host.LOCAL) into external form. This 1887 ** may be used as a default to the above rules. 1888 */ 1889 1890 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 1891 *pstat = EX_TEMPFAIL; 1892 1893 /* 1894 ** Now restore the comment information we had at the beginning. 1895 */ 1896 1897 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1898 define('g', lbuf, e); 1899 1900 /* need to make sure route-addrs have <angle brackets> */ 1901 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 1902 expand("<\201g>", buf, sizeof buf, e); 1903 else 1904 expand(fancy, buf, sizeof buf, e); 1905 1906 define('g', oldg, e); 1907 1908 if (tTd(12, 1)) 1909 printf("remotename => `%s'\n", buf); 1910 return (buf); 1911 } 1912 /* 1913 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1914 ** 1915 ** Parameters: 1916 ** a -- the address to map (but just the user name part). 1917 ** sendq -- the sendq in which to install any replacement 1918 ** addresses. 1919 ** aliaslevel -- the alias nesting depth. 1920 ** e -- the envelope. 1921 ** 1922 ** Returns: 1923 ** none. 1924 */ 1925 1926 void 1927 maplocaluser(a, sendq, aliaslevel, e) 1928 register ADDRESS *a; 1929 ADDRESS **sendq; 1930 int aliaslevel; 1931 ENVELOPE *e; 1932 { 1933 register char **pvp; 1934 register ADDRESS *a1 = NULL; 1935 auto char *delimptr; 1936 char pvpbuf[PSBUFSIZE]; 1937 1938 if (tTd(29, 1)) 1939 { 1940 printf("maplocaluser: "); 1941 printaddr(a, FALSE); 1942 } 1943 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 1944 if (pvp == NULL) 1945 return; 1946 1947 (void) rewrite(pvp, 5, 0, e); 1948 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1949 return; 1950 1951 /* if non-null, mailer destination specified -- has it changed? */ 1952 a1 = buildaddr(pvp, NULL, 0, e); 1953 if (a1 == NULL || sameaddr(a, a1)) 1954 return; 1955 1956 /* mark old address as dead; insert new address */ 1957 a->q_flags |= QDONTSEND; 1958 if (tTd(29, 5)) 1959 { 1960 printf("maplocaluser: QDONTSEND "); 1961 printaddr(a, FALSE); 1962 } 1963 a1->q_alias = a; 1964 allocaddr(a1, RF_COPYALL, NULL); 1965 (void) recipient(a1, sendq, aliaslevel, e); 1966 } 1967 /* 1968 ** DEQUOTE_INIT -- initialize dequote map 1969 ** 1970 ** This is a no-op. 1971 ** 1972 ** Parameters: 1973 ** map -- the internal map structure. 1974 ** args -- arguments. 1975 ** 1976 ** Returns: 1977 ** TRUE. 1978 */ 1979 1980 bool 1981 dequote_init(map, args) 1982 MAP *map; 1983 char *args; 1984 { 1985 register char *p = args; 1986 1987 for (;;) 1988 { 1989 while (isascii(*p) && isspace(*p)) 1990 p++; 1991 if (*p != '-') 1992 break; 1993 switch (*++p) 1994 { 1995 case 'a': 1996 map->map_app = ++p; 1997 break; 1998 1999 case 's': 2000 map->map_coldelim = *++p; 2001 break; 2002 } 2003 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2004 p++; 2005 if (*p != '\0') 2006 *p = '\0'; 2007 } 2008 if (map->map_app != NULL) 2009 map->map_app = newstr(map->map_app); 2010 2011 return TRUE; 2012 } 2013 /* 2014 ** DEQUOTE_MAP -- unquote an address 2015 ** 2016 ** Parameters: 2017 ** map -- the internal map structure (ignored). 2018 ** name -- the name to dequote. 2019 ** av -- arguments (ignored). 2020 ** statp -- pointer to status out-parameter. 2021 ** 2022 ** Returns: 2023 ** NULL -- if there were no quotes, or if the resulting 2024 ** unquoted buffer would not be acceptable to prescan. 2025 ** else -- The dequoted buffer. 2026 */ 2027 2028 char * 2029 dequote_map(map, name, av, statp) 2030 MAP *map; 2031 char *name; 2032 char **av; 2033 int *statp; 2034 { 2035 register char *p; 2036 register char *q; 2037 register char c; 2038 int anglecnt = 0; 2039 int cmntcnt = 0; 2040 int quotecnt = 0; 2041 int spacecnt = 0; 2042 bool quotemode = FALSE; 2043 bool bslashmode = FALSE; 2044 char spacesub = map->map_coldelim; 2045 2046 for (p = q = name; (c = *p++) != '\0'; ) 2047 { 2048 if (bslashmode) 2049 { 2050 bslashmode = FALSE; 2051 *q++ = c; 2052 continue; 2053 } 2054 2055 if (c == ' ' && spacesub != '\0') 2056 c = spacesub; 2057 2058 switch (c) 2059 { 2060 case '\\': 2061 bslashmode = TRUE; 2062 break; 2063 2064 case '(': 2065 cmntcnt++; 2066 break; 2067 2068 case ')': 2069 if (cmntcnt-- <= 0) 2070 return NULL; 2071 break; 2072 2073 case ' ': 2074 spacecnt++; 2075 break; 2076 } 2077 2078 if (cmntcnt > 0) 2079 { 2080 *q++ = c; 2081 continue; 2082 } 2083 2084 switch (c) 2085 { 2086 case '"': 2087 quotemode = !quotemode; 2088 quotecnt++; 2089 continue; 2090 2091 case '<': 2092 anglecnt++; 2093 break; 2094 2095 case '>': 2096 if (anglecnt-- <= 0) 2097 return NULL; 2098 break; 2099 } 2100 *q++ = c; 2101 } 2102 2103 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2104 quotemode || quotecnt <= 0 || spacecnt != 0) 2105 return NULL; 2106 *q++ = '\0'; 2107 return name; 2108 } 2109