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