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