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.384 2006/04/18 01:28:47 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 { 1448 syserr("554 5.3.0 rewrite: missing mapname"); 1449 /* NOTREACHED */ 1450 SM_ASSERT(0); 1451 } 1452 } 1453 map = stab(mapname, ST_MAP, ST_FIND); 1454 if (map == NULL) 1455 syserr("554 5.3.0 rewrite: map %s not found", 1456 mapname); 1457 1458 /* extract the match part */ 1459 key_rvp = ++rvp; 1460 if (key_rvp == NULL) 1461 { 1462 syserr("554 5.3.0 rewrite: missing key for map %s", 1463 mapname); 1464 /* NOTREACHED */ 1465 SM_ASSERT(0); 1466 } 1467 default_rvp = NULL; 1468 arg_rvp = argvect; 1469 xpvp = NULL; 1470 replac = pvpbuf; 1471 while (*rvp != NULL && (**rvp & 0377) != endtoken) 1472 { 1473 int nodetype = **rvp & 0377; 1474 1475 if (nodetype != CANONHOST && 1476 nodetype != CANONUSER) 1477 { 1478 rvp++; 1479 continue; 1480 } 1481 1482 *rvp++ = NULL; 1483 1484 if (xpvp != NULL) 1485 { 1486 cataddr(xpvp, NULL, replac, 1487 &pvpbuf[sizeof pvpbuf] - replac, 1488 '\0'); 1489 if (arg_rvp < 1490 &argvect[MAX_MAP_ARGS - 1]) 1491 *++arg_rvp = replac; 1492 replac += strlen(replac) + 1; 1493 xpvp = NULL; 1494 } 1495 switch (nodetype) 1496 { 1497 case CANONHOST: 1498 xpvp = rvp; 1499 break; 1500 1501 case CANONUSER: 1502 default_rvp = rvp; 1503 break; 1504 } 1505 } 1506 if (*rvp != NULL) 1507 *rvp++ = NULL; 1508 if (xpvp != NULL) 1509 { 1510 cataddr(xpvp, NULL, replac, 1511 &pvpbuf[sizeof pvpbuf] - replac, 1512 '\0'); 1513 if (arg_rvp < &argvect[MAX_MAP_ARGS - 1]) 1514 *++arg_rvp = replac; 1515 } 1516 if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1]) 1517 argvect[MAX_MAP_ARGS - 1] = NULL; 1518 else 1519 *++arg_rvp = NULL; 1520 1521 /* save the remainder of the input string */ 1522 trsize = (avp - rvp + 1) * sizeof *rvp; 1523 memmove((char *) pvpb1, (char *) rvp, trsize); 1524 1525 /* look it up */ 1526 cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 1527 map == NULL ? '\0' : map->s_map.map_spacesub); 1528 argvect[0] = cbuf; 1529 replac = map_lookup(map, cbuf, argvect, &rstat, e); 1530 1531 /* if no replacement, use default */ 1532 if (replac == NULL && default_rvp != NULL) 1533 { 1534 /* create the default */ 1535 cataddr(default_rvp, NULL, cbuf, sizeof cbuf, 1536 '\0'); 1537 replac = cbuf; 1538 } 1539 1540 if (replac == NULL) 1541 { 1542 xpvp = key_rvp; 1543 } 1544 else if (*replac == '\0') 1545 { 1546 /* null replacement */ 1547 nullpvp[0] = NULL; 1548 xpvp = nullpvp; 1549 } 1550 else 1551 { 1552 /* scan the new replacement */ 1553 xpvp = prescan(replac, '\0', pvpbuf, 1554 sizeof pvpbuf, NULL, NULL, false); 1555 if (xpvp == NULL) 1556 { 1557 /* prescan already printed error */ 1558 return EX_DATAERR; 1559 } 1560 } 1561 1562 /* append it to the token list */ 1563 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1564 { 1565 *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 1566 if (avp >= &npvp[maxatom]) 1567 goto toolong; 1568 } 1569 1570 /* restore the old trailing information */ 1571 rvp = avp - 1; 1572 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1573 if (avp >= &npvp[maxatom]) 1574 goto toolong; 1575 } 1576 1577 /* 1578 ** Check for subroutine calls. 1579 */ 1580 1581 status = callsubr(npvp, reclevel, e); 1582 if (rstat == EX_OK || status == EX_TEMPFAIL) 1583 rstat = status; 1584 1585 /* copy vector back into original space. */ 1586 for (avp = npvp; *avp++ != NULL;) 1587 continue; 1588 memmove((char *) pvp, (char *) npvp, 1589 (int) (avp - npvp) * sizeof *avp); 1590 1591 if (tTd(21, 4)) 1592 { 1593 sm_dprintf("rewritten as:"); 1594 printav(sm_debug_file(), pvp); 1595 } 1596 } 1597 1598 if (OpMode == MD_TEST) 1599 { 1600 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1601 "%s%-16.16s returns:", prefix, rulename); 1602 printav(smioout, pvp); 1603 } 1604 else if (tTd(21, 1)) 1605 { 1606 sm_dprintf("%s%-16.16s returns:", prefix, rulename); 1607 printav(sm_debug_file(), pvp); 1608 } 1609 return rstat; 1610 } 1611 /* 1612 ** CALLSUBR -- call subroutines in rewrite vector 1613 ** 1614 ** Parameters: 1615 ** pvp -- pointer to token vector. 1616 ** reclevel -- the current recursion level. 1617 ** e -- the current envelope. 1618 ** 1619 ** Returns: 1620 ** The status from the subroutine call. 1621 ** 1622 ** Side Effects: 1623 ** pvp is modified. 1624 */ 1625 1626 static int 1627 callsubr(pvp, reclevel, e) 1628 char **pvp; 1629 int reclevel; 1630 ENVELOPE *e; 1631 { 1632 char **avp; 1633 register int i; 1634 int subr, j; 1635 int nsubr; 1636 int status; 1637 int rstat = EX_OK; 1638 #define MAX_SUBR 16 1639 int subrnumber[MAX_SUBR]; 1640 int subrindex[MAX_SUBR]; 1641 1642 nsubr = 0; 1643 1644 /* 1645 ** Look for subroutine calls in pvp, collect them into subr*[] 1646 ** We will perform the calls in the next loop, because we will 1647 ** call the "last" subroutine first to avoid recursive calls 1648 ** and too much copying. 1649 */ 1650 1651 for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 1652 { 1653 if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 1654 { 1655 stripquotes(avp[1]); 1656 subr = strtorwset(avp[1], NULL, ST_FIND); 1657 if (subr < 0) 1658 { 1659 syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 1660 return EX_CONFIG; 1661 } 1662 1663 /* 1664 ** XXX instead of doing this we could optimize 1665 ** the rules after reading them: just remove 1666 ** calls to empty rulesets 1667 */ 1668 1669 /* subroutine is an empty ruleset? don't call it */ 1670 if (RewriteRules[subr] == NULL) 1671 { 1672 if (tTd(21, 3)) 1673 sm_dprintf("-----skip subr %s (%d)\n", 1674 avp[1], subr); 1675 for (i = 2; avp[i] != NULL; i++) 1676 avp[i - 2] = avp[i]; 1677 avp[i - 2] = NULL; 1678 continue; 1679 } 1680 if (++nsubr >= MAX_SUBR) 1681 { 1682 syserr("554 5.3.0 Too many subroutine calls (%d max)", 1683 MAX_SUBR); 1684 return EX_CONFIG; 1685 } 1686 subrnumber[nsubr] = subr; 1687 subrindex[nsubr] = j; 1688 } 1689 } 1690 1691 /* 1692 ** Perform the actual subroutines calls, "last" one first, i.e., 1693 ** go from the right to the left through all calls, 1694 ** do the rewriting in place. 1695 */ 1696 1697 for (; nsubr > 0; nsubr--) 1698 { 1699 subr = subrnumber[nsubr]; 1700 avp = pvp + subrindex[nsubr]; 1701 1702 /* remove the subroutine call and name */ 1703 for (i = 2; avp[i] != NULL; i++) 1704 avp[i - 2] = avp[i]; 1705 avp[i - 2] = NULL; 1706 1707 /* 1708 ** Now we need to call the ruleset specified for 1709 ** the subroutine. We can do this in place since 1710 ** we call the "last" subroutine first. 1711 */ 1712 1713 status = rewrite(avp, subr, reclevel, e, 1714 MAXATOM - subrindex[nsubr]); 1715 if (status != EX_OK && status != EX_TEMPFAIL) 1716 return status; 1717 if (rstat == EX_OK || status == EX_TEMPFAIL) 1718 rstat = status; 1719 } 1720 return rstat; 1721 } 1722 /* 1723 ** MAP_LOOKUP -- do lookup in map 1724 ** 1725 ** Parameters: 1726 ** smap -- the map to use for the lookup. 1727 ** key -- the key to look up. 1728 ** argvect -- arguments to pass to the map lookup. 1729 ** pstat -- a pointer to an integer in which to store the 1730 ** status from the lookup. 1731 ** e -- the current envelope. 1732 ** 1733 ** Returns: 1734 ** The result of the lookup. 1735 ** NULL -- if there was no data for the given key. 1736 */ 1737 1738 static char * 1739 map_lookup(smap, key, argvect, pstat, e) 1740 STAB *smap; 1741 char key[]; 1742 char **argvect; 1743 int *pstat; 1744 ENVELOPE *e; 1745 { 1746 auto int status = EX_OK; 1747 MAP *map; 1748 char *replac; 1749 1750 if (smap == NULL) 1751 return NULL; 1752 1753 map = &smap->s_map; 1754 DYNOPENMAP(map); 1755 1756 if (e->e_sendmode == SM_DEFER && 1757 bitset(MF_DEFER, map->map_mflags)) 1758 { 1759 /* don't do any map lookups */ 1760 if (tTd(60, 1)) 1761 sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 1762 smap->s_name, key); 1763 *pstat = EX_TEMPFAIL; 1764 return NULL; 1765 } 1766 1767 if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1768 stripquotes(key); 1769 1770 if (tTd(60, 1)) 1771 { 1772 sm_dprintf("map_lookup(%s, %s", smap->s_name, key); 1773 if (tTd(60, 5)) 1774 { 1775 int i; 1776 1777 for (i = 0; argvect[i] != NULL; i++) 1778 sm_dprintf(", %%%d=%s", i, argvect[i]); 1779 } 1780 sm_dprintf(") => "); 1781 } 1782 replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1783 if (tTd(60, 1)) 1784 sm_dprintf("%s (%d)\n", 1785 replac != NULL ? replac : "NOT FOUND", 1786 status); 1787 1788 /* should recover if status == EX_TEMPFAIL */ 1789 if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1790 { 1791 *pstat = EX_TEMPFAIL; 1792 if (tTd(60, 1)) 1793 sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 1794 smap->s_name, key, errno); 1795 if (e->e_message == NULL) 1796 { 1797 char mbuf[320]; 1798 1799 (void) sm_snprintf(mbuf, sizeof mbuf, 1800 "%.80s map: lookup (%s): deferred", 1801 smap->s_name, 1802 shortenstring(key, MAXSHORTSTR)); 1803 e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 1804 } 1805 } 1806 if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1807 { 1808 size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1809 static char *rwbuf = NULL; 1810 static size_t rwbuflen = 0; 1811 1812 if (i > rwbuflen) 1813 { 1814 if (rwbuf != NULL) 1815 sm_free(rwbuf); 1816 rwbuflen = i; 1817 rwbuf = (char *) sm_pmalloc_x(rwbuflen); 1818 } 1819 (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 1820 if (tTd(60, 4)) 1821 sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 1822 rwbuf); 1823 return rwbuf; 1824 } 1825 return replac; 1826 } 1827 /* 1828 ** INITERRMAILERS -- initialize error and discard mailers 1829 ** 1830 ** Parameters: 1831 ** none. 1832 ** 1833 ** Returns: 1834 ** none. 1835 ** 1836 ** Side Effects: 1837 ** initializes error and discard mailers. 1838 */ 1839 1840 static MAILER discardmailer; 1841 static MAILER errormailer; 1842 static char *discardargv[] = { "DISCARD", NULL }; 1843 static char *errorargv[] = { "ERROR", NULL }; 1844 1845 void 1846 initerrmailers() 1847 { 1848 if (discardmailer.m_name == NULL) 1849 { 1850 /* initialize the discard mailer */ 1851 discardmailer.m_name = "*discard*"; 1852 discardmailer.m_mailer = "DISCARD"; 1853 discardmailer.m_argv = discardargv; 1854 } 1855 if (errormailer.m_name == NULL) 1856 { 1857 /* initialize the bogus mailer */ 1858 errormailer.m_name = "*error*"; 1859 errormailer.m_mailer = "ERROR"; 1860 errormailer.m_argv = errorargv; 1861 } 1862 } 1863 /* 1864 ** BUILDADDR -- build address from token vector. 1865 ** 1866 ** Parameters: 1867 ** tv -- token vector. 1868 ** a -- pointer to address descriptor to fill. 1869 ** If NULL, one will be allocated. 1870 ** flags -- info regarding whether this is a sender or 1871 ** a recipient. 1872 ** e -- the current envelope. 1873 ** 1874 ** Returns: 1875 ** NULL if there was an error. 1876 ** 'a' otherwise. 1877 ** 1878 ** Side Effects: 1879 ** fills in 'a' 1880 */ 1881 1882 static struct errcodes 1883 { 1884 char *ec_name; /* name of error code */ 1885 int ec_code; /* numeric code */ 1886 } ErrorCodes[] = 1887 { 1888 { "usage", EX_USAGE }, 1889 { "nouser", EX_NOUSER }, 1890 { "nohost", EX_NOHOST }, 1891 { "unavailable", EX_UNAVAILABLE }, 1892 { "software", EX_SOFTWARE }, 1893 { "tempfail", EX_TEMPFAIL }, 1894 { "protocol", EX_PROTOCOL }, 1895 { "config", EX_CONFIG }, 1896 { NULL, EX_UNAVAILABLE } 1897 }; 1898 1899 static ADDRESS * 1900 buildaddr(tv, a, flags, e) 1901 register char **tv; 1902 register ADDRESS *a; 1903 int flags; 1904 register ENVELOPE *e; 1905 { 1906 bool tempfail = false; 1907 int maxatom; 1908 struct mailer **mp; 1909 register struct mailer *m; 1910 register char *p; 1911 char *mname; 1912 char **hostp; 1913 char hbuf[MAXNAME + 1]; 1914 static char ubuf[MAXNAME + 2]; 1915 1916 if (tTd(24, 5)) 1917 { 1918 sm_dprintf("buildaddr, flags=%x, tv=", flags); 1919 printav(sm_debug_file(), tv); 1920 } 1921 1922 maxatom = MAXATOM; 1923 if (a == NULL) 1924 a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a); 1925 memset((char *) a, '\0', sizeof *a); 1926 hbuf[0] = '\0'; 1927 1928 /* set up default error return flags */ 1929 a->q_flags |= DefaultNotify; 1930 1931 /* figure out what net/mailer to use */ 1932 if (*tv == NULL || (**tv & 0377) != CANONNET) 1933 { 1934 syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 1935 badaddr: 1936 /* 1937 ** ExitStat may have been set by an earlier map open 1938 ** failure (to a permanent error (EX_OSERR) in syserr()) 1939 ** so we also need to check if this particular $#error 1940 ** return wanted a 4XX failure. 1941 ** 1942 ** XXX the real fix is probably to set ExitStat correctly, 1943 ** i.e., to EX_TEMPFAIL if the map open is just a temporary 1944 ** error. 1945 */ 1946 1947 if (ExitStat == EX_TEMPFAIL || tempfail) 1948 a->q_state = QS_QUEUEUP; 1949 else 1950 { 1951 a->q_state = QS_BADADDR; 1952 a->q_mailer = &errormailer; 1953 } 1954 return a; 1955 } 1956 mname = *++tv; 1957 --maxatom; 1958 1959 /* extract host and user portions */ 1960 if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1961 { 1962 hostp = ++tv; 1963 --maxatom; 1964 } 1965 else 1966 hostp = NULL; 1967 --maxatom; 1968 while (*tv != NULL && (**tv & 0377) != CANONUSER) 1969 { 1970 tv++; 1971 --maxatom; 1972 } 1973 if (*tv == NULL) 1974 { 1975 syserr("554 5.3.5 buildaddr: no user"); 1976 goto badaddr; 1977 } 1978 if (tv == hostp) 1979 hostp = NULL; 1980 else if (hostp != NULL) 1981 cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1982 cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1983 --maxatom; 1984 1985 /* save away the host name */ 1986 if (sm_strcasecmp(mname, "error") == 0) 1987 { 1988 /* Set up triplet for use by -bv */ 1989 a->q_mailer = &errormailer; 1990 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 1991 /* XXX wrong place? */ 1992 1993 if (hostp != NULL) 1994 { 1995 register struct errcodes *ep; 1996 1997 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 1998 if (strchr(hbuf, '.') != NULL) 1999 { 2000 a->q_status = sm_rpool_strdup_x(e->e_rpool, 2001 hbuf); 2002 setstat(dsntoexitstat(hbuf)); 2003 } 2004 else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 2005 { 2006 setstat(atoi(hbuf)); 2007 } 2008 else 2009 { 2010 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 2011 if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 2012 break; 2013 setstat(ep->ec_code); 2014 } 2015 } 2016 else 2017 { 2018 a->q_host = NULL; 2019 setstat(EX_UNAVAILABLE); 2020 } 2021 stripquotes(ubuf); 2022 if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 2023 { 2024 char fmt[16]; 2025 int off; 2026 2027 if ((off = isenhsc(ubuf + 4, ' ')) > 0) 2028 { 2029 ubuf[off + 4] = '\0'; 2030 off += 5; 2031 } 2032 else 2033 { 2034 off = 4; 2035 ubuf[3] = '\0'; 2036 } 2037 (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s"); 2038 if (off > 4) 2039 usrerr(fmt, ubuf + off); 2040 else if (isenhsc(hbuf, '\0') > 0) 2041 usrerrenh(hbuf, fmt, ubuf + off); 2042 else 2043 usrerr(fmt, ubuf + off); 2044 /* XXX ubuf[off - 1] = ' '; */ 2045 if (ubuf[0] == '4') 2046 tempfail = true; 2047 } 2048 else 2049 { 2050 usrerr("553 5.3.0 %s", ubuf); 2051 } 2052 goto badaddr; 2053 } 2054 2055 for (mp = Mailer; (m = *mp++) != NULL; ) 2056 { 2057 if (sm_strcasecmp(m->m_name, mname) == 0) 2058 break; 2059 } 2060 if (m == NULL) 2061 { 2062 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 2063 goto badaddr; 2064 } 2065 a->q_mailer = m; 2066 2067 /* figure out what host (if any) */ 2068 if (hostp == NULL) 2069 { 2070 if (!bitnset(M_LOCALMAILER, m->m_flags)) 2071 { 2072 syserr("554 5.3.5 buildaddr: no host"); 2073 goto badaddr; 2074 } 2075 a->q_host = NULL; 2076 } 2077 else 2078 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 2079 2080 /* figure out the user */ 2081 p = ubuf; 2082 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 2083 { 2084 p++; 2085 tv++; 2086 --maxatom; 2087 a->q_flags |= QNOTREMOTE; 2088 } 2089 2090 /* do special mapping for local mailer */ 2091 if (*p == '"') 2092 p++; 2093 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 2094 a->q_mailer = m = ProgMailer; 2095 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 2096 a->q_mailer = m = FileMailer; 2097 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 2098 { 2099 /* may be :include: */ 2100 stripquotes(ubuf); 2101 if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 2102 { 2103 /* if :include:, don't need further rewriting */ 2104 a->q_mailer = m = InclMailer; 2105 a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 2106 return a; 2107 } 2108 } 2109 2110 /* rewrite according recipient mailer rewriting rules */ 2111 macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 2112 2113 if (ConfigLevel >= 10 || 2114 !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 2115 { 2116 /* sender addresses done later */ 2117 (void) rewrite(tv, 2, 0, e, maxatom); 2118 if (m->m_re_rwset > 0) 2119 (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom); 2120 } 2121 (void) rewrite(tv, 4, 0, e, maxatom); 2122 2123 /* save the result for the command line/RCPT argument */ 2124 cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 2125 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 2126 2127 /* 2128 ** Do mapping to lower case as requested by mailer 2129 */ 2130 2131 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 2132 makelower(a->q_host); 2133 if (!bitnset(M_USR_UPPER, m->m_flags)) 2134 makelower(a->q_user); 2135 2136 if (tTd(24, 6)) 2137 { 2138 sm_dprintf("buildaddr => "); 2139 printaddr(sm_debug_file(), a, false); 2140 } 2141 return a; 2142 } 2143 2144 /* 2145 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 2146 ** 2147 ** Parameters: 2148 ** pvp -- parameter vector to rebuild. 2149 ** evp -- last parameter to include. Can be NULL to 2150 ** use entire pvp. 2151 ** buf -- buffer to build the string into. 2152 ** sz -- size of buf. 2153 ** spacesub -- the space separator character; if '\0', 2154 ** use SpaceSub. 2155 ** 2156 ** Returns: 2157 ** none. 2158 ** 2159 ** Side Effects: 2160 ** Destroys buf. 2161 */ 2162 2163 void 2164 cataddr(pvp, evp, buf, sz, spacesub) 2165 char **pvp; 2166 char **evp; 2167 char *buf; 2168 register int sz; 2169 int spacesub; 2170 { 2171 bool oatomtok = false; 2172 bool natomtok = false; 2173 register int i; 2174 register char *p; 2175 2176 if (sz <= 0) 2177 return; 2178 2179 if (spacesub == '\0') 2180 spacesub = SpaceSub; 2181 2182 if (pvp == NULL) 2183 { 2184 *buf = '\0'; 2185 return; 2186 } 2187 p = buf; 2188 sz -= 2; 2189 while (*pvp != NULL && sz > 0) 2190 { 2191 natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 2192 if (oatomtok && natomtok) 2193 { 2194 *p++ = spacesub; 2195 if (--sz <= 0) 2196 break; 2197 } 2198 i = sm_strlcpy(p, *pvp, sz); 2199 sz -= i; 2200 if (sz <= 0) 2201 break; 2202 oatomtok = natomtok; 2203 p += i; 2204 if (pvp++ == evp) 2205 break; 2206 } 2207 2208 #if 0 2209 /* 2210 ** Silently truncate long strings: even though this doesn't 2211 ** seem like a good idea it is necessary because header checks 2212 ** send the whole header value to rscheck() and hence rewrite(). 2213 ** The latter however sometimes uses a "short" buffer (e.g., 2214 ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this 2215 ** error function. One possible fix to the problem is to pass 2216 ** flags to rscheck() and rewrite() to distinguish the various 2217 ** calls and only trigger the error if necessary. For now just 2218 ** undo the change from 8.13.0. 2219 */ 2220 2221 if (sz <= 0) 2222 usrerr("cataddr: string too long"); 2223 #endif 2224 *p = '\0'; 2225 } 2226 /* 2227 ** SAMEADDR -- Determine if two addresses are the same 2228 ** 2229 ** This is not just a straight comparison -- if the mailer doesn't 2230 ** care about the host we just ignore it, etc. 2231 ** 2232 ** Parameters: 2233 ** a, b -- pointers to the internal forms to compare. 2234 ** 2235 ** Returns: 2236 ** true -- they represent the same mailbox. 2237 ** false -- they don't. 2238 ** 2239 ** Side Effects: 2240 ** none. 2241 */ 2242 2243 bool 2244 sameaddr(a, b) 2245 register ADDRESS *a; 2246 register ADDRESS *b; 2247 { 2248 register ADDRESS *ca, *cb; 2249 2250 /* if they don't have the same mailer, forget it */ 2251 if (a->q_mailer != b->q_mailer) 2252 return false; 2253 2254 /* if the user isn't the same, we can drop out */ 2255 if (strcmp(a->q_user, b->q_user) != 0) 2256 return false; 2257 2258 /* if we have good uids for both but they differ, these are different */ 2259 if (a->q_mailer == ProgMailer) 2260 { 2261 ca = getctladdr(a); 2262 cb = getctladdr(b); 2263 if (ca != NULL && cb != NULL && 2264 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 2265 ca->q_uid != cb->q_uid) 2266 return false; 2267 } 2268 2269 /* otherwise compare hosts (but be careful for NULL ptrs) */ 2270 if (a->q_host == b->q_host) 2271 { 2272 /* probably both null pointers */ 2273 return true; 2274 } 2275 if (a->q_host == NULL || b->q_host == NULL) 2276 { 2277 /* only one is a null pointer */ 2278 return false; 2279 } 2280 if (strcmp(a->q_host, b->q_host) != 0) 2281 return false; 2282 2283 return true; 2284 } 2285 /* 2286 ** PRINTADDR -- print address (for debugging) 2287 ** 2288 ** Parameters: 2289 ** a -- the address to print 2290 ** follow -- follow the q_next chain. 2291 ** 2292 ** Returns: 2293 ** none. 2294 ** 2295 ** Side Effects: 2296 ** none. 2297 */ 2298 2299 struct qflags 2300 { 2301 char *qf_name; 2302 unsigned long qf_bit; 2303 }; 2304 2305 static struct qflags AddressFlags[] = 2306 { 2307 { "QGOODUID", QGOODUID }, 2308 { "QPRIMARY", QPRIMARY }, 2309 { "QNOTREMOTE", QNOTREMOTE }, 2310 { "QSELFREF", QSELFREF }, 2311 { "QBOGUSSHELL", QBOGUSSHELL }, 2312 { "QUNSAFEADDR", QUNSAFEADDR }, 2313 { "QPINGONSUCCESS", QPINGONSUCCESS }, 2314 { "QPINGONFAILURE", QPINGONFAILURE }, 2315 { "QPINGONDELAY", QPINGONDELAY }, 2316 { "QHASNOTIFY", QHASNOTIFY }, 2317 { "QRELAYED", QRELAYED }, 2318 { "QEXPANDED", QEXPANDED }, 2319 { "QDELIVERED", QDELIVERED }, 2320 { "QDELAYED", QDELAYED }, 2321 { "QTHISPASS", QTHISPASS }, 2322 { "QRCPTOK", QRCPTOK }, 2323 { NULL, 0 } 2324 }; 2325 2326 void 2327 printaddr(fp, a, follow) 2328 SM_FILE_T *fp; 2329 register ADDRESS *a; 2330 bool follow; 2331 { 2332 register MAILER *m; 2333 MAILER pseudomailer; 2334 register struct qflags *qfp; 2335 bool firstone; 2336 2337 if (a == NULL) 2338 { 2339 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 2340 return; 2341 } 2342 2343 while (a != NULL) 2344 { 2345 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); 2346 (void) sm_io_flush(fp, SM_TIME_DEFAULT); 2347 2348 /* find the mailer -- carefully */ 2349 m = a->q_mailer; 2350 if (m == NULL) 2351 { 2352 m = &pseudomailer; 2353 m->m_mno = -1; 2354 m->m_name = "NULL"; 2355 } 2356 2357 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2358 "%s:\n\tmailer %d (%s), host `%s'\n", 2359 a->q_paddr == NULL ? "<null>" : a->q_paddr, 2360 m->m_mno, m->m_name, 2361 a->q_host == NULL ? "<null>" : a->q_host); 2362 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2363 "\tuser `%s', ruser `%s'\n", 2364 a->q_user, 2365 a->q_ruser == NULL ? "<null>" : a->q_ruser); 2366 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 2367 switch (a->q_state) 2368 { 2369 case QS_OK: 2370 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 2371 break; 2372 2373 case QS_DONTSEND: 2374 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2375 "DONTSEND"); 2376 break; 2377 2378 case QS_BADADDR: 2379 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2380 "BADADDR"); 2381 break; 2382 2383 case QS_QUEUEUP: 2384 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2385 "QUEUEUP"); 2386 break; 2387 2388 case QS_RETRY: 2389 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 2390 break; 2391 2392 case QS_SENT: 2393 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 2394 break; 2395 2396 case QS_VERIFIED: 2397 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2398 "VERIFIED"); 2399 break; 2400 2401 case QS_EXPANDED: 2402 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2403 "EXPANDED"); 2404 break; 2405 2406 case QS_SENDER: 2407 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2408 "SENDER"); 2409 break; 2410 2411 case QS_CLONED: 2412 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2413 "CLONED"); 2414 break; 2415 2416 case QS_DISCARDED: 2417 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2418 "DISCARDED"); 2419 break; 2420 2421 case QS_REPLACED: 2422 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2423 "REPLACED"); 2424 break; 2425 2426 case QS_REMOVED: 2427 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2428 "REMOVED"); 2429 break; 2430 2431 case QS_DUPLICATE: 2432 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2433 "DUPLICATE"); 2434 break; 2435 2436 case QS_INCLUDED: 2437 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2438 "INCLUDED"); 2439 break; 2440 2441 default: 2442 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2443 "%d", a->q_state); 2444 break; 2445 } 2446 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2447 ", next=%p, alias %p, uid %d, gid %d\n", 2448 a->q_next, a->q_alias, 2449 (int) a->q_uid, (int) a->q_gid); 2450 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 2451 a->q_flags); 2452 firstone = true; 2453 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2454 { 2455 if (!bitset(qfp->qf_bit, a->q_flags)) 2456 continue; 2457 if (!firstone) 2458 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2459 ","); 2460 firstone = false; 2461 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 2462 qfp->qf_name); 2463 } 2464 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2465 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2466 "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2467 a->q_owner == NULL ? "(none)" : a->q_owner, 2468 a->q_home == NULL ? "(none)" : a->q_home, 2469 a->q_fullname == NULL ? "(none)" : a->q_fullname); 2470 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2471 "\torcpt=\"%s\", statmta=%s, status=%s\n", 2472 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2473 a->q_statmta == NULL ? "(none)" : a->q_statmta, 2474 a->q_status == NULL ? "(none)" : a->q_status); 2475 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2476 "\tfinalrcpt=\"%s\"\n", 2477 a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2478 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2479 "\trstatus=\"%s\"\n", 2480 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2481 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2482 "\tstatdate=%s\n", 2483 a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2484 2485 if (!follow) 2486 return; 2487 a = a->q_next; 2488 } 2489 } 2490 /* 2491 ** EMPTYADDR -- return true if this address is empty (``<>'') 2492 ** 2493 ** Parameters: 2494 ** a -- pointer to the address 2495 ** 2496 ** Returns: 2497 ** true -- if this address is "empty" (i.e., no one should 2498 ** ever generate replies to it. 2499 ** false -- if it is a "regular" (read: replyable) address. 2500 */ 2501 2502 bool 2503 emptyaddr(a) 2504 register ADDRESS *a; 2505 { 2506 return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2507 a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2508 } 2509 /* 2510 ** REMOTENAME -- return the name relative to the current mailer 2511 ** 2512 ** Parameters: 2513 ** name -- the name to translate. 2514 ** m -- the mailer that we want to do rewriting relative to. 2515 ** flags -- fine tune operations. 2516 ** pstat -- pointer to status word. 2517 ** e -- the current envelope. 2518 ** 2519 ** Returns: 2520 ** the text string representing this address relative to 2521 ** the receiving mailer. 2522 ** 2523 ** Side Effects: 2524 ** none. 2525 ** 2526 ** Warnings: 2527 ** The text string returned is tucked away locally; 2528 ** copy it if you intend to save it. 2529 */ 2530 2531 char * 2532 remotename(name, m, flags, pstat, e) 2533 char *name; 2534 struct mailer *m; 2535 int flags; 2536 int *pstat; 2537 register ENVELOPE *e; 2538 { 2539 register char **pvp; 2540 char *SM_NONVOLATILE fancy; 2541 char *oldg; 2542 int rwset; 2543 static char buf[MAXNAME + 1]; 2544 char lbuf[MAXNAME + 1]; 2545 char pvpbuf[PSBUFSIZE]; 2546 char addrtype[4]; 2547 2548 if (tTd(12, 1)) 2549 sm_dprintf("remotename(%s)\n", name); 2550 2551 /* don't do anything if we are tagging it as special */ 2552 if (bitset(RF_SENDERADDR, flags)) 2553 { 2554 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2555 : m->m_se_rwset; 2556 addrtype[2] = 's'; 2557 } 2558 else 2559 { 2560 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2561 : m->m_re_rwset; 2562 addrtype[2] = 'r'; 2563 } 2564 if (rwset < 0) 2565 return name; 2566 addrtype[1] = ' '; 2567 addrtype[3] = '\0'; 2568 addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 2569 macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 2570 2571 /* 2572 ** Do a heuristic crack of this name to extract any comment info. 2573 ** This will leave the name as a comment and a $g macro. 2574 */ 2575 2576 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2577 fancy = "\201g"; 2578 else 2579 fancy = crackaddr(name, e); 2580 2581 /* 2582 ** Turn the name into canonical form. 2583 ** Normally this will be RFC 822 style, i.e., "user@domain". 2584 ** If this only resolves to "user", and the "C" flag is 2585 ** specified in the sending mailer, then the sender's 2586 ** domain will be appended. 2587 */ 2588 2589 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 2590 if (pvp == NULL) 2591 return name; 2592 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2593 *pstat = EX_TEMPFAIL; 2594 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2595 { 2596 /* append from domain to this address */ 2597 register char **pxp = pvp; 2598 int l = MAXATOM; /* size of buffer for pvp */ 2599 2600 /* see if there is an "@domain" in the current name */ 2601 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 2602 { 2603 pxp++; 2604 --l; 2605 } 2606 if (*pxp == NULL) 2607 { 2608 /* no.... append the "@domain" from the sender */ 2609 register char **qxq = e->e_fromdomain; 2610 2611 while ((*pxp++ = *qxq++) != NULL) 2612 { 2613 if (--l <= 0) 2614 { 2615 *--pxp = NULL; 2616 usrerr("553 5.1.0 remotename: too many tokens"); 2617 *pstat = EX_UNAVAILABLE; 2618 break; 2619 } 2620 } 2621 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2622 *pstat = EX_TEMPFAIL; 2623 } 2624 } 2625 2626 /* 2627 ** Do more specific rewriting. 2628 ** Rewrite using ruleset 1 or 2 depending on whether this is 2629 ** a sender address or not. 2630 ** Then run it through any receiving-mailer-specific rulesets. 2631 */ 2632 2633 if (bitset(RF_SENDERADDR, flags)) 2634 { 2635 if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 2636 *pstat = EX_TEMPFAIL; 2637 } 2638 else 2639 { 2640 if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 2641 *pstat = EX_TEMPFAIL; 2642 } 2643 if (rwset > 0) 2644 { 2645 if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 2646 *pstat = EX_TEMPFAIL; 2647 } 2648 2649 /* 2650 ** Do any final sanitation the address may require. 2651 ** This will normally be used to turn internal forms 2652 ** (e.g., user@host.LOCAL) into external form. This 2653 ** may be used as a default to the above rules. 2654 */ 2655 2656 if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 2657 *pstat = EX_TEMPFAIL; 2658 2659 /* 2660 ** Now restore the comment information we had at the beginning. 2661 */ 2662 2663 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 2664 oldg = macget(&e->e_macro, 'g'); 2665 macset(&e->e_macro, 'g', lbuf); 2666 2667 SM_TRY 2668 /* need to make sure route-addrs have <angle brackets> */ 2669 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2670 expand("<\201g>", buf, sizeof buf, e); 2671 else 2672 expand(fancy, buf, sizeof buf, e); 2673 SM_FINALLY 2674 macset(&e->e_macro, 'g', oldg); 2675 SM_END_TRY 2676 2677 if (tTd(12, 1)) 2678 sm_dprintf("remotename => `%s'\n", buf); 2679 return buf; 2680 } 2681 /* 2682 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2683 ** 2684 ** Parameters: 2685 ** a -- the address to map (but just the user name part). 2686 ** sendq -- the sendq in which to install any replacement 2687 ** addresses. 2688 ** aliaslevel -- the alias nesting depth. 2689 ** e -- the envelope. 2690 ** 2691 ** Returns: 2692 ** none. 2693 */ 2694 2695 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2696 Q_PINGFLAGS|QHASNOTIFY|\ 2697 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 2698 QBYTRACE|QBYNDELAY|QBYNRELAY) 2699 2700 void 2701 maplocaluser(a, sendq, aliaslevel, e) 2702 register ADDRESS *a; 2703 ADDRESS **sendq; 2704 int aliaslevel; 2705 ENVELOPE *e; 2706 { 2707 register char **pvp; 2708 register ADDRESS *SM_NONVOLATILE a1 = NULL; 2709 char pvpbuf[PSBUFSIZE]; 2710 2711 if (tTd(29, 1)) 2712 { 2713 sm_dprintf("maplocaluser: "); 2714 printaddr(sm_debug_file(), a, false); 2715 } 2716 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 2717 if (pvp == NULL) 2718 { 2719 if (tTd(29, 9)) 2720 sm_dprintf("maplocaluser: cannot prescan %s\n", 2721 a->q_user); 2722 return; 2723 } 2724 2725 macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 2726 macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 2727 macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 2728 2729 macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 2730 if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 2731 { 2732 if (tTd(29, 9)) 2733 sm_dprintf("maplocaluser: rewrite tempfail\n"); 2734 a->q_state = QS_QUEUEUP; 2735 a->q_status = "4.4.3"; 2736 return; 2737 } 2738 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2739 { 2740 if (tTd(29, 9)) 2741 sm_dprintf("maplocaluser: doesn't resolve\n"); 2742 return; 2743 } 2744 2745 SM_TRY 2746 a1 = buildaddr(pvp, NULL, 0, e); 2747 SM_EXCEPT(exc, "E:mta.quickabort") 2748 2749 /* 2750 ** mark address as bad, S5 returned an error 2751 ** and we gave that back to the SMTP client. 2752 */ 2753 2754 a->q_state = QS_DONTSEND; 2755 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 2756 SM_END_TRY 2757 2758 /* if non-null, mailer destination specified -- has it changed? */ 2759 if (a1 == NULL || sameaddr(a, a1)) 2760 { 2761 if (tTd(29, 9)) 2762 sm_dprintf("maplocaluser: address unchanged\n"); 2763 return; 2764 } 2765 2766 /* make new address take on flags and print attributes of old */ 2767 a1->q_flags &= ~Q_COPYFLAGS; 2768 a1->q_flags |= a->q_flags & Q_COPYFLAGS; 2769 a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 2770 a1->q_finalrcpt = a->q_finalrcpt; 2771 a1->q_orcpt = a->q_orcpt; 2772 2773 /* mark old address as dead; insert new address */ 2774 a->q_state = QS_REPLACED; 2775 if (tTd(29, 5)) 2776 { 2777 sm_dprintf("maplocaluser: QS_REPLACED "); 2778 printaddr(sm_debug_file(), a, false); 2779 } 2780 a1->q_alias = a; 2781 allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 2782 (void) recipient(a1, sendq, aliaslevel, e); 2783 } 2784 /* 2785 ** DEQUOTE_INIT -- initialize dequote map 2786 ** 2787 ** Parameters: 2788 ** map -- the internal map structure. 2789 ** args -- arguments. 2790 ** 2791 ** Returns: 2792 ** true. 2793 */ 2794 2795 bool 2796 dequote_init(map, args) 2797 MAP *map; 2798 char *args; 2799 { 2800 register char *p = args; 2801 2802 /* there is no check whether there is really an argument */ 2803 map->map_mflags |= MF_KEEPQUOTES; 2804 for (;;) 2805 { 2806 while (isascii(*p) && isspace(*p)) 2807 p++; 2808 if (*p != '-') 2809 break; 2810 switch (*++p) 2811 { 2812 case 'a': 2813 map->map_app = ++p; 2814 break; 2815 2816 case 'D': 2817 map->map_mflags |= MF_DEFER; 2818 break; 2819 2820 case 'S': 2821 case 's': 2822 map->map_spacesub = *++p; 2823 break; 2824 } 2825 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2826 p++; 2827 if (*p != '\0') 2828 *p = '\0'; 2829 } 2830 if (map->map_app != NULL) 2831 map->map_app = newstr(map->map_app); 2832 2833 return true; 2834 } 2835 /* 2836 ** DEQUOTE_MAP -- unquote an address 2837 ** 2838 ** Parameters: 2839 ** map -- the internal map structure (ignored). 2840 ** name -- the name to dequote. 2841 ** av -- arguments (ignored). 2842 ** statp -- pointer to status out-parameter. 2843 ** 2844 ** Returns: 2845 ** NULL -- if there were no quotes, or if the resulting 2846 ** unquoted buffer would not be acceptable to prescan. 2847 ** else -- The dequoted buffer. 2848 */ 2849 2850 /* ARGSUSED2 */ 2851 char * 2852 dequote_map(map, name, av, statp) 2853 MAP *map; 2854 char *name; 2855 char **av; 2856 int *statp; 2857 { 2858 register char *p; 2859 register char *q; 2860 register char c; 2861 int anglecnt = 0; 2862 int cmntcnt = 0; 2863 int quotecnt = 0; 2864 int spacecnt = 0; 2865 bool quotemode = false; 2866 bool bslashmode = false; 2867 char spacesub = map->map_spacesub; 2868 2869 for (p = q = name; (c = *p++) != '\0'; ) 2870 { 2871 if (bslashmode) 2872 { 2873 bslashmode = false; 2874 *q++ = c; 2875 continue; 2876 } 2877 2878 if (c == ' ' && spacesub != '\0') 2879 c = spacesub; 2880 2881 switch (c) 2882 { 2883 case '\\': 2884 bslashmode = true; 2885 break; 2886 2887 case '(': 2888 cmntcnt++; 2889 break; 2890 2891 case ')': 2892 if (cmntcnt-- <= 0) 2893 return NULL; 2894 break; 2895 2896 case ' ': 2897 case '\t': 2898 spacecnt++; 2899 break; 2900 } 2901 2902 if (cmntcnt > 0) 2903 { 2904 *q++ = c; 2905 continue; 2906 } 2907 2908 switch (c) 2909 { 2910 case '"': 2911 quotemode = !quotemode; 2912 quotecnt++; 2913 continue; 2914 2915 case '<': 2916 anglecnt++; 2917 break; 2918 2919 case '>': 2920 if (anglecnt-- <= 0) 2921 return NULL; 2922 break; 2923 } 2924 *q++ = c; 2925 } 2926 2927 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2928 quotemode || quotecnt <= 0 || spacecnt != 0) 2929 return NULL; 2930 *q++ = '\0'; 2931 return map_rewrite(map, name, strlen(name), NULL); 2932 } 2933 /* 2934 ** RSCHECK -- check string(s) for validity using rewriting sets 2935 ** 2936 ** Parameters: 2937 ** rwset -- the rewriting set to use. 2938 ** p1 -- the first string to check. 2939 ** p2 -- the second string to check -- may be null. 2940 ** e -- the current envelope. 2941 ** flags -- control some behavior, see RSF_ in sendmail.h 2942 ** logl -- logging level. 2943 ** host -- NULL or relay host. 2944 ** logid -- id for sm_syslog. 2945 ** 2946 ** Returns: 2947 ** EX_OK -- if the rwset doesn't resolve to $#error 2948 ** else -- the failure status (message printed) 2949 */ 2950 2951 int 2952 rscheck(rwset, p1, p2, e, flags, logl, host, logid) 2953 char *rwset; 2954 char *p1; 2955 char *p2; 2956 ENVELOPE *e; 2957 int flags; 2958 int logl; 2959 char *host; 2960 char *logid; 2961 { 2962 char *volatile buf; 2963 size_t bufsize; 2964 int saveexitstat; 2965 int volatile rstat = EX_OK; 2966 char **pvp; 2967 int rsno; 2968 bool volatile discard = false; 2969 auto ADDRESS a1; 2970 bool saveQuickAbort = QuickAbort; 2971 bool saveSuprErrs = SuprErrs; 2972 bool quarantine = false; 2973 char ubuf[BUFSIZ * 2]; 2974 char buf0[MAXLINE]; 2975 char pvpbuf[PSBUFSIZE]; 2976 extern char MsgBuf[]; 2977 2978 if (tTd(48, 2)) 2979 sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 2980 p2 == NULL ? "(NULL)" : p2); 2981 2982 rsno = strtorwset(rwset, NULL, ST_FIND); 2983 if (rsno < 0) 2984 return EX_OK; 2985 2986 if (p2 != NULL) 2987 { 2988 bufsize = strlen(p1) + strlen(p2) + 2; 2989 if (bufsize > sizeof buf0) 2990 buf = sm_malloc_x(bufsize); 2991 else 2992 { 2993 buf = buf0; 2994 bufsize = sizeof buf0; 2995 } 2996 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2997 } 2998 else 2999 { 3000 bufsize = strlen(p1) + 1; 3001 if (bufsize > sizeof buf0) 3002 buf = sm_malloc_x(bufsize); 3003 else 3004 { 3005 buf = buf0; 3006 bufsize = sizeof buf0; 3007 } 3008 (void) sm_strlcpy(buf, p1, bufsize); 3009 } 3010 SM_TRY 3011 { 3012 SuprErrs = true; 3013 QuickAbort = false; 3014 pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 3015 bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC, 3016 bitset(RSF_RMCOMM, flags) ? false : true); 3017 SuprErrs = saveSuprErrs; 3018 if (pvp == NULL) 3019 { 3020 if (tTd(48, 2)) 3021 sm_dprintf("rscheck: cannot prescan input\n"); 3022 /* 3023 syserr("rscheck: cannot prescan input: \"%s\"", 3024 shortenstring(buf, MAXSHORTSTR)); 3025 rstat = EX_DATAERR; 3026 */ 3027 goto finis; 3028 } 3029 if (bitset(RSF_UNSTRUCTURED, flags)) 3030 SuprErrs = true; 3031 (void) REWRITE(pvp, rsno, e); 3032 if (bitset(RSF_UNSTRUCTURED, flags)) 3033 SuprErrs = saveSuprErrs; 3034 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 3035 pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 3036 strcmp(pvp[1], "discard") != 0)) 3037 { 3038 goto finis; 3039 } 3040 3041 if (strcmp(pvp[1], "discard") == 0) 3042 { 3043 if (tTd(48, 2)) 3044 sm_dprintf("rscheck: discard mailer selected\n"); 3045 e->e_flags |= EF_DISCARD; 3046 discard = true; 3047 } 3048 else if (strcmp(pvp[1], "error") == 0 && 3049 pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 3050 pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 3051 { 3052 if (pvp[4] == NULL || 3053 (pvp[4][0] & 0377) != CANONUSER || 3054 pvp[5] == NULL) 3055 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 3056 rwset); 3057 else 3058 { 3059 cataddr(&(pvp[5]), NULL, ubuf, 3060 sizeof ubuf, ' '); 3061 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 3062 ubuf); 3063 } 3064 macdefine(&e->e_macro, A_PERM, 3065 macid("{quarantine}"), e->e_quarmsg); 3066 quarantine = true; 3067 } 3068 else 3069 { 3070 int savelogusrerrs = LogUsrErrs; 3071 static bool logged = false; 3072 3073 /* got an error -- process it */ 3074 saveexitstat = ExitStat; 3075 LogUsrErrs = false; 3076 (void) buildaddr(pvp, &a1, 0, e); 3077 LogUsrErrs = savelogusrerrs; 3078 rstat = ExitStat; 3079 ExitStat = saveexitstat; 3080 if (!logged) 3081 { 3082 if (bitset(RSF_COUNT, flags)) 3083 markstats(e, &a1, STATS_REJECT); 3084 logged = true; 3085 } 3086 } 3087 3088 if (LogLevel > logl) 3089 { 3090 char *relay; 3091 char *p; 3092 char lbuf[MAXLINE]; 3093 3094 p = lbuf; 3095 if (p2 != NULL) 3096 { 3097 (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3098 ", arg2=%s", 3099 p2); 3100 p += strlen(p); 3101 } 3102 3103 if (host != NULL) 3104 relay = host; 3105 else 3106 relay = macvalue('_', e); 3107 if (relay != NULL) 3108 { 3109 (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3110 ", relay=%s", relay); 3111 p += strlen(p); 3112 } 3113 *p = '\0'; 3114 if (discard) 3115 sm_syslog(LOG_NOTICE, logid, 3116 "ruleset=%s, arg1=%s%s, discard", 3117 rwset, p1, lbuf); 3118 else if (quarantine) 3119 sm_syslog(LOG_NOTICE, logid, 3120 "ruleset=%s, arg1=%s%s, quarantine=%s", 3121 rwset, p1, lbuf, ubuf); 3122 else 3123 sm_syslog(LOG_NOTICE, logid, 3124 "ruleset=%s, arg1=%s%s, reject=%s", 3125 rwset, p1, lbuf, MsgBuf); 3126 } 3127 3128 finis: ; 3129 } 3130 SM_FINALLY 3131 { 3132 /* clean up */ 3133 if (buf != buf0) 3134 sm_free(buf); 3135 QuickAbort = saveQuickAbort; 3136 } 3137 SM_END_TRY 3138 3139 setstat(rstat); 3140 3141 /* rulesets don't set errno */ 3142 errno = 0; 3143 if (rstat != EX_OK && QuickAbort) 3144 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 3145 return rstat; 3146 } 3147 /* 3148 ** RSCAP -- call rewriting set to return capabilities 3149 ** 3150 ** Parameters: 3151 ** rwset -- the rewriting set to use. 3152 ** p1 -- the first string to check. 3153 ** p2 -- the second string to check -- may be null. 3154 ** e -- the current envelope. 3155 ** pvp -- pointer to token vector. 3156 ** pvpbuf -- buffer space. 3157 ** size -- size of buffer space. 3158 ** 3159 ** Returns: 3160 ** EX_UNAVAILABLE -- ruleset doesn't exist. 3161 ** EX_DATAERR -- prescan() failed. 3162 ** EX_OK -- rewrite() was successful. 3163 ** else -- return status from rewrite(). 3164 */ 3165 3166 int 3167 rscap(rwset, p1, p2, e, pvp, pvpbuf, size) 3168 char *rwset; 3169 char *p1; 3170 char *p2; 3171 ENVELOPE *e; 3172 char ***pvp; 3173 char *pvpbuf; 3174 int size; 3175 { 3176 char *volatile buf; 3177 size_t bufsize; 3178 int volatile rstat = EX_OK; 3179 int rsno; 3180 bool saveQuickAbort = QuickAbort; 3181 bool saveSuprErrs = SuprErrs; 3182 char buf0[MAXLINE]; 3183 extern char MsgBuf[]; 3184 3185 if (tTd(48, 2)) 3186 sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 3187 p2 == NULL ? "(NULL)" : p2); 3188 3189 SM_REQUIRE(pvp != NULL); 3190 rsno = strtorwset(rwset, NULL, ST_FIND); 3191 if (rsno < 0) 3192 return EX_UNAVAILABLE; 3193 3194 if (p2 != NULL) 3195 { 3196 bufsize = strlen(p1) + strlen(p2) + 2; 3197 if (bufsize > sizeof buf0) 3198 buf = sm_malloc_x(bufsize); 3199 else 3200 { 3201 buf = buf0; 3202 bufsize = sizeof buf0; 3203 } 3204 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 3205 } 3206 else 3207 { 3208 bufsize = strlen(p1) + 1; 3209 if (bufsize > sizeof buf0) 3210 buf = sm_malloc_x(bufsize); 3211 else 3212 { 3213 buf = buf0; 3214 bufsize = sizeof buf0; 3215 } 3216 (void) sm_strlcpy(buf, p1, bufsize); 3217 } 3218 SM_TRY 3219 { 3220 SuprErrs = true; 3221 QuickAbort = false; 3222 *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL, false); 3223 if (*pvp != NULL) 3224 rstat = rewrite(*pvp, rsno, 0, e, size); 3225 else 3226 { 3227 if (tTd(48, 2)) 3228 sm_dprintf("rscap: cannot prescan input\n"); 3229 rstat = EX_DATAERR; 3230 } 3231 } 3232 SM_FINALLY 3233 { 3234 /* clean up */ 3235 if (buf != buf0) 3236 sm_free(buf); 3237 SuprErrs = saveSuprErrs; 3238 QuickAbort = saveQuickAbort; 3239 3240 /* prevent information leak, this may contain rewrite error */ 3241 MsgBuf[0] = '\0'; 3242 } 3243 SM_END_TRY 3244 return rstat; 3245 } 3246