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