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