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