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