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