1 /* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)parseaddr.c 8.156 (Berkeley) 10/27/1998"; 15 #endif /* not lint */ 16 17 # include "sendmail.h" 18 19 /* 20 ** PARSEADDR -- Parse an address 21 ** 22 ** Parses an address and breaks it up into three parts: a 23 ** net to transmit the message on, the host to transmit it 24 ** to, and a user on that host. These are loaded into an 25 ** ADDRESS header with the values squirreled away if necessary. 26 ** The "user" part may not be a real user; the process may 27 ** just reoccur on that machine. For example, on a machine 28 ** with an arpanet connection, the address 29 ** csvax.bill@berkeley 30 ** will break up to a "user" of 'csvax.bill' and a host 31 ** of 'berkeley' -- to be transmitted over the arpanet. 32 ** 33 ** Parameters: 34 ** addr -- the address to parse. 35 ** a -- a pointer to the address descriptor buffer. 36 ** If NULL, a header will be created. 37 ** flags -- describe detail for parsing. See RF_ definitions 38 ** in sendmail.h. 39 ** delim -- the character to terminate the address, passed 40 ** to prescan. 41 ** delimptr -- if non-NULL, set to the location of the 42 ** delim character that was found. 43 ** e -- the envelope that will contain this address. 44 ** 45 ** Returns: 46 ** A pointer to the address descriptor header (`a' if 47 ** `a' is non-NULL). 48 ** NULL on error. 49 ** 50 ** Side Effects: 51 ** none 52 */ 53 54 /* following delimiters are inherent to the internal algorithms */ 55 # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 56 57 ADDRESS * 58 parseaddr(addr, a, flags, delim, delimptr, e) 59 char *addr; 60 register ADDRESS *a; 61 int flags; 62 int delim; 63 char **delimptr; 64 register ENVELOPE *e; 65 { 66 register char **pvp; 67 auto char *delimptrbuf; 68 bool queueup; 69 char pvpbuf[PSBUFSIZE]; 70 extern bool invalidaddr __P((char *, char *)); 71 extern void allocaddr __P((ADDRESS *, int, char *)); 72 73 /* 74 ** Initialize and prescan address. 75 */ 76 77 e->e_to = addr; 78 if (tTd(20, 1)) 79 printf("\n--parseaddr(%s)\n", addr); 80 81 if (delimptr == NULL) 82 delimptr = &delimptrbuf; 83 84 pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); 85 if (pvp == NULL) 86 { 87 if (tTd(20, 1)) 88 printf("parseaddr-->NULL\n"); 89 return (NULL); 90 } 91 92 if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 93 { 94 if (tTd(20, 1)) 95 printf("parseaddr-->bad address\n"); 96 return NULL; 97 } 98 99 /* 100 ** Save addr if we are going to have to. 101 ** 102 ** We have to do this early because there is a chance that 103 ** the map lookups in the rewriting rules could clobber 104 ** static memory somewhere. 105 */ 106 107 if (bitset(RF_COPYPADDR, flags) && addr != NULL) 108 { 109 char savec = **delimptr; 110 111 if (savec != '\0') 112 **delimptr = '\0'; 113 e->e_to = addr = newstr(addr); 114 if (savec != '\0') 115 **delimptr = savec; 116 } 117 118 /* 119 ** Apply rewriting rules. 120 ** Ruleset 0 does basic parsing. It must resolve. 121 */ 122 123 queueup = FALSE; 124 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 125 queueup = TRUE; 126 if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) 127 queueup = TRUE; 128 129 130 /* 131 ** Build canonical address from pvp. 132 */ 133 134 a = buildaddr(pvp, a, flags, e); 135 136 /* 137 ** Make local copies of the host & user and then 138 ** transport them out. 139 */ 140 141 allocaddr(a, flags, addr); 142 if (bitset(QBADADDR, a->q_flags)) 143 return a; 144 145 /* 146 ** If there was a parsing failure, mark it for queueing. 147 */ 148 149 if (queueup && OpMode != MD_INITALIAS) 150 { 151 char *msg = "Transient parse error -- message queued for future delivery"; 152 153 if (e->e_sendmode == SM_DEFER) 154 msg = "Deferring message until queue run"; 155 if (tTd(20, 1)) 156 printf("parseaddr: queuing message\n"); 157 message(msg); 158 if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 159 e->e_message = newstr(msg); 160 a->q_flags |= QQUEUEUP; 161 a->q_status = "4.4.3"; 162 } 163 164 /* 165 ** Compute return value. 166 */ 167 168 if (tTd(20, 1)) 169 { 170 printf("parseaddr-->"); 171 printaddr(a, FALSE); 172 } 173 174 return (a); 175 } 176 /* 177 ** INVALIDADDR -- check for address containing meta-characters 178 ** 179 ** Parameters: 180 ** addr -- the address to check. 181 ** 182 ** Returns: 183 ** TRUE -- if the address has any "wierd" characters 184 ** FALSE -- otherwise. 185 */ 186 187 bool 188 invalidaddr(addr, delimptr) 189 register char *addr; 190 char *delimptr; 191 { 192 char savedelim = '\0'; 193 194 if (delimptr != NULL) 195 { 196 savedelim = *delimptr; 197 if (savedelim != '\0') 198 *delimptr = '\0'; 199 } 200 if (strlen(addr) > TOBUFSIZE - 2) 201 { 202 usrerr("553 Address too long (%d bytes max)", TOBUFSIZE - 2); 203 goto failure; 204 } 205 for (; *addr != '\0'; addr++) 206 { 207 if ((*addr & 0340) == 0200) 208 break; 209 } 210 if (*addr == '\0') 211 { 212 if (delimptr != NULL && savedelim != '\0') 213 *delimptr = savedelim; 214 return FALSE; 215 } 216 setstat(EX_USAGE); 217 usrerr("553 Address contained invalid control characters"); 218 failure: 219 if (delimptr != NULL && savedelim != '\0') 220 *delimptr = savedelim; 221 return TRUE; 222 } 223 /* 224 ** ALLOCADDR -- do local allocations of address on demand. 225 ** 226 ** Also lowercases the host name if requested. 227 ** 228 ** Parameters: 229 ** a -- the address to reallocate. 230 ** flags -- the copy flag (see RF_ definitions in sendmail.h 231 ** for a description). 232 ** paddr -- the printname of the address. 233 ** 234 ** Returns: 235 ** none. 236 ** 237 ** Side Effects: 238 ** Copies portions of a into local buffers as requested. 239 */ 240 241 void 242 allocaddr(a, flags, paddr) 243 register ADDRESS *a; 244 int flags; 245 char *paddr; 246 { 247 if (tTd(24, 4)) 248 printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 249 250 a->q_paddr = paddr; 251 252 if (a->q_user == NULL) 253 a->q_user = ""; 254 if (a->q_host == NULL) 255 a->q_host = ""; 256 257 if (bitset(RF_COPYPARSE, flags)) 258 { 259 a->q_host = newstr(a->q_host); 260 if (a->q_user != a->q_paddr) 261 a->q_user = newstr(a->q_user); 262 } 263 264 if (a->q_paddr == NULL) 265 a->q_paddr = a->q_user; 266 } 267 /* 268 ** PRESCAN -- Prescan name and make it canonical 269 ** 270 ** Scans a name and turns it into a set of tokens. This process 271 ** deletes blanks and comments (in parentheses). 272 ** 273 ** This routine knows about quoted strings and angle brackets. 274 ** 275 ** There are certain subtleties to this routine. The one that 276 ** comes to mind now is that backslashes on the ends of names 277 ** are silently stripped off; this is intentional. The problem 278 ** is that some versions of sndmsg (like at LBL) set the kill 279 ** character to something other than @ when reading addresses; 280 ** so people type "csvax.eric\@berkeley" -- which screws up the 281 ** berknet mailer. 282 ** 283 ** Parameters: 284 ** addr -- the name to chomp. 285 ** delim -- the delimiter for the address, normally 286 ** '\0' or ','; \0 is accepted in any case. 287 ** If '\t' then we are reading the .cf file. 288 ** pvpbuf -- place to put the saved text -- note that 289 ** the pointers are static. 290 ** pvpbsize -- size of pvpbuf. 291 ** delimptr -- if non-NULL, set to the location of the 292 ** terminating delimiter. 293 ** toktab -- if set, a token table to use for parsing. 294 ** If NULL, use the default table. 295 ** 296 ** Returns: 297 ** A pointer to a vector of tokens. 298 ** NULL on error. 299 */ 300 301 /* states and character types */ 302 # define OPR 0 /* operator */ 303 # define ATM 1 /* atom */ 304 # define QST 2 /* in quoted string */ 305 # define SPC 3 /* chewing up spaces */ 306 # define ONE 4 /* pick up one character */ 307 # define ILL 5 /* illegal character */ 308 309 # define NSTATES 6 /* number of states */ 310 # define TYPE 017 /* mask to select state type */ 311 312 /* meta bits for table */ 313 # define M 020 /* meta character; don't pass through */ 314 # define B 040 /* cause a break */ 315 # define MB M|B /* meta-break */ 316 317 static short StateTab[NSTATES][NSTATES] = 318 { 319 /* oldst chtype> OPR ATM QST SPC ONE ILL */ 320 /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 321 /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 322 /*QST*/ { QST, QST, OPR, QST, QST, QST }, 323 /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 324 /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 325 /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 326 }; 327 328 /* token type table -- it gets modified with $o characters */ 329 static u_char TokTypeTab[256] = 330 { 331 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 332 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 333 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 334 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 335 /* sp ! " # $ % & ' ( ) * + , - . / */ 336 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 337 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 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 [ \ ] ^ _ */ 342 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 343 /* ` a b c d e f g h i j k l m n o */ 344 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 345 /* p q r s t u v w x y z { | } ~ del */ 346 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 347 348 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 349 OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 350 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 351 OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 352 /* sp ! " # $ % & ' ( ) * + , - . / */ 353 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 354 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 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 [ \ ] ^ _ */ 359 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 360 /* ` a b c d e f g h i j k l m n o */ 361 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 362 /* p q r s t u v w x y z { | } ~ del */ 363 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 364 }; 365 366 /* token type table for MIME parsing */ 367 u_char MimeTokenTab[256] = 368 { 369 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 370 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 371 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 372 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 373 /* sp ! " # $ % & ' ( ) * + , - . / */ 374 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 375 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 376 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 377 /* @ A B C D E F G H I J K L M N O */ 378 OPR,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 [ \ ] ^ _ */ 380 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 381 /* ` a b c d e f g h i j k l m n o */ 382 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 383 /* p q r s t u v w x y z { | } ~ del */ 384 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 385 386 /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 387 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 388 /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 389 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 390 /* sp ! " # $ % & ' ( ) * + , - . / */ 391 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 392 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 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 [ \ ] ^ _ */ 397 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 398 /* ` a b c d e f g h i j k l m n o */ 399 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 400 /* p q r s t u v w x y z { | } ~ del */ 401 ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 402 }; 403 404 405 # define NOCHAR -1 /* signal nothing in lookahead token */ 406 407 char ** 408 prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) 409 char *addr; 410 int delim; 411 char pvpbuf[]; 412 int pvpbsize; 413 char **delimptr; 414 u_char *toktab; 415 { 416 register char *p; 417 register char *q; 418 register int c; 419 char **avp; 420 bool bslashmode; 421 bool route_syntax; 422 int cmntcnt; 423 int anglecnt; 424 char *tok; 425 int state; 426 int newstate; 427 char *saveto = CurEnv->e_to; 428 static char *av[MAXATOM+1]; 429 static char firsttime = TRUE; 430 extern int errno; 431 432 if (firsttime) 433 { 434 /* initialize the token type table */ 435 char obuf[50]; 436 437 firsttime = FALSE; 438 if (OperatorChars == NULL) 439 { 440 if (ConfigLevel < 7) 441 OperatorChars = macvalue('o', CurEnv); 442 if (OperatorChars == NULL) 443 OperatorChars = ".:@[]"; 444 } 445 expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv); 446 strcat(obuf, DELIMCHARS); 447 for (p = obuf; *p != '\0'; p++) 448 { 449 if (TokTypeTab[*p & 0xff] == ATM) 450 TokTypeTab[*p & 0xff] = OPR; 451 } 452 } 453 if (toktab == NULL) 454 toktab = TokTypeTab; 455 456 /* make sure error messages don't have garbage on them */ 457 errno = 0; 458 459 q = pvpbuf; 460 bslashmode = FALSE; 461 route_syntax = FALSE; 462 cmntcnt = 0; 463 anglecnt = 0; 464 avp = av; 465 state = ATM; 466 c = NOCHAR; 467 p = addr; 468 CurEnv->e_to = p; 469 if (tTd(22, 11)) 470 { 471 printf("prescan: "); 472 xputs(p); 473 (void) putchar('\n'); 474 } 475 476 do 477 { 478 /* read a token */ 479 tok = q; 480 for (;;) 481 { 482 /* store away any old lookahead character */ 483 if (c != NOCHAR && !bslashmode) 484 { 485 /* see if there is room */ 486 if (q >= &pvpbuf[pvpbsize - 5]) 487 { 488 usrerr("553 Address too long"); 489 if (strlen(addr) > (SIZE_T) MAXNAME) 490 addr[MAXNAME] = '\0'; 491 returnnull: 492 if (delimptr != NULL) 493 *delimptr = p; 494 CurEnv->e_to = saveto; 495 return (NULL); 496 } 497 498 /* squirrel it away */ 499 *q++ = c; 500 } 501 502 /* read a new input character */ 503 c = *p++; 504 if (c == '\0') 505 { 506 /* diagnose and patch up bad syntax */ 507 if (state == QST) 508 { 509 usrerr("653 Unbalanced '\"'"); 510 c = '"'; 511 } 512 else if (cmntcnt > 0) 513 { 514 usrerr("653 Unbalanced '('"); 515 c = ')'; 516 } 517 else if (anglecnt > 0) 518 { 519 c = '>'; 520 usrerr("653 Unbalanced '<'"); 521 } 522 else 523 break; 524 525 p--; 526 } 527 else if (c == delim && cmntcnt <= 0 && state != QST) 528 { 529 if (anglecnt <= 0) 530 break; 531 532 /* special case for better error management */ 533 if (delim == ',' && !route_syntax) 534 { 535 usrerr("653 Unbalanced '<'"); 536 c = '>'; 537 p--; 538 } 539 } 540 541 if (tTd(22, 101)) 542 printf("c=%c, s=%d; ", c, state); 543 544 /* chew up special characters */ 545 *q = '\0'; 546 if (bslashmode) 547 { 548 bslashmode = FALSE; 549 550 /* kludge \! for naive users */ 551 if (cmntcnt > 0) 552 { 553 c = NOCHAR; 554 continue; 555 } 556 else if (c != '!' || state == QST) 557 { 558 *q++ = '\\'; 559 continue; 560 } 561 } 562 563 if (c == '\\') 564 { 565 bslashmode = TRUE; 566 } 567 else if (state == QST) 568 { 569 /* do nothing, just avoid next clauses */ 570 } 571 else if (c == '(') 572 { 573 cmntcnt++; 574 c = NOCHAR; 575 } 576 else if (c == ')') 577 { 578 if (cmntcnt <= 0) 579 { 580 usrerr("653 Unbalanced ')'"); 581 c = NOCHAR; 582 } 583 else 584 cmntcnt--; 585 } 586 else if (cmntcnt > 0) 587 c = NOCHAR; 588 else if (c == '<') 589 { 590 char *q = p; 591 592 anglecnt++; 593 while (isascii(*q) && isspace(*q)) 594 q++; 595 if (*q == '@') 596 route_syntax = TRUE; 597 } 598 else if (c == '>') 599 { 600 if (anglecnt <= 0) 601 { 602 usrerr("653 Unbalanced '>'"); 603 c = NOCHAR; 604 } 605 else 606 anglecnt--; 607 route_syntax = FALSE; 608 } 609 else if (delim == ' ' && isascii(c) && isspace(c)) 610 c = ' '; 611 612 if (c == NOCHAR) 613 continue; 614 615 /* see if this is end of input */ 616 if (c == delim && anglecnt <= 0 && state != QST) 617 break; 618 619 newstate = StateTab[state][toktab[c & 0xff]]; 620 if (tTd(22, 101)) 621 printf("ns=%02o\n", newstate); 622 state = newstate & TYPE; 623 if (state == ILL) 624 { 625 if (isascii(c) && isprint(c)) 626 usrerr("653 Illegal character %c", c); 627 else 628 usrerr("653 Illegal character 0x%02x", c); 629 } 630 if (bitset(M, newstate)) 631 c = NOCHAR; 632 if (bitset(B, newstate)) 633 break; 634 } 635 636 /* new token */ 637 if (tok != q) 638 { 639 *q++ = '\0'; 640 if (tTd(22, 36)) 641 { 642 printf("tok="); 643 xputs(tok); 644 (void) putchar('\n'); 645 } 646 if (avp >= &av[MAXATOM]) 647 { 648 usrerr("553 prescan: too many tokens"); 649 goto returnnull; 650 } 651 if (q - tok > MAXNAME) 652 { 653 usrerr("553 prescan: token too long"); 654 goto returnnull; 655 } 656 *avp++ = tok; 657 } 658 } while (c != '\0' && (c != delim || anglecnt > 0)); 659 *avp = NULL; 660 p--; 661 if (delimptr != NULL) 662 *delimptr = p; 663 if (tTd(22, 12)) 664 { 665 printf("prescan==>"); 666 printav(av); 667 } 668 CurEnv->e_to = saveto; 669 if (av[0] == NULL) 670 { 671 if (tTd(22, 1)) 672 printf("prescan: null leading token\n"); 673 return (NULL); 674 } 675 return (av); 676 } 677 /* 678 ** REWRITE -- apply rewrite rules to token vector. 679 ** 680 ** This routine is an ordered production system. Each rewrite 681 ** rule has a LHS (called the pattern) and a RHS (called the 682 ** rewrite); 'rwr' points the the current rewrite rule. 683 ** 684 ** For each rewrite rule, 'avp' points the address vector we 685 ** are trying to match against, and 'pvp' points to the pattern. 686 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 687 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 688 ** matched is saved away in the match vector (pointed to by 'mvp'). 689 ** 690 ** When a match between avp & pvp does not match, we try to 691 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 692 ** we must also back out the match in mvp. If we reach a 693 ** MATCHANY or MATCHZANY we just extend the match and start 694 ** over again. 695 ** 696 ** When we finally match, we rewrite the address vector 697 ** and try over again. 698 ** 699 ** Parameters: 700 ** pvp -- pointer to token vector. 701 ** ruleset -- the ruleset to use for rewriting. 702 ** reclevel -- recursion level (to catch loops). 703 ** e -- the current envelope. 704 ** 705 ** Returns: 706 ** A status code. If EX_TEMPFAIL, higher level code should 707 ** attempt recovery. 708 ** 709 ** Side Effects: 710 ** pvp is modified. 711 */ 712 713 struct match 714 { 715 char **first; /* first token matched */ 716 char **last; /* last token matched */ 717 char **pattern; /* pointer to pattern */ 718 }; 719 720 # define MAXMATCH 9 /* max params per rewrite */ 721 722 723 int 724 rewrite(pvp, ruleset, reclevel, e) 725 char **pvp; 726 int ruleset; 727 int reclevel; 728 register ENVELOPE *e; 729 { 730 register char *ap; /* address pointer */ 731 register char *rp; /* rewrite pointer */ 732 register char **avp; /* address vector pointer */ 733 register char **rvp; /* rewrite vector pointer */ 734 register struct match *mlp; /* cur ptr into mlist */ 735 register struct rewrite *rwr; /* pointer to current rewrite rule */ 736 int ruleno; /* current rule number */ 737 int rstat = EX_OK; /* return status */ 738 int loopcount; 739 struct match mlist[MAXMATCH]; /* stores match on LHS */ 740 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 741 char buf[MAXLINE]; 742 extern int callsubr __P((char**, int, ENVELOPE *)); 743 extern int sm_strcasecmp __P((char *, char *)); 744 745 if (OpMode == MD_TEST || tTd(21, 1)) 746 { 747 printf("rewrite: ruleset %3d input:", ruleset); 748 printav(pvp); 749 } 750 if (ruleset < 0 || ruleset >= MAXRWSETS) 751 { 752 syserr("554 rewrite: illegal ruleset number %d", ruleset); 753 return EX_CONFIG; 754 } 755 if (reclevel++ > MaxRuleRecursion) 756 { 757 syserr("rewrite: excessive recursion (max %d), ruleset %d", 758 MaxRuleRecursion, ruleset); 759 return EX_CONFIG; 760 } 761 if (pvp == NULL) 762 return EX_USAGE; 763 764 /* 765 ** Run through the list of rewrite rules, applying 766 ** any that match. 767 */ 768 769 ruleno = 1; 770 loopcount = 0; 771 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 772 { 773 int stat; 774 775 /* if already canonical, quit now */ 776 if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 777 break; 778 779 if (tTd(21, 12)) 780 { 781 printf("-----trying rule:"); 782 printav(rwr->r_lhs); 783 } 784 785 /* try to match on this rule */ 786 mlp = mlist; 787 rvp = rwr->r_lhs; 788 avp = pvp; 789 if (++loopcount > 100) 790 { 791 syserr("554 Infinite loop in ruleset %d, rule %d", 792 ruleset, ruleno); 793 if (tTd(21, 1)) 794 { 795 printf("workspace: "); 796 printav(pvp); 797 } 798 break; 799 } 800 801 while ((ap = *avp) != NULL || *rvp != NULL) 802 { 803 rp = *rvp; 804 if (tTd(21, 35)) 805 { 806 printf("ADVANCE rp="); 807 xputs(rp); 808 printf(", ap="); 809 xputs(ap); 810 printf("\n"); 811 } 812 if (rp == NULL) 813 { 814 /* end-of-pattern before end-of-address */ 815 goto backup; 816 } 817 if (ap == NULL && (*rp & 0377) != MATCHZANY && 818 (*rp & 0377) != MATCHZERO) 819 { 820 /* end-of-input with patterns left */ 821 goto backup; 822 } 823 824 switch (*rp & 0377) 825 { 826 case MATCHCLASS: 827 /* match any phrase in a class */ 828 mlp->pattern = rvp; 829 mlp->first = avp; 830 extendclass: 831 ap = *avp; 832 if (ap == NULL) 833 goto backup; 834 mlp->last = avp++; 835 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 836 if (!wordinclass(buf, rp[1])) 837 { 838 if (tTd(21, 36)) 839 { 840 printf("EXTEND rp="); 841 xputs(rp); 842 printf(", ap="); 843 xputs(ap); 844 printf("\n"); 845 } 846 goto extendclass; 847 } 848 if (tTd(21, 36)) 849 printf("CLMATCH\n"); 850 mlp++; 851 break; 852 853 case MATCHNCLASS: 854 /* match any token not in a class */ 855 if (wordinclass(ap, rp[1])) 856 goto backup; 857 858 /* fall through */ 859 860 case MATCHONE: 861 case MATCHANY: 862 /* match exactly one token */ 863 mlp->pattern = rvp; 864 mlp->first = avp; 865 mlp->last = avp++; 866 mlp++; 867 break; 868 869 case MATCHZANY: 870 /* match zero or more tokens */ 871 mlp->pattern = rvp; 872 mlp->first = avp; 873 mlp->last = avp - 1; 874 mlp++; 875 break; 876 877 case MATCHZERO: 878 /* match zero tokens */ 879 break; 880 881 case MACRODEXPAND: 882 /* 883 ** Match against run-time macro. 884 ** This algorithm is broken for the 885 ** general case (no recursive macros, 886 ** improper tokenization) but should 887 ** work for the usual cases. 888 */ 889 890 ap = macvalue(rp[1], e); 891 mlp->first = avp; 892 if (tTd(21, 2)) 893 printf("rewrite: LHS $&%s => \"%s\"\n", 894 macname(rp[1]), 895 ap == NULL ? "(NULL)" : ap); 896 897 if (ap == NULL) 898 break; 899 while (*ap != '\0') 900 { 901 if (*avp == NULL || 902 strncasecmp(ap, *avp, strlen(*avp)) != 0) 903 { 904 /* no match */ 905 avp = mlp->first; 906 goto backup; 907 } 908 ap += strlen(*avp++); 909 } 910 911 /* match */ 912 break; 913 914 default: 915 /* must have exact match */ 916 if (sm_strcasecmp(rp, ap)) 917 goto backup; 918 avp++; 919 break; 920 } 921 922 /* successful match on this token */ 923 rvp++; 924 continue; 925 926 backup: 927 /* match failed -- back up */ 928 while (--mlp >= mlist) 929 { 930 rvp = mlp->pattern; 931 rp = *rvp; 932 avp = mlp->last + 1; 933 ap = *avp; 934 935 if (tTd(21, 36)) 936 { 937 printf("BACKUP rp="); 938 xputs(rp); 939 printf(", ap="); 940 xputs(ap); 941 printf("\n"); 942 } 943 944 if (ap == NULL) 945 { 946 /* run off the end -- back up again */ 947 continue; 948 } 949 if ((*rp & 0377) == MATCHANY || 950 (*rp & 0377) == MATCHZANY) 951 { 952 /* extend binding and continue */ 953 mlp->last = avp++; 954 rvp++; 955 mlp++; 956 break; 957 } 958 if ((*rp & 0377) == MATCHCLASS) 959 { 960 /* extend binding and try again */ 961 mlp->last = avp; 962 goto extendclass; 963 } 964 } 965 966 if (mlp < mlist) 967 { 968 /* total failure to match */ 969 break; 970 } 971 } 972 973 /* 974 ** See if we successfully matched 975 */ 976 977 if (mlp < mlist || *rvp != NULL) 978 { 979 if (tTd(21, 10)) 980 printf("----- rule fails\n"); 981 rwr = rwr->r_next; 982 ruleno++; 983 loopcount = 0; 984 continue; 985 } 986 987 rvp = rwr->r_rhs; 988 if (tTd(21, 12)) 989 { 990 printf("-----rule matches:"); 991 printav(rvp); 992 } 993 994 rp = *rvp; 995 if ((*rp & 0377) == CANONUSER) 996 { 997 rvp++; 998 rwr = rwr->r_next; 999 ruleno++; 1000 loopcount = 0; 1001 } 1002 else if ((*rp & 0377) == CANONHOST) 1003 { 1004 rvp++; 1005 rwr = NULL; 1006 } 1007 1008 /* substitute */ 1009 for (avp = npvp; *rvp != NULL; rvp++) 1010 { 1011 register struct match *m; 1012 register char **pp; 1013 1014 rp = *rvp; 1015 if ((*rp & 0377) == MATCHREPL) 1016 { 1017 /* substitute from LHS */ 1018 m = &mlist[rp[1] - '1']; 1019 if (m < mlist || m >= mlp) 1020 { 1021 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 1022 ruleset, rp[1]); 1023 return EX_CONFIG; 1024 } 1025 if (tTd(21, 15)) 1026 { 1027 printf("$%c:", rp[1]); 1028 pp = m->first; 1029 while (pp <= m->last) 1030 { 1031 printf(" %lx=\"", (u_long) *pp); 1032 (void) fflush(stdout); 1033 printf("%s\"", *pp++); 1034 } 1035 printf("\n"); 1036 } 1037 pp = m->first; 1038 while (pp <= m->last) 1039 { 1040 if (avp >= &npvp[MAXATOM]) 1041 { 1042 syserr("554 rewrite: expansion too long"); 1043 return EX_DATAERR; 1044 } 1045 *avp++ = *pp++; 1046 } 1047 } 1048 else 1049 { 1050 /* some sort of replacement */ 1051 if (avp >= &npvp[MAXATOM]) 1052 { 1053 toolong: 1054 syserr("554 rewrite: expansion too long"); 1055 return EX_DATAERR; 1056 } 1057 if ((*rp & 0377) != MACRODEXPAND) 1058 { 1059 /* vanilla replacement */ 1060 *avp++ = rp; 1061 } 1062 else 1063 { 1064 /* $&x replacement */ 1065 char *mval = macvalue(rp[1], e); 1066 char **xpvp; 1067 int trsize = 0; 1068 static size_t pvpb1_size = 0; 1069 static char **pvpb1 = NULL; 1070 char pvpbuf[PSBUFSIZE]; 1071 1072 if (tTd(21, 2)) 1073 printf("rewrite: RHS $&%s => \"%s\"\n", 1074 macname(rp[1]), 1075 mval == NULL ? "(NULL)" : mval); 1076 if (mval == NULL || *mval == '\0') 1077 continue; 1078 1079 /* save the remainder of the input */ 1080 for (xpvp = pvp; *xpvp != NULL; xpvp++) 1081 trsize += sizeof *xpvp; 1082 if (trsize > pvpb1_size) 1083 { 1084 if (pvpb1 != NULL) 1085 free(pvpb1); 1086 pvpb1 = (char **)xalloc(trsize); 1087 pvpb1_size = trsize; 1088 } 1089 1090 bcopy((char *) pvp, (char *) pvpb1, trsize); 1091 1092 /* scan the new replacement */ 1093 xpvp = prescan(mval, '\0', pvpbuf, 1094 sizeof pvpbuf, NULL, NULL); 1095 if (xpvp == NULL) 1096 { 1097 /* prescan pre-printed error */ 1098 return EX_DATAERR; 1099 } 1100 1101 /* insert it into the output stream */ 1102 while (*xpvp != NULL) 1103 { 1104 if (tTd(21, 19)) 1105 printf(" ... %s\n", *xpvp); 1106 *avp++ = newstr(*xpvp); 1107 if (avp >= &npvp[MAXATOM]) 1108 goto toolong; 1109 xpvp++; 1110 } 1111 if (tTd(21, 19)) 1112 printf(" ... DONE\n"); 1113 1114 /* restore the old trailing input */ 1115 bcopy((char *) pvpb1, (char *) pvp, trsize); 1116 } 1117 } 1118 } 1119 *avp++ = NULL; 1120 1121 /* 1122 ** Check for any hostname/keyword lookups. 1123 */ 1124 1125 for (rvp = npvp; *rvp != NULL; rvp++) 1126 { 1127 char **hbrvp; 1128 char **xpvp; 1129 int trsize; 1130 char *replac; 1131 int endtoken; 1132 STAB *map; 1133 char *mapname; 1134 char **key_rvp; 1135 char **arg_rvp; 1136 char **default_rvp; 1137 char buf[MAXNAME + 1]; 1138 char *pvpb1[MAXATOM + 1]; 1139 char *argvect[10]; 1140 char pvpbuf[PSBUFSIZE]; 1141 char *nullpvp[1]; 1142 extern char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 1143 1144 if ((**rvp & 0377) != HOSTBEGIN && 1145 (**rvp & 0377) != LOOKUPBEGIN) 1146 continue; 1147 1148 /* 1149 ** Got a hostname/keyword lookup. 1150 ** 1151 ** This could be optimized fairly easily. 1152 */ 1153 1154 hbrvp = rvp; 1155 if ((**rvp & 0377) == HOSTBEGIN) 1156 { 1157 endtoken = HOSTEND; 1158 mapname = "host"; 1159 } 1160 else 1161 { 1162 endtoken = LOOKUPEND; 1163 mapname = *++rvp; 1164 } 1165 map = stab(mapname, ST_MAP, ST_FIND); 1166 if (map == NULL) 1167 syserr("554 rewrite: map %s not found", mapname); 1168 1169 /* extract the match part */ 1170 key_rvp = ++rvp; 1171 default_rvp = NULL; 1172 arg_rvp = argvect; 1173 xpvp = NULL; 1174 replac = pvpbuf; 1175 while (*rvp != NULL && (**rvp & 0377) != endtoken) 1176 { 1177 int nodetype = **rvp & 0377; 1178 1179 if (nodetype != CANONHOST && nodetype != CANONUSER) 1180 { 1181 rvp++; 1182 continue; 1183 } 1184 1185 *rvp++ = NULL; 1186 1187 if (xpvp != NULL) 1188 { 1189 cataddr(xpvp, NULL, replac, 1190 &pvpbuf[sizeof pvpbuf] - replac, 1191 '\0'); 1192 *++arg_rvp = replac; 1193 replac += strlen(replac) + 1; 1194 xpvp = NULL; 1195 } 1196 switch (nodetype) 1197 { 1198 case CANONHOST: 1199 xpvp = rvp; 1200 break; 1201 1202 case CANONUSER: 1203 default_rvp = rvp; 1204 break; 1205 } 1206 } 1207 if (*rvp != NULL) 1208 *rvp++ = NULL; 1209 if (xpvp != NULL) 1210 { 1211 cataddr(xpvp, NULL, replac, 1212 &pvpbuf[sizeof pvpbuf] - replac, 1213 '\0'); 1214 *++arg_rvp = replac; 1215 } 1216 *++arg_rvp = NULL; 1217 1218 /* save the remainder of the input string */ 1219 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1220 bcopy((char *) rvp, (char *) pvpb1, trsize); 1221 1222 /* look it up */ 1223 cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 1224 argvect[0] = buf; 1225 replac = map_lookup(map, buf, argvect, &rstat, e); 1226 1227 /* if no replacement, use default */ 1228 if (replac == NULL && default_rvp != NULL) 1229 { 1230 /* create the default */ 1231 cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 1232 replac = buf; 1233 } 1234 1235 if (replac == NULL) 1236 { 1237 xpvp = key_rvp; 1238 } 1239 else if (*replac == '\0') 1240 { 1241 /* null replacement */ 1242 nullpvp[0] = NULL; 1243 xpvp = nullpvp; 1244 } 1245 else 1246 { 1247 /* scan the new replacement */ 1248 xpvp = prescan(replac, '\0', pvpbuf, 1249 sizeof pvpbuf, NULL, NULL); 1250 if (xpvp == NULL) 1251 { 1252 /* prescan already printed error */ 1253 return EX_DATAERR; 1254 } 1255 } 1256 1257 /* append it to the token list */ 1258 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1259 { 1260 *avp++ = newstr(*xpvp); 1261 if (avp >= &npvp[MAXATOM]) 1262 goto toolong; 1263 } 1264 1265 /* restore the old trailing information */ 1266 rvp = avp - 1; 1267 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1268 if (avp >= &npvp[MAXATOM]) 1269 goto toolong; 1270 } 1271 1272 /* 1273 ** Check for subroutine calls. 1274 */ 1275 1276 stat = callsubr(npvp, reclevel, e); 1277 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1278 rstat = stat; 1279 1280 /* copy vector back into original space. */ 1281 for (avp = npvp; *avp++ != NULL;) 1282 continue; 1283 bcopy((char *) npvp, (char *) pvp, 1284 (int) (avp - npvp) * sizeof *avp); 1285 1286 if (tTd(21, 4)) 1287 { 1288 printf("rewritten as:"); 1289 printav(pvp); 1290 } 1291 } 1292 1293 if (OpMode == MD_TEST || tTd(21, 1)) 1294 { 1295 printf("rewrite: ruleset %3d returns:", ruleset); 1296 printav(pvp); 1297 } 1298 1299 return rstat; 1300 } 1301 /* 1302 ** CALLSUBR -- call subroutines in rewrite vector 1303 ** 1304 ** Parameters: 1305 ** pvp -- pointer to token vector. 1306 ** reclevel -- the current recursion level. 1307 ** e -- the current envelope. 1308 ** 1309 ** Returns: 1310 ** The status from the subroutine call. 1311 ** 1312 ** Side Effects: 1313 ** pvp is modified. 1314 */ 1315 1316 int 1317 callsubr(pvp, reclevel, e) 1318 char **pvp; 1319 int reclevel; 1320 ENVELOPE *e; 1321 { 1322 char **avp; 1323 char **rvp; 1324 register int i; 1325 int subr; 1326 int stat; 1327 int rstat = EX_OK; 1328 char *tpvp[MAXATOM + 1]; 1329 1330 for (avp = pvp; *avp != NULL; avp++) 1331 { 1332 if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 1333 { 1334 stripquotes(avp[1]); 1335 subr = strtorwset(avp[1], NULL, ST_FIND); 1336 if (subr < 0) 1337 { 1338 syserr("Unknown ruleset %s", avp[1]); 1339 return EX_CONFIG; 1340 } 1341 1342 if (tTd(21, 3)) 1343 printf("-----callsubr %s (%d)\n", avp[1], subr); 1344 1345 /* 1346 ** Take care of possible inner calls first. 1347 ** use a full size temporary buffer to avoid 1348 ** overflows in rewrite, but strip off the 1349 ** subroutine call. 1350 */ 1351 1352 for (i = 2; avp[i] != NULL; i++) 1353 tpvp[i - 2] = avp[i]; 1354 tpvp[i - 2] = NULL; 1355 1356 stat = callsubr(tpvp, reclevel, e); 1357 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1358 rstat = stat; 1359 1360 /* 1361 ** Now we need to call the ruleset specified for 1362 ** the subroutine. we can do this with the 1363 ** temporary buffer that we set up earlier, 1364 ** since it has all the data we want to rewrite. 1365 */ 1366 1367 stat = rewrite(tpvp, subr, reclevel, e); 1368 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1369 rstat = stat; 1370 1371 /* 1372 ** Find length of tpvp and current offset into 1373 ** pvp, if the total is greater than MAXATOM, 1374 ** then it would overflow the buffer if we copied 1375 ** it back in to pvp, in which case we throw a 1376 ** fit. 1377 */ 1378 1379 for (rvp = tpvp; *rvp != NULL; rvp++) 1380 continue; 1381 if (((rvp - tpvp) + (avp - pvp)) > MAXATOM) 1382 { 1383 syserr("554 callsubr: expansion too long"); 1384 return EX_DATAERR; 1385 } 1386 1387 /* 1388 ** Now we can copy the rewritten code over 1389 ** the initial subroutine call in the buffer. 1390 */ 1391 1392 for (i = 0; tpvp[i] != NULL; i++) 1393 avp[i] = tpvp[i]; 1394 avp[i] = NULL; 1395 1396 /* 1397 ** If we got this far, we've processed the left 1398 ** most subroutine, and recursively called ourselves 1399 ** to handle any other subroutines. We're done. 1400 */ 1401 1402 break; 1403 } 1404 } 1405 return rstat; 1406 } 1407 /* 1408 ** MAP_LOOKUP -- do lookup in map 1409 ** 1410 ** Parameters: 1411 ** map -- the map to use for the lookup. 1412 ** key -- the key to look up. 1413 ** argvect -- arguments to pass to the map lookup. 1414 ** pstat -- a pointer to an integer in which to store the 1415 ** status from the lookup. 1416 ** e -- the current envelope. 1417 ** 1418 ** Returns: 1419 ** The result of the lookup. 1420 ** NULL -- if there was no data for the given key. 1421 */ 1422 1423 char * 1424 map_lookup(map, key, argvect, pstat, e) 1425 STAB *map; 1426 char key[]; 1427 char **argvect; 1428 int *pstat; 1429 ENVELOPE *e; 1430 { 1431 auto int stat = EX_OK; 1432 char *replac; 1433 1434 if (e->e_sendmode == SM_DEFER) 1435 { 1436 /* don't do any map lookups */ 1437 if (tTd(60, 1)) 1438 printf("map_lookup(%s, %s) => DEFERRED\n", 1439 map->s_name, key); 1440 *pstat = EX_TEMPFAIL; 1441 return NULL; 1442 } 1443 if (map == NULL || !bitset(MF_OPEN, map->s_map.map_mflags)) 1444 return NULL; 1445 1446 if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags)) 1447 stripquotes(key); 1448 1449 /* XXX should try to auto-open the map here */ 1450 1451 if (tTd(60, 1)) 1452 { 1453 printf("map_lookup(%s, %s", map->s_name, key); 1454 if (tTd(60, 5)) 1455 { 1456 int i; 1457 1458 for (i = 0; argvect[i] != NULL; i++) 1459 printf(", %%%d=%s", i, argvect[i]); 1460 } 1461 printf(") => "); 1462 } 1463 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 1464 key, argvect, &stat); 1465 if (tTd(60, 1)) 1466 printf("%s (%d)\n", 1467 replac != NULL ? replac : "NOT FOUND", 1468 stat); 1469 1470 /* should recover if stat == EX_TEMPFAIL */ 1471 if (stat == EX_TEMPFAIL && !bitset(MF_NODEFER, map->s_map.map_mflags)) 1472 { 1473 *pstat = EX_TEMPFAIL; 1474 if (tTd(60, 1)) 1475 printf("map_lookup(%s, %s) tempfail: errno=%d\n", 1476 map->s_name, key, errno); 1477 if (e->e_message == NULL) 1478 { 1479 char mbuf[320]; 1480 1481 snprintf(mbuf, sizeof mbuf, 1482 "%.80s map: lookup (%s): deferred", 1483 map->s_name, 1484 shortenstring(key, MAXSHORTSTR)); 1485 e->e_message = newstr(mbuf); 1486 } 1487 } 1488 if (stat == EX_TEMPFAIL && map->s_map.map_tapp != NULL) 1489 { 1490 size_t i = strlen(key) + strlen(map->s_map.map_tapp) + 1; 1491 static char *rwbuf = NULL; 1492 static size_t rwbuflen = 0; 1493 1494 if (i > rwbuflen) 1495 { 1496 if (rwbuf != NULL) 1497 free(rwbuf); 1498 rwbuflen = i; 1499 rwbuf = (char *) xalloc(rwbuflen); 1500 } 1501 snprintf(rwbuf, rwbuflen, "%s%s", key, map->s_map.map_tapp); 1502 if (tTd(60, 4)) 1503 printf("map_lookup tempfail: returning \"%s\"\n", 1504 rwbuf); 1505 return rwbuf; 1506 } 1507 return replac; 1508 } 1509 /* 1510 ** BUILDADDR -- build address from token vector. 1511 ** 1512 ** Parameters: 1513 ** tv -- token vector. 1514 ** a -- pointer to address descriptor to fill. 1515 ** If NULL, one will be allocated. 1516 ** flags -- info regarding whether this is a sender or 1517 ** a recipient. 1518 ** e -- the current envelope. 1519 ** 1520 ** Returns: 1521 ** NULL if there was an error. 1522 ** 'a' otherwise. 1523 ** 1524 ** Side Effects: 1525 ** fills in 'a' 1526 */ 1527 1528 struct errcodes 1529 { 1530 char *ec_name; /* name of error code */ 1531 int ec_code; /* numeric code */ 1532 } ErrorCodes[] = 1533 { 1534 { "usage", EX_USAGE }, 1535 { "nouser", EX_NOUSER }, 1536 { "nohost", EX_NOHOST }, 1537 { "unavailable", EX_UNAVAILABLE }, 1538 { "software", EX_SOFTWARE }, 1539 { "tempfail", EX_TEMPFAIL }, 1540 { "protocol", EX_PROTOCOL }, 1541 #ifdef EX_CONFIG 1542 { "config", EX_CONFIG }, 1543 #endif 1544 { NULL, EX_UNAVAILABLE } 1545 }; 1546 1547 ADDRESS * 1548 buildaddr(tv, a, flags, e) 1549 register char **tv; 1550 register ADDRESS *a; 1551 int flags; 1552 register ENVELOPE *e; 1553 { 1554 struct mailer **mp; 1555 register struct mailer *m; 1556 register char *p; 1557 char *mname; 1558 char **hostp; 1559 char hbuf[MAXNAME + 1]; 1560 static MAILER discardmailer; 1561 static MAILER errormailer; 1562 static char *discardargv[] = { "DISCARD", NULL }; 1563 static char *errorargv[] = { "ERROR", NULL }; 1564 static char ubuf[MAXNAME + 2]; 1565 1566 if (tTd(24, 5)) 1567 { 1568 printf("buildaddr, flags=%x, tv=", flags); 1569 printav(tv); 1570 } 1571 1572 if (a == NULL) 1573 a = (ADDRESS *) xalloc(sizeof *a); 1574 bzero((char *) a, sizeof *a); 1575 1576 /* set up default error return flags */ 1577 a->q_flags |= DefaultNotify; 1578 1579 if (discardmailer.m_name == NULL) 1580 { 1581 /* initialize the discard mailer */ 1582 discardmailer.m_name = "*discard*"; 1583 discardmailer.m_mailer = "DISCARD"; 1584 discardmailer.m_argv = discardargv; 1585 } 1586 1587 /* figure out what net/mailer to use */ 1588 if (*tv == NULL || (**tv & 0377) != CANONNET) 1589 { 1590 syserr("554 buildaddr: no mailer in parsed address"); 1591 badaddr: 1592 a->q_flags |= QBADADDR; 1593 a->q_mailer = &errormailer; 1594 if (errormailer.m_name == NULL) 1595 { 1596 /* initialize the bogus mailer */ 1597 errormailer.m_name = "*error*"; 1598 errormailer.m_mailer = "ERROR"; 1599 errormailer.m_argv = errorargv; 1600 } 1601 return a; 1602 } 1603 mname = *++tv; 1604 1605 /* extract host and user portions */ 1606 if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1607 hostp = ++tv; 1608 else 1609 hostp = NULL; 1610 while (*tv != NULL && (**tv & 0377) != CANONUSER) 1611 tv++; 1612 if (*tv == NULL) 1613 { 1614 syserr("554 buildaddr: no user"); 1615 goto badaddr; 1616 } 1617 if (tv == hostp) 1618 hostp = NULL; 1619 else if (hostp != NULL) 1620 cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1621 cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1622 1623 /* save away the host name */ 1624 if (strcasecmp(mname, "error") == 0) 1625 { 1626 if (hostp != NULL) 1627 { 1628 register struct errcodes *ep; 1629 1630 if (strchr(hbuf, '.') != NULL) 1631 { 1632 extern int dsntoexitstat __P((char *)); 1633 1634 a->q_status = newstr(hbuf); 1635 setstat(dsntoexitstat(hbuf)); 1636 } 1637 else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 1638 { 1639 setstat(atoi(hbuf)); 1640 } 1641 else 1642 { 1643 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1644 if (strcasecmp(ep->ec_name, hbuf) == 0) 1645 break; 1646 setstat(ep->ec_code); 1647 } 1648 } 1649 else 1650 setstat(EX_UNAVAILABLE); 1651 stripquotes(ubuf); 1652 if (isascii(ubuf[0]) && isdigit(ubuf[0]) && 1653 isascii(ubuf[1]) && isdigit(ubuf[1]) && 1654 isascii(ubuf[2]) && isdigit(ubuf[2]) && 1655 ubuf[3] == ' ') 1656 { 1657 char fmt[10]; 1658 1659 strncpy(fmt, ubuf, 3); 1660 strcpy(&fmt[3], " %s"); 1661 usrerr(fmt, ubuf + 4); 1662 1663 /* 1664 ** If this is a 4xx code and we aren't running 1665 ** SMTP on our input, bounce this message; 1666 ** otherwise it disappears without a trace. 1667 */ 1668 1669 if (fmt[0] == '4' && OpMode != MD_SMTP && 1670 OpMode != MD_DAEMON) 1671 { 1672 e->e_flags |= EF_FATALERRS; 1673 } 1674 } 1675 else 1676 { 1677 usrerr("553 %s", ubuf); 1678 } 1679 goto badaddr; 1680 } 1681 1682 for (mp = Mailer; (m = *mp++) != NULL; ) 1683 { 1684 if (strcasecmp(m->m_name, mname) == 0) 1685 break; 1686 } 1687 if (m == NULL) 1688 { 1689 syserr("554 buildaddr: unknown mailer %s", mname); 1690 goto badaddr; 1691 } 1692 a->q_mailer = m; 1693 1694 /* figure out what host (if any) */ 1695 if (hostp == NULL) 1696 { 1697 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1698 { 1699 syserr("554 buildaddr: no host"); 1700 goto badaddr; 1701 } 1702 a->q_host = NULL; 1703 } 1704 else 1705 a->q_host = newstr(hbuf); 1706 1707 /* figure out the user */ 1708 p = ubuf; 1709 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 1710 { 1711 p++; 1712 tv++; 1713 a->q_flags |= QNOTREMOTE; 1714 } 1715 1716 /* do special mapping for local mailer */ 1717 if (*p == '"') 1718 p++; 1719 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 1720 a->q_mailer = m = ProgMailer; 1721 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 1722 a->q_mailer = m = FileMailer; 1723 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 1724 { 1725 /* may be :include: */ 1726 stripquotes(ubuf); 1727 if (strncasecmp(ubuf, ":include:", 9) == 0) 1728 { 1729 /* if :include:, don't need further rewriting */ 1730 a->q_mailer = m = InclMailer; 1731 a->q_user = newstr(&ubuf[9]); 1732 return a; 1733 } 1734 } 1735 1736 /* rewrite according recipient mailer rewriting rules */ 1737 define('h', a->q_host, e); 1738 if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1739 { 1740 /* sender addresses done later */ 1741 (void) rewrite(tv, 2, 0, e); 1742 if (m->m_re_rwset > 0) 1743 (void) rewrite(tv, m->m_re_rwset, 0, e); 1744 } 1745 (void) rewrite(tv, 4, 0, e); 1746 1747 /* save the result for the command line/RCPT argument */ 1748 cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 1749 a->q_user = ubuf; 1750 1751 /* 1752 ** Do mapping to lower case as requested by mailer 1753 */ 1754 1755 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1756 makelower(a->q_host); 1757 if (!bitnset(M_USR_UPPER, m->m_flags)) 1758 makelower(a->q_user); 1759 1760 if (tTd(24, 6)) 1761 { 1762 printf("buildaddr => "); 1763 printaddr(a, FALSE); 1764 } 1765 return a; 1766 } 1767 /* 1768 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1769 ** 1770 ** Parameters: 1771 ** pvp -- parameter vector to rebuild. 1772 ** evp -- last parameter to include. Can be NULL to 1773 ** use entire pvp. 1774 ** buf -- buffer to build the string into. 1775 ** sz -- size of buf. 1776 ** spacesub -- the space separator character; if null, 1777 ** use SpaceSub. 1778 ** 1779 ** Returns: 1780 ** none. 1781 ** 1782 ** Side Effects: 1783 ** Destroys buf. 1784 */ 1785 1786 void 1787 cataddr(pvp, evp, buf, sz, spacesub) 1788 char **pvp; 1789 char **evp; 1790 char *buf; 1791 register int sz; 1792 int spacesub; 1793 { 1794 bool oatomtok = FALSE; 1795 bool natomtok = FALSE; 1796 register int i; 1797 register char *p; 1798 1799 if (spacesub == '\0') 1800 spacesub = SpaceSub; 1801 1802 if (pvp == NULL) 1803 { 1804 (void) strcpy(buf, ""); 1805 return; 1806 } 1807 p = buf; 1808 sz -= 2; 1809 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1810 { 1811 natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 1812 if (oatomtok && natomtok) 1813 *p++ = spacesub; 1814 (void) strcpy(p, *pvp); 1815 oatomtok = natomtok; 1816 p += i; 1817 sz -= i + 1; 1818 if (pvp++ == evp) 1819 break; 1820 } 1821 *p = '\0'; 1822 } 1823 /* 1824 ** SAMEADDR -- Determine if two addresses are the same 1825 ** 1826 ** This is not just a straight comparison -- if the mailer doesn't 1827 ** care about the host we just ignore it, etc. 1828 ** 1829 ** Parameters: 1830 ** a, b -- pointers to the internal forms to compare. 1831 ** 1832 ** Returns: 1833 ** TRUE -- they represent the same mailbox. 1834 ** FALSE -- they don't. 1835 ** 1836 ** Side Effects: 1837 ** none. 1838 */ 1839 1840 bool 1841 sameaddr(a, b) 1842 register ADDRESS *a; 1843 register ADDRESS *b; 1844 { 1845 register ADDRESS *ca, *cb; 1846 1847 /* if they don't have the same mailer, forget it */ 1848 if (a->q_mailer != b->q_mailer) 1849 return (FALSE); 1850 1851 /* if the user isn't the same, we can drop out */ 1852 if (strcmp(a->q_user, b->q_user) != 0) 1853 return (FALSE); 1854 1855 /* if we have good uids for both but they differ, these are different */ 1856 if (a->q_mailer == ProgMailer) 1857 { 1858 ca = getctladdr(a); 1859 cb = getctladdr(b); 1860 if (ca != NULL && cb != NULL && 1861 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1862 ca->q_uid != cb->q_uid) 1863 return (FALSE); 1864 } 1865 1866 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1867 if (a->q_host == b->q_host) 1868 { 1869 /* probably both null pointers */ 1870 return (TRUE); 1871 } 1872 if (a->q_host == NULL || b->q_host == NULL) 1873 { 1874 /* only one is a null pointer */ 1875 return (FALSE); 1876 } 1877 if (strcmp(a->q_host, b->q_host) != 0) 1878 return (FALSE); 1879 1880 return (TRUE); 1881 } 1882 /* 1883 ** PRINTADDR -- print address (for debugging) 1884 ** 1885 ** Parameters: 1886 ** a -- the address to print 1887 ** follow -- follow the q_next chain. 1888 ** 1889 ** Returns: 1890 ** none. 1891 ** 1892 ** Side Effects: 1893 ** none. 1894 */ 1895 1896 struct qflags 1897 { 1898 char *qf_name; 1899 u_long qf_bit; 1900 }; 1901 1902 struct qflags AddressFlags[] = 1903 { 1904 { "QDONTSEND", QDONTSEND }, 1905 { "QBADADDR", QBADADDR }, 1906 { "QGOODUID", QGOODUID }, 1907 { "QPRIMARY", QPRIMARY }, 1908 { "QQUEUEUP", QQUEUEUP }, 1909 { "QSENT", QSENT }, 1910 { "QNOTREMOTE", QNOTREMOTE }, 1911 { "QSELFREF", QSELFREF }, 1912 { "QVERIFIED", QVERIFIED }, 1913 { "QBOGUSSHELL", QBOGUSSHELL }, 1914 { "QUNSAFEADDR", QUNSAFEADDR }, 1915 { "QPINGONSUCCESS", QPINGONSUCCESS }, 1916 { "QPINGONFAILURE", QPINGONFAILURE }, 1917 { "QPINGONDELAY", QPINGONDELAY }, 1918 { "QHASNOTIFY", QHASNOTIFY }, 1919 { "QRELAYED", QRELAYED }, 1920 { "QEXPANDED", QEXPANDED }, 1921 { "QDELIVERED", QDELIVERED }, 1922 { "QDELAYED", QDELAYED }, 1923 { "QTHISPASS", QTHISPASS }, 1924 { "QRCPTOK", QRCPTOK }, 1925 { NULL } 1926 }; 1927 1928 void 1929 printaddr(a, follow) 1930 register ADDRESS *a; 1931 bool follow; 1932 { 1933 register MAILER *m; 1934 MAILER pseudomailer; 1935 register struct qflags *qfp; 1936 bool firstone; 1937 1938 if (a == NULL) 1939 { 1940 printf("[NULL]\n"); 1941 return; 1942 } 1943 1944 while (a != NULL) 1945 { 1946 printf("%lx=", (u_long) a); 1947 (void) fflush(stdout); 1948 1949 /* find the mailer -- carefully */ 1950 m = a->q_mailer; 1951 if (m == NULL) 1952 { 1953 m = &pseudomailer; 1954 m->m_mno = -1; 1955 m->m_name = "NULL"; 1956 } 1957 1958 printf("%s:\n\tmailer %d (%s), host `%s'\n", 1959 a->q_paddr == NULL ? "<null>" : a->q_paddr, 1960 m->m_mno, m->m_name, 1961 a->q_host == NULL ? "<null>" : a->q_host); 1962 printf("\tuser `%s', ruser `%s'\n", 1963 a->q_user, 1964 a->q_ruser == NULL ? "<null>" : a->q_ruser); 1965 printf("\tnext=%lx, alias %lx, uid %d, gid %d\n", 1966 (u_long) a->q_next, (u_long) a->q_alias, 1967 (int) a->q_uid, (int) a->q_gid); 1968 printf("\tflags=%lx<", a->q_flags); 1969 firstone = TRUE; 1970 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 1971 { 1972 if (!bitset(qfp->qf_bit, a->q_flags)) 1973 continue; 1974 if (!firstone) 1975 printf(","); 1976 firstone = FALSE; 1977 printf("%s", qfp->qf_name); 1978 } 1979 printf(">\n"); 1980 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1981 a->q_owner == NULL ? "(none)" : a->q_owner, 1982 a->q_home == NULL ? "(none)" : a->q_home, 1983 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1984 printf("\torcpt=\"%s\", statmta=%s, status=%s\n", 1985 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 1986 a->q_statmta == NULL ? "(none)" : a->q_statmta, 1987 a->q_status == NULL ? "(none)" : a->q_status); 1988 printf("\trstatus=\"%s\"\n", 1989 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 1990 printf("\tspecificity=%d, statdate=%s\n", 1991 a->q_specificity, ctime(&a->q_statdate)); 1992 1993 if (!follow) 1994 return; 1995 a = a->q_next; 1996 } 1997 } 1998 /* 1999 ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 2000 ** 2001 ** Parameters: 2002 ** a -- pointer to the address 2003 ** 2004 ** Returns: 2005 ** TRUE -- if this address is "empty" (i.e., no one should 2006 ** ever generate replies to it. 2007 ** FALSE -- if it is a "regular" (read: replyable) address. 2008 */ 2009 2010 bool 2011 emptyaddr(a) 2012 register ADDRESS *a; 2013 { 2014 return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2015 a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2016 } 2017 /* 2018 ** REMOTENAME -- return the name relative to the current mailer 2019 ** 2020 ** Parameters: 2021 ** name -- the name to translate. 2022 ** m -- the mailer that we want to do rewriting relative 2023 ** to. 2024 ** flags -- fine tune operations. 2025 ** pstat -- pointer to status word. 2026 ** e -- the current envelope. 2027 ** 2028 ** Returns: 2029 ** the text string representing this address relative to 2030 ** the receiving mailer. 2031 ** 2032 ** Side Effects: 2033 ** none. 2034 ** 2035 ** Warnings: 2036 ** The text string returned is tucked away locally; 2037 ** copy it if you intend to save it. 2038 */ 2039 2040 char * 2041 remotename(name, m, flags, pstat, e) 2042 char *name; 2043 struct mailer *m; 2044 int flags; 2045 int *pstat; 2046 register ENVELOPE *e; 2047 { 2048 register char **pvp; 2049 char *fancy; 2050 char *oldg = macvalue('g', e); 2051 int rwset; 2052 static char buf[MAXNAME + 1]; 2053 char lbuf[MAXNAME + 1]; 2054 char pvpbuf[PSBUFSIZE]; 2055 extern char *crackaddr __P((char *)); 2056 2057 if (tTd(12, 1)) 2058 printf("remotename(%s)\n", name); 2059 2060 /* don't do anything if we are tagging it as special */ 2061 if (bitset(RF_SENDERADDR, flags)) 2062 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2063 : m->m_se_rwset; 2064 else 2065 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2066 : m->m_re_rwset; 2067 if (rwset < 0) 2068 return (name); 2069 2070 /* 2071 ** Do a heuristic crack of this name to extract any comment info. 2072 ** This will leave the name as a comment and a $g macro. 2073 */ 2074 2075 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2076 fancy = "\201g"; 2077 else 2078 fancy = crackaddr(name); 2079 2080 /* 2081 ** Turn the name into canonical form. 2082 ** Normally this will be RFC 822 style, i.e., "user@domain". 2083 ** If this only resolves to "user", and the "C" flag is 2084 ** specified in the sending mailer, then the sender's 2085 ** domain will be appended. 2086 */ 2087 2088 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 2089 if (pvp == NULL) 2090 return (name); 2091 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2092 *pstat = EX_TEMPFAIL; 2093 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2094 { 2095 /* append from domain to this address */ 2096 register char **pxp = pvp; 2097 2098 /* see if there is an "@domain" in the current name */ 2099 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 2100 pxp++; 2101 if (*pxp == NULL) 2102 { 2103 /* no.... append the "@domain" from the sender */ 2104 register char **qxq = e->e_fromdomain; 2105 2106 while ((*pxp++ = *qxq++) != NULL) 2107 continue; 2108 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2109 *pstat = EX_TEMPFAIL; 2110 } 2111 } 2112 2113 /* 2114 ** Do more specific rewriting. 2115 ** Rewrite using ruleset 1 or 2 depending on whether this is 2116 ** a sender address or not. 2117 ** Then run it through any receiving-mailer-specific rulesets. 2118 */ 2119 2120 if (bitset(RF_SENDERADDR, flags)) 2121 { 2122 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 2123 *pstat = EX_TEMPFAIL; 2124 } 2125 else 2126 { 2127 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 2128 *pstat = EX_TEMPFAIL; 2129 } 2130 if (rwset > 0) 2131 { 2132 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 2133 *pstat = EX_TEMPFAIL; 2134 } 2135 2136 /* 2137 ** Do any final sanitation the address may require. 2138 ** This will normally be used to turn internal forms 2139 ** (e.g., user@host.LOCAL) into external form. This 2140 ** may be used as a default to the above rules. 2141 */ 2142 2143 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 2144 *pstat = EX_TEMPFAIL; 2145 2146 /* 2147 ** Now restore the comment information we had at the beginning. 2148 */ 2149 2150 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 2151 define('g', lbuf, e); 2152 2153 /* need to make sure route-addrs have <angle brackets> */ 2154 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2155 expand("<\201g>", buf, sizeof buf, e); 2156 else 2157 expand(fancy, buf, sizeof buf, e); 2158 2159 define('g', oldg, e); 2160 2161 if (tTd(12, 1)) 2162 printf("remotename => `%s'\n", buf); 2163 return (buf); 2164 } 2165 /* 2166 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2167 ** 2168 ** Parameters: 2169 ** a -- the address to map (but just the user name part). 2170 ** sendq -- the sendq in which to install any replacement 2171 ** addresses. 2172 ** aliaslevel -- the alias nesting depth. 2173 ** e -- the envelope. 2174 ** 2175 ** Returns: 2176 ** none. 2177 */ 2178 2179 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2180 Q_PINGFLAGS|QHASNOTIFY|\ 2181 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED) 2182 2183 void 2184 maplocaluser(a, sendq, aliaslevel, e) 2185 register ADDRESS *a; 2186 ADDRESS **sendq; 2187 int aliaslevel; 2188 ENVELOPE *e; 2189 { 2190 register char **pvp; 2191 register ADDRESS *a1 = NULL; 2192 auto char *delimptr; 2193 char pvpbuf[PSBUFSIZE]; 2194 2195 if (tTd(29, 1)) 2196 { 2197 printf("maplocaluser: "); 2198 printaddr(a, FALSE); 2199 } 2200 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 2201 if (pvp == NULL) 2202 { 2203 if (tTd(29, 9)) 2204 printf("maplocaluser: cannot prescan %s\n", a->q_user); 2205 return; 2206 } 2207 2208 define('h', a->q_host, e); 2209 define('u', a->q_user, e); 2210 define('z', a->q_home, e); 2211 2212 if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL) 2213 { 2214 if (tTd(29, 9)) 2215 printf("maplocaluser: rewrite tempfail\n"); 2216 a->q_flags |= QQUEUEUP; 2217 a->q_status = "4.4.3"; 2218 return; 2219 } 2220 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2221 { 2222 if (tTd(29, 9)) 2223 printf("maplocaluser: doesn't resolve\n"); 2224 return; 2225 } 2226 2227 /* if non-null, mailer destination specified -- has it changed? */ 2228 a1 = buildaddr(pvp, NULL, 0, e); 2229 if (a1 == NULL || sameaddr(a, a1)) 2230 { 2231 if (tTd(29, 9)) 2232 printf("maplocaluser: address unchanged\n"); 2233 if (a1 != NULL) 2234 free(a1); 2235 return; 2236 } 2237 2238 /* make new address take on flags and print attributes of old */ 2239 a1->q_flags &= ~Q_COPYFLAGS; 2240 a1->q_flags |= a->q_flags & Q_COPYFLAGS; 2241 a1->q_paddr = a->q_paddr; 2242 2243 /* mark old address as dead; insert new address */ 2244 a->q_flags |= QDONTSEND; 2245 if (tTd(29, 5)) 2246 { 2247 printf("maplocaluser: QDONTSEND "); 2248 printaddr(a, FALSE); 2249 } 2250 a1->q_alias = a; 2251 allocaddr(a1, RF_COPYALL, a->q_paddr); 2252 (void) recipient(a1, sendq, aliaslevel, e); 2253 } 2254 /* 2255 ** DEQUOTE_INIT -- initialize dequote map 2256 ** 2257 ** This is a no-op. 2258 ** 2259 ** Parameters: 2260 ** map -- the internal map structure. 2261 ** args -- arguments. 2262 ** 2263 ** Returns: 2264 ** TRUE. 2265 */ 2266 2267 bool 2268 dequote_init(map, args) 2269 MAP *map; 2270 char *args; 2271 { 2272 register char *p = args; 2273 2274 map->map_mflags |= MF_KEEPQUOTES; 2275 for (;;) 2276 { 2277 while (isascii(*p) && isspace(*p)) 2278 p++; 2279 if (*p != '-') 2280 break; 2281 switch (*++p) 2282 { 2283 case 'a': 2284 map->map_app = ++p; 2285 break; 2286 2287 case 's': 2288 map->map_coldelim = *++p; 2289 break; 2290 } 2291 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2292 p++; 2293 if (*p != '\0') 2294 *p = '\0'; 2295 } 2296 if (map->map_app != NULL) 2297 map->map_app = newstr(map->map_app); 2298 2299 return TRUE; 2300 } 2301 /* 2302 ** DEQUOTE_MAP -- unquote an address 2303 ** 2304 ** Parameters: 2305 ** map -- the internal map structure (ignored). 2306 ** name -- the name to dequote. 2307 ** av -- arguments (ignored). 2308 ** statp -- pointer to status out-parameter. 2309 ** 2310 ** Returns: 2311 ** NULL -- if there were no quotes, or if the resulting 2312 ** unquoted buffer would not be acceptable to prescan. 2313 ** else -- The dequoted buffer. 2314 */ 2315 2316 /* ARGSUSED2 */ 2317 char * 2318 dequote_map(map, name, av, statp) 2319 MAP *map; 2320 char *name; 2321 char **av; 2322 int *statp; 2323 { 2324 register char *p; 2325 register char *q; 2326 register char c; 2327 int anglecnt = 0; 2328 int cmntcnt = 0; 2329 int quotecnt = 0; 2330 int spacecnt = 0; 2331 bool quotemode = FALSE; 2332 bool bslashmode = FALSE; 2333 char spacesub = map->map_coldelim; 2334 2335 for (p = q = name; (c = *p++) != '\0'; ) 2336 { 2337 if (bslashmode) 2338 { 2339 bslashmode = FALSE; 2340 *q++ = c; 2341 continue; 2342 } 2343 2344 if (c == ' ' && spacesub != '\0') 2345 c = spacesub; 2346 2347 switch (c) 2348 { 2349 case '\\': 2350 bslashmode = TRUE; 2351 break; 2352 2353 case '(': 2354 cmntcnt++; 2355 break; 2356 2357 case ')': 2358 if (cmntcnt-- <= 0) 2359 return NULL; 2360 break; 2361 2362 case ' ': 2363 spacecnt++; 2364 break; 2365 } 2366 2367 if (cmntcnt > 0) 2368 { 2369 *q++ = c; 2370 continue; 2371 } 2372 2373 switch (c) 2374 { 2375 case '"': 2376 quotemode = !quotemode; 2377 quotecnt++; 2378 continue; 2379 2380 case '<': 2381 anglecnt++; 2382 break; 2383 2384 case '>': 2385 if (anglecnt-- <= 0) 2386 return NULL; 2387 break; 2388 } 2389 *q++ = c; 2390 } 2391 2392 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2393 quotemode || quotecnt <= 0 || spacecnt != 0) 2394 return NULL; 2395 *q++ = '\0'; 2396 return map_rewrite(map, name, strlen(name), NULL); 2397 } 2398 /* 2399 ** RSCHECK -- check string(s) for validity using rewriting sets 2400 ** 2401 ** Parameters: 2402 ** rwset -- the rewriting set to use. 2403 ** p1 -- the first string to check. 2404 ** p2 -- the second string to check -- may be null. 2405 ** e -- the current envelope. 2406 ** 2407 ** Returns: 2408 ** EX_OK -- if the rwset doesn't resolve to $#error 2409 ** else -- the failure status (message printed) 2410 */ 2411 2412 int 2413 rscheck(rwset, p1, p2, e) 2414 char *rwset; 2415 char *p1; 2416 char *p2; 2417 ENVELOPE *e; 2418 { 2419 char *buf; 2420 int bufsize; 2421 int saveexitstat; 2422 int rstat = EX_OK; 2423 char **pvp; 2424 int rsno; 2425 bool discard = FALSE; 2426 auto ADDRESS a1; 2427 bool saveQuickAbort = QuickAbort; 2428 bool saveSuprErrs = SuprErrs; 2429 char buf0[MAXLINE]; 2430 char pvpbuf[PSBUFSIZE]; 2431 extern char MsgBuf[]; 2432 2433 if (tTd(48, 2)) 2434 printf("rscheck(%s, %s, %s)\n", rwset, p1, 2435 p2 == NULL ? "(NULL)" : p2); 2436 2437 rsno = strtorwset(rwset, NULL, ST_FIND); 2438 if (rsno < 0) 2439 return EX_OK; 2440 2441 if (p2 != NULL) 2442 { 2443 bufsize = strlen(p1) + strlen(p2) + 2; 2444 if (bufsize > sizeof buf0) 2445 buf = xalloc(bufsize); 2446 else 2447 { 2448 buf = buf0; 2449 bufsize = sizeof buf0; 2450 } 2451 (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2452 } 2453 else 2454 { 2455 bufsize = strlen(p1) + 1; 2456 if (bufsize > sizeof buf0) 2457 buf = xalloc(bufsize); 2458 else 2459 { 2460 buf = buf0; 2461 bufsize = sizeof buf0; 2462 } 2463 (void) snprintf(buf, bufsize, "%s", p1); 2464 } 2465 SuprErrs = TRUE; 2466 QuickAbort = FALSE; 2467 pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 2468 SuprErrs = saveSuprErrs; 2469 if (pvp == NULL) 2470 { 2471 if (tTd(48, 2)) 2472 printf("rscheck: cannot prescan input\n"); 2473 /* 2474 syserr("rscheck: cannot prescan input: \"%s\"", 2475 shortenstring(buf, MAXSHORTSTR)); 2476 rstat = EX_DATAERR; 2477 */ 2478 goto finis; 2479 } 2480 (void) rewrite(pvp, rsno, 0, e); 2481 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 2482 pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 2483 strcmp(pvp[1], "discard") != 0)) 2484 { 2485 goto finis; 2486 } 2487 2488 if (strcmp(pvp[1], "discard") == 0) 2489 { 2490 if (tTd(48, 2)) 2491 printf("rscheck: discard mailer selected\n"); 2492 e->e_flags |= EF_DISCARD; 2493 discard = TRUE; 2494 } 2495 else 2496 { 2497 int savelogusrerrs = LogUsrErrs; 2498 static bool logged = FALSE; 2499 2500 /* got an error -- process it */ 2501 saveexitstat = ExitStat; 2502 LogUsrErrs = FALSE; 2503 (void) buildaddr(pvp, &a1, 0, e); 2504 LogUsrErrs = savelogusrerrs; 2505 rstat = ExitStat; 2506 ExitStat = saveexitstat; 2507 if (!logged) 2508 { 2509 markstats(e, &a1, TRUE); 2510 logged = TRUE; 2511 } 2512 } 2513 2514 if (LogLevel >= 4) 2515 { 2516 char *relay; 2517 char *p; 2518 char lbuf[MAXLINE]; 2519 2520 p = lbuf; 2521 if (p2 != NULL) 2522 { 2523 snprintf(p, SPACELEFT(lbuf, p), 2524 ", arg2=%s", 2525 p2); 2526 p += strlen(p); 2527 } 2528 if ((relay = macvalue('_', e)) != NULL) 2529 { 2530 snprintf(p, SPACELEFT(lbuf, p), 2531 ", relay=%s", relay); 2532 p += strlen(p); 2533 } 2534 *p = '\0'; 2535 if (discard) 2536 sm_syslog(LOG_NOTICE, e->e_id, 2537 "ruleset=%s, arg1=%s%s, discard", 2538 rwset, p1, lbuf); 2539 else 2540 sm_syslog(LOG_NOTICE, e->e_id, 2541 "ruleset=%s, arg1=%s%s, reject=%s", 2542 rwset, p1, lbuf, MsgBuf); 2543 } 2544 2545 finis: 2546 /* clean up */ 2547 QuickAbort = saveQuickAbort; 2548 setstat(rstat); 2549 if (buf != buf0) 2550 free(buf); 2551 2552 if (rstat != EX_OK && QuickAbort) 2553 longjmp(TopFrame, 2); 2554 return rstat; 2555 } 2556