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 * 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(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 * 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 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 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 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 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 * 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 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 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 * 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