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.68 (Berkeley) 04/25/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 /* XXX should try to auto-open the map here */ 1146 1147 if (tTd(60, 1)) 1148 printf("map_lookup(%s, %s) => ", 1149 mapname, buf); 1150 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 1151 buf, argvect, &stat); 1152 if (tTd(60, 1)) 1153 printf("%s (%d)\n", 1154 replac ? replac : "NOT FOUND", 1155 stat); 1156 1157 /* should recover if stat == EX_TEMPFAIL */ 1158 if (stat == EX_TEMPFAIL) 1159 { 1160 rstat = EX_TEMPFAIL; 1161 if (tTd(50, 1)) 1162 printf("map_lookup(%s, %s) failed (stat = %d)\n", 1163 mapname, buf, stat); 1164 if (e->e_message == NULL) 1165 { 1166 char mbuf[300]; 1167 1168 sprintf(mbuf, "map %s: lookup (%s) failed", 1169 mapname, buf); 1170 e->e_message = newstr(mbuf); 1171 } 1172 } 1173 } 1174 else 1175 replac = NULL; 1176 1177 /* if no replacement, use default */ 1178 if (replac == NULL && default_rvp != NULL) 1179 { 1180 /* create the default */ 1181 cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 1182 replac = buf; 1183 } 1184 1185 if (replac == NULL) 1186 { 1187 xpvp = key_rvp; 1188 } 1189 else if (*replac == '\0') 1190 { 1191 /* null replacement */ 1192 nullpvp[0] = NULL; 1193 xpvp = nullpvp; 1194 } 1195 else 1196 { 1197 /* scan the new replacement */ 1198 xpvp = prescan(replac, '\0', pvpbuf, 1199 sizeof pvpbuf, NULL, NULL); 1200 if (xpvp == NULL) 1201 { 1202 /* prescan already printed error */ 1203 return EX_DATAERR; 1204 } 1205 } 1206 1207 /* append it to the token list */ 1208 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1209 { 1210 *avp++ = newstr(*xpvp); 1211 if (avp >= &npvp[MAXATOM]) 1212 goto toolong; 1213 } 1214 1215 /* restore the old trailing information */ 1216 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1217 if (avp >= &npvp[MAXATOM]) 1218 goto toolong; 1219 1220 break; 1221 } 1222 1223 /* 1224 ** Check for subroutine calls. 1225 */ 1226 1227 if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 1228 { 1229 int stat; 1230 1231 if (npvp[1] == NULL) 1232 { 1233 syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 1234 ruleset, ruleno); 1235 *pvp = NULL; 1236 } 1237 else 1238 { 1239 int ruleset; 1240 STAB *s; 1241 1242 bcopy((char *) &npvp[2], (char *) pvp, 1243 (int) (avp - npvp - 2) * sizeof *avp); 1244 if (tTd(21, 3)) 1245 printf("-----callsubr %s\n", npvp[1]); 1246 s = stab(npvp[1], ST_RULESET, ST_FIND); 1247 if (s == NULL) 1248 ruleset = atoi(npvp[1]); 1249 else 1250 ruleset = s->s_ruleset; 1251 stat = rewrite(pvp, ruleset, reclevel, e); 1252 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1253 rstat = stat; 1254 if (*pvp != NULL && (**pvp & 0377) == CANONNET) 1255 rwr = NULL; 1256 } 1257 } 1258 else 1259 { 1260 bcopy((char *) npvp, (char *) pvp, 1261 (int) (avp - npvp) * sizeof *avp); 1262 } 1263 if (tTd(21, 4)) 1264 { 1265 printf("rewritten as:"); 1266 printav(pvp); 1267 } 1268 } 1269 1270 if (OpMode == MD_TEST || tTd(21, 1)) 1271 { 1272 printf("rewrite: ruleset %2d returns:", ruleset); 1273 printav(pvp); 1274 } 1275 1276 return rstat; 1277 } 1278 /* 1279 ** BUILDADDR -- build address from token vector. 1280 ** 1281 ** Parameters: 1282 ** tv -- token vector. 1283 ** a -- pointer to address descriptor to fill. 1284 ** If NULL, one will be allocated. 1285 ** flags -- info regarding whether this is a sender or 1286 ** a recipient. 1287 ** e -- the current envelope. 1288 ** 1289 ** Returns: 1290 ** NULL if there was an error. 1291 ** 'a' otherwise. 1292 ** 1293 ** Side Effects: 1294 ** fills in 'a' 1295 */ 1296 1297 struct errcodes 1298 { 1299 char *ec_name; /* name of error code */ 1300 int ec_code; /* numeric code */ 1301 } ErrorCodes[] = 1302 { 1303 "usage", EX_USAGE, 1304 "nouser", EX_NOUSER, 1305 "nohost", EX_NOHOST, 1306 "unavailable", EX_UNAVAILABLE, 1307 "software", EX_SOFTWARE, 1308 "tempfail", EX_TEMPFAIL, 1309 "protocol", EX_PROTOCOL, 1310 #ifdef EX_CONFIG 1311 "config", EX_CONFIG, 1312 #endif 1313 NULL, EX_UNAVAILABLE, 1314 }; 1315 1316 ADDRESS * 1317 buildaddr(tv, a, flags, e) 1318 register char **tv; 1319 register ADDRESS *a; 1320 int flags; 1321 register ENVELOPE *e; 1322 { 1323 struct mailer **mp; 1324 register struct mailer *m; 1325 register char *p; 1326 char *bp; 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 cataddr(pvp, evp, buf, sz, spacesub) 1538 char **pvp; 1539 char **evp; 1540 char *buf; 1541 register int sz; 1542 char spacesub; 1543 { 1544 bool oatomtok = FALSE; 1545 bool natomtok = FALSE; 1546 register int i; 1547 register char *p; 1548 1549 if (spacesub == '\0') 1550 spacesub = SpaceSub; 1551 1552 if (pvp == NULL) 1553 { 1554 (void) strcpy(buf, ""); 1555 return; 1556 } 1557 p = buf; 1558 sz -= 2; 1559 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1560 { 1561 natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 1562 if (oatomtok && natomtok) 1563 *p++ = spacesub; 1564 (void) strcpy(p, *pvp); 1565 oatomtok = natomtok; 1566 p += i; 1567 sz -= i + 1; 1568 if (pvp++ == evp) 1569 break; 1570 } 1571 *p = '\0'; 1572 } 1573 /* 1574 ** SAMEADDR -- Determine if two addresses are the same 1575 ** 1576 ** This is not just a straight comparison -- if the mailer doesn't 1577 ** care about the host we just ignore it, etc. 1578 ** 1579 ** Parameters: 1580 ** a, b -- pointers to the internal forms to compare. 1581 ** 1582 ** Returns: 1583 ** TRUE -- they represent the same mailbox. 1584 ** FALSE -- they don't. 1585 ** 1586 ** Side Effects: 1587 ** none. 1588 */ 1589 1590 bool 1591 sameaddr(a, b) 1592 register ADDRESS *a; 1593 register ADDRESS *b; 1594 { 1595 register ADDRESS *ca, *cb; 1596 1597 /* if they don't have the same mailer, forget it */ 1598 if (a->q_mailer != b->q_mailer) 1599 return (FALSE); 1600 1601 /* if the user isn't the same, we can drop out */ 1602 if (strcmp(a->q_user, b->q_user) != 0) 1603 return (FALSE); 1604 1605 /* if we have good uids for both but they differ, these are different */ 1606 if (a->q_mailer == ProgMailer) 1607 { 1608 ca = getctladdr(a); 1609 cb = getctladdr(b); 1610 if (ca != NULL && cb != NULL && 1611 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1612 ca->q_uid != cb->q_uid) 1613 return (FALSE); 1614 } 1615 1616 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1617 if (a->q_host == b->q_host) 1618 { 1619 /* probably both null pointers */ 1620 return (TRUE); 1621 } 1622 if (a->q_host == NULL || b->q_host == NULL) 1623 { 1624 /* only one is a null pointer */ 1625 return (FALSE); 1626 } 1627 if (strcmp(a->q_host, b->q_host) != 0) 1628 return (FALSE); 1629 1630 return (TRUE); 1631 } 1632 /* 1633 ** PRINTADDR -- print address (for debugging) 1634 ** 1635 ** Parameters: 1636 ** a -- the address to print 1637 ** follow -- follow the q_next chain. 1638 ** 1639 ** Returns: 1640 ** none. 1641 ** 1642 ** Side Effects: 1643 ** none. 1644 */ 1645 1646 struct qflags 1647 { 1648 char *qf_name; 1649 u_long qf_bit; 1650 }; 1651 1652 struct qflags AddressFlags[] = 1653 { 1654 "QDONTSEND", QDONTSEND, 1655 "QBADADDR", QBADADDR, 1656 "QGOODUID", QGOODUID, 1657 "QPRIMARY", QPRIMARY, 1658 "QQUEUEUP", QQUEUEUP, 1659 "QSENT", QSENT, 1660 "QNOTREMOTE", QNOTREMOTE, 1661 "QSELFREF", QSELFREF, 1662 "QVERIFIED", QVERIFIED, 1663 "QBOGUSSHELL", QBOGUSSHELL, 1664 "QUNSAFEADDR", QUNSAFEADDR, 1665 "QPINGONSUCCESS", QPINGONSUCCESS, 1666 "QPINGONFAILURE", QPINGONFAILURE, 1667 "QPINGONDELAY", QPINGONDELAY, 1668 "QHASNOTIFY", QHASNOTIFY, 1669 "QRELAYED", QRELAYED, 1670 "QEXPANDED", QEXPANDED, 1671 "QDELIVERED", QDELIVERED, 1672 "QDELAYED", QDELAYED, 1673 "QTHISPASS", QTHISPASS, 1674 NULL 1675 }; 1676 1677 void 1678 printaddr(a, follow) 1679 register ADDRESS *a; 1680 bool follow; 1681 { 1682 register MAILER *m; 1683 MAILER pseudomailer; 1684 register struct qflags *qfp; 1685 bool firstone; 1686 1687 if (a == NULL) 1688 { 1689 printf("[NULL]\n"); 1690 return; 1691 } 1692 1693 while (a != NULL) 1694 { 1695 printf("%x=", a); 1696 (void) fflush(stdout); 1697 1698 /* find the mailer -- carefully */ 1699 m = a->q_mailer; 1700 if (m == NULL) 1701 { 1702 m = &pseudomailer; 1703 m->m_mno = -1; 1704 m->m_name = "NULL"; 1705 } 1706 1707 printf("%s:\n\tmailer %d (%s), host `%s'\n", 1708 a->q_paddr, m->m_mno, m->m_name, 1709 a->q_host == NULL ? "<null>" : a->q_host); 1710 printf("\tuser `%s', ruser `%s'\n", 1711 a->q_user, 1712 a->q_ruser == NULL ? "<null>" : a->q_ruser); 1713 printf("\tnext=%x, alias %x, uid %d, gid %d\n", 1714 a->q_next, a->q_alias, a->q_uid, a->q_gid); 1715 printf("\tflags=%lx<", a->q_flags); 1716 firstone = TRUE; 1717 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 1718 { 1719 if (!bitset(qfp->qf_bit, a->q_flags)) 1720 continue; 1721 if (!firstone) 1722 printf(","); 1723 firstone = FALSE; 1724 printf("%s", qfp->qf_name); 1725 } 1726 printf(">\n"); 1727 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1728 a->q_owner == NULL ? "(none)" : a->q_owner, 1729 a->q_home == NULL ? "(none)" : a->q_home, 1730 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1731 printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 1732 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 1733 a->q_statmta == NULL ? "(none)" : a->q_statmta, 1734 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 1735 1736 if (!follow) 1737 return; 1738 a = a->q_next; 1739 } 1740 } 1741 /* 1742 ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 1743 ** 1744 ** Parameters: 1745 ** a -- pointer to the address 1746 ** 1747 ** Returns: 1748 ** TRUE -- if this address is "empty" (i.e., no one should 1749 ** ever generate replies to it. 1750 ** FALSE -- if it is a "regular" (read: replyable) address. 1751 */ 1752 1753 bool 1754 emptyaddr(a) 1755 register ADDRESS *a; 1756 { 1757 return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 1758 } 1759 /* 1760 ** REMOTENAME -- return the name relative to the current mailer 1761 ** 1762 ** Parameters: 1763 ** name -- the name to translate. 1764 ** m -- the mailer that we want to do rewriting relative 1765 ** to. 1766 ** flags -- fine tune operations. 1767 ** pstat -- pointer to status word. 1768 ** e -- the current envelope. 1769 ** 1770 ** Returns: 1771 ** the text string representing this address relative to 1772 ** the receiving mailer. 1773 ** 1774 ** Side Effects: 1775 ** none. 1776 ** 1777 ** Warnings: 1778 ** The text string returned is tucked away locally; 1779 ** copy it if you intend to save it. 1780 */ 1781 1782 char * 1783 remotename(name, m, flags, pstat, e) 1784 char *name; 1785 struct mailer *m; 1786 int flags; 1787 int *pstat; 1788 register ENVELOPE *e; 1789 { 1790 register char **pvp; 1791 char *fancy; 1792 char *oldg = macvalue('g', e); 1793 int rwset; 1794 static char buf[MAXNAME + 1]; 1795 char lbuf[MAXNAME + 1]; 1796 char pvpbuf[PSBUFSIZE]; 1797 extern char *crackaddr(); 1798 1799 if (tTd(12, 1)) 1800 printf("remotename(%s)\n", name); 1801 1802 /* don't do anything if we are tagging it as special */ 1803 if (bitset(RF_SENDERADDR, flags)) 1804 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1805 : m->m_se_rwset; 1806 else 1807 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1808 : m->m_re_rwset; 1809 if (rwset < 0) 1810 return (name); 1811 1812 /* 1813 ** Do a heuristic crack of this name to extract any comment info. 1814 ** This will leave the name as a comment and a $g macro. 1815 */ 1816 1817 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1818 fancy = "\201g"; 1819 else 1820 fancy = crackaddr(name); 1821 1822 /* 1823 ** Turn the name into canonical form. 1824 ** Normally this will be RFC 822 style, i.e., "user@domain". 1825 ** If this only resolves to "user", and the "C" flag is 1826 ** specified in the sending mailer, then the sender's 1827 ** domain will be appended. 1828 */ 1829 1830 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 1831 if (pvp == NULL) 1832 return (name); 1833 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1834 *pstat = EX_TEMPFAIL; 1835 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1836 { 1837 /* append from domain to this address */ 1838 register char **pxp = pvp; 1839 1840 /* see if there is an "@domain" in the current name */ 1841 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1842 pxp++; 1843 if (*pxp == NULL) 1844 { 1845 /* no.... append the "@domain" from the sender */ 1846 register char **qxq = e->e_fromdomain; 1847 1848 while ((*pxp++ = *qxq++) != NULL) 1849 continue; 1850 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1851 *pstat = EX_TEMPFAIL; 1852 } 1853 } 1854 1855 /* 1856 ** Do more specific rewriting. 1857 ** Rewrite using ruleset 1 or 2 depending on whether this is 1858 ** a sender address or not. 1859 ** Then run it through any receiving-mailer-specific rulesets. 1860 */ 1861 1862 if (bitset(RF_SENDERADDR, flags)) 1863 { 1864 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 1865 *pstat = EX_TEMPFAIL; 1866 } 1867 else 1868 { 1869 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 1870 *pstat = EX_TEMPFAIL; 1871 } 1872 if (rwset > 0) 1873 { 1874 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 1875 *pstat = EX_TEMPFAIL; 1876 } 1877 1878 /* 1879 ** Do any final sanitation the address may require. 1880 ** This will normally be used to turn internal forms 1881 ** (e.g., user@host.LOCAL) into external form. This 1882 ** may be used as a default to the above rules. 1883 */ 1884 1885 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 1886 *pstat = EX_TEMPFAIL; 1887 1888 /* 1889 ** Now restore the comment information we had at the beginning. 1890 */ 1891 1892 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1893 define('g', lbuf, e); 1894 1895 /* need to make sure route-addrs have <angle brackets> */ 1896 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 1897 expand("<\201g>", buf, sizeof buf, e); 1898 else 1899 expand(fancy, buf, sizeof buf, e); 1900 1901 define('g', oldg, e); 1902 1903 if (tTd(12, 1)) 1904 printf("remotename => `%s'\n", buf); 1905 return (buf); 1906 } 1907 /* 1908 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1909 ** 1910 ** Parameters: 1911 ** a -- the address to map (but just the user name part). 1912 ** sendq -- the sendq in which to install any replacement 1913 ** addresses. 1914 ** aliaslevel -- the alias nesting depth. 1915 ** e -- the envelope. 1916 ** 1917 ** Returns: 1918 ** none. 1919 */ 1920 1921 maplocaluser(a, sendq, aliaslevel, e) 1922 register ADDRESS *a; 1923 ADDRESS **sendq; 1924 int aliaslevel; 1925 ENVELOPE *e; 1926 { 1927 register char **pvp; 1928 register ADDRESS *a1 = NULL; 1929 auto char *delimptr; 1930 char pvpbuf[PSBUFSIZE]; 1931 1932 if (tTd(29, 1)) 1933 { 1934 printf("maplocaluser: "); 1935 printaddr(a, FALSE); 1936 } 1937 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 1938 if (pvp == NULL) 1939 return; 1940 1941 (void) rewrite(pvp, 5, 0, e); 1942 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1943 return; 1944 1945 /* if non-null, mailer destination specified -- has it changed? */ 1946 a1 = buildaddr(pvp, NULL, 0, e); 1947 if (a1 == NULL || sameaddr(a, a1)) 1948 return; 1949 1950 /* mark old address as dead; insert new address */ 1951 a->q_flags |= QDONTSEND; 1952 if (tTd(29, 5)) 1953 { 1954 printf("maplocaluser: QDONTSEND "); 1955 printaddr(a, FALSE); 1956 } 1957 a1->q_alias = a; 1958 allocaddr(a1, RF_COPYALL, NULL); 1959 (void) recipient(a1, sendq, aliaslevel, e); 1960 } 1961 /* 1962 ** DEQUOTE_INIT -- initialize dequote map 1963 ** 1964 ** This is a no-op. 1965 ** 1966 ** Parameters: 1967 ** map -- the internal map structure. 1968 ** args -- arguments. 1969 ** 1970 ** Returns: 1971 ** TRUE. 1972 */ 1973 1974 bool 1975 dequote_init(map, args) 1976 MAP *map; 1977 char *args; 1978 { 1979 register char *p = args; 1980 1981 for (;;) 1982 { 1983 while (isascii(*p) && isspace(*p)) 1984 p++; 1985 if (*p != '-') 1986 break; 1987 switch (*++p) 1988 { 1989 case 'a': 1990 map->map_app = ++p; 1991 break; 1992 1993 case 's': 1994 map->map_coldelim = *++p; 1995 break; 1996 } 1997 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1998 p++; 1999 if (*p != '\0') 2000 *p = '\0'; 2001 } 2002 if (map->map_app != NULL) 2003 map->map_app = newstr(map->map_app); 2004 2005 return TRUE; 2006 } 2007 /* 2008 ** DEQUOTE_MAP -- unquote an address 2009 ** 2010 ** Parameters: 2011 ** map -- the internal map structure (ignored). 2012 ** name -- the name to dequote. 2013 ** av -- arguments (ignored). 2014 ** statp -- pointer to status out-parameter. 2015 ** 2016 ** Returns: 2017 ** NULL -- if there were no quotes, or if the resulting 2018 ** unquoted buffer would not be acceptable to prescan. 2019 ** else -- The dequoted buffer. 2020 */ 2021 2022 char * 2023 dequote_map(map, name, av, statp) 2024 MAP *map; 2025 char *name; 2026 char **av; 2027 int *statp; 2028 { 2029 register char *p; 2030 register char *q; 2031 register char c; 2032 int anglecnt = 0; 2033 int cmntcnt = 0; 2034 int quotecnt = 0; 2035 int spacecnt = 0; 2036 bool quotemode = FALSE; 2037 bool bslashmode = FALSE; 2038 char spacesub = map->map_coldelim; 2039 2040 for (p = q = name; (c = *p++) != '\0'; ) 2041 { 2042 if (bslashmode) 2043 { 2044 bslashmode = FALSE; 2045 *q++ = c; 2046 continue; 2047 } 2048 2049 if (c == ' ' && spacesub != '\0') 2050 c = spacesub; 2051 2052 switch (c) 2053 { 2054 case '\\': 2055 bslashmode = TRUE; 2056 break; 2057 2058 case '(': 2059 cmntcnt++; 2060 break; 2061 2062 case ')': 2063 if (cmntcnt-- <= 0) 2064 return NULL; 2065 break; 2066 2067 case ' ': 2068 spacecnt++; 2069 break; 2070 } 2071 2072 if (cmntcnt > 0) 2073 { 2074 *q++ = c; 2075 continue; 2076 } 2077 2078 switch (c) 2079 { 2080 case '"': 2081 quotemode = !quotemode; 2082 quotecnt++; 2083 continue; 2084 2085 case '<': 2086 anglecnt++; 2087 break; 2088 2089 case '>': 2090 if (anglecnt-- <= 0) 2091 return NULL; 2092 break; 2093 } 2094 *q++ = c; 2095 } 2096 2097 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2098 quotemode || quotecnt <= 0 || spacecnt != 0) 2099 return NULL; 2100 *q++ = '\0'; 2101 return name; 2102 } 2103