1 /* 2 * Copyright (c) 1998-2003 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.378 2004/05/18 20:01:54 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 /* Don't silently truncate long strings */ 2198 if (sz <= 0) 2199 syserr("cataddr: string too long"); 2200 *p = '\0'; 2201 } 2202 /* 2203 ** SAMEADDR -- Determine if two addresses are the same 2204 ** 2205 ** This is not just a straight comparison -- if the mailer doesn't 2206 ** care about the host we just ignore it, etc. 2207 ** 2208 ** Parameters: 2209 ** a, b -- pointers to the internal forms to compare. 2210 ** 2211 ** Returns: 2212 ** true -- they represent the same mailbox. 2213 ** false -- they don't. 2214 ** 2215 ** Side Effects: 2216 ** none. 2217 */ 2218 2219 bool 2220 sameaddr(a, b) 2221 register ADDRESS *a; 2222 register ADDRESS *b; 2223 { 2224 register ADDRESS *ca, *cb; 2225 2226 /* if they don't have the same mailer, forget it */ 2227 if (a->q_mailer != b->q_mailer) 2228 return false; 2229 2230 /* if the user isn't the same, we can drop out */ 2231 if (strcmp(a->q_user, b->q_user) != 0) 2232 return false; 2233 2234 /* if we have good uids for both but they differ, these are different */ 2235 if (a->q_mailer == ProgMailer) 2236 { 2237 ca = getctladdr(a); 2238 cb = getctladdr(b); 2239 if (ca != NULL && cb != NULL && 2240 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 2241 ca->q_uid != cb->q_uid) 2242 return false; 2243 } 2244 2245 /* otherwise compare hosts (but be careful for NULL ptrs) */ 2246 if (a->q_host == b->q_host) 2247 { 2248 /* probably both null pointers */ 2249 return true; 2250 } 2251 if (a->q_host == NULL || b->q_host == NULL) 2252 { 2253 /* only one is a null pointer */ 2254 return false; 2255 } 2256 if (strcmp(a->q_host, b->q_host) != 0) 2257 return false; 2258 2259 return true; 2260 } 2261 /* 2262 ** PRINTADDR -- print address (for debugging) 2263 ** 2264 ** Parameters: 2265 ** a -- the address to print 2266 ** follow -- follow the q_next chain. 2267 ** 2268 ** Returns: 2269 ** none. 2270 ** 2271 ** Side Effects: 2272 ** none. 2273 */ 2274 2275 struct qflags 2276 { 2277 char *qf_name; 2278 unsigned long qf_bit; 2279 }; 2280 2281 static struct qflags AddressFlags[] = 2282 { 2283 { "QGOODUID", QGOODUID }, 2284 { "QPRIMARY", QPRIMARY }, 2285 { "QNOTREMOTE", QNOTREMOTE }, 2286 { "QSELFREF", QSELFREF }, 2287 { "QBOGUSSHELL", QBOGUSSHELL }, 2288 { "QUNSAFEADDR", QUNSAFEADDR }, 2289 { "QPINGONSUCCESS", QPINGONSUCCESS }, 2290 { "QPINGONFAILURE", QPINGONFAILURE }, 2291 { "QPINGONDELAY", QPINGONDELAY }, 2292 { "QHASNOTIFY", QHASNOTIFY }, 2293 { "QRELAYED", QRELAYED }, 2294 { "QEXPANDED", QEXPANDED }, 2295 { "QDELIVERED", QDELIVERED }, 2296 { "QDELAYED", QDELAYED }, 2297 { "QTHISPASS", QTHISPASS }, 2298 { "QRCPTOK", QRCPTOK }, 2299 { NULL, 0 } 2300 }; 2301 2302 void 2303 printaddr(fp, a, follow) 2304 SM_FILE_T *fp; 2305 register ADDRESS *a; 2306 bool follow; 2307 { 2308 register MAILER *m; 2309 MAILER pseudomailer; 2310 register struct qflags *qfp; 2311 bool firstone; 2312 2313 if (a == NULL) 2314 { 2315 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 2316 return; 2317 } 2318 2319 while (a != NULL) 2320 { 2321 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); 2322 (void) sm_io_flush(fp, SM_TIME_DEFAULT); 2323 2324 /* find the mailer -- carefully */ 2325 m = a->q_mailer; 2326 if (m == NULL) 2327 { 2328 m = &pseudomailer; 2329 m->m_mno = -1; 2330 m->m_name = "NULL"; 2331 } 2332 2333 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2334 "%s:\n\tmailer %d (%s), host `%s'\n", 2335 a->q_paddr == NULL ? "<null>" : a->q_paddr, 2336 m->m_mno, m->m_name, 2337 a->q_host == NULL ? "<null>" : a->q_host); 2338 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2339 "\tuser `%s', ruser `%s'\n", 2340 a->q_user, 2341 a->q_ruser == NULL ? "<null>" : a->q_ruser); 2342 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 2343 switch (a->q_state) 2344 { 2345 case QS_OK: 2346 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 2347 break; 2348 2349 case QS_DONTSEND: 2350 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2351 "DONTSEND"); 2352 break; 2353 2354 case QS_BADADDR: 2355 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2356 "BADADDR"); 2357 break; 2358 2359 case QS_QUEUEUP: 2360 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2361 "QUEUEUP"); 2362 break; 2363 2364 case QS_RETRY: 2365 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 2366 break; 2367 2368 case QS_SENT: 2369 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 2370 break; 2371 2372 case QS_VERIFIED: 2373 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2374 "VERIFIED"); 2375 break; 2376 2377 case QS_EXPANDED: 2378 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2379 "EXPANDED"); 2380 break; 2381 2382 case QS_SENDER: 2383 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2384 "SENDER"); 2385 break; 2386 2387 case QS_CLONED: 2388 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2389 "CLONED"); 2390 break; 2391 2392 case QS_DISCARDED: 2393 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2394 "DISCARDED"); 2395 break; 2396 2397 case QS_REPLACED: 2398 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2399 "REPLACED"); 2400 break; 2401 2402 case QS_REMOVED: 2403 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2404 "REMOVED"); 2405 break; 2406 2407 case QS_DUPLICATE: 2408 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2409 "DUPLICATE"); 2410 break; 2411 2412 case QS_INCLUDED: 2413 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2414 "INCLUDED"); 2415 break; 2416 2417 default: 2418 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2419 "%d", a->q_state); 2420 break; 2421 } 2422 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2423 ", next=%p, alias %p, uid %d, gid %d\n", 2424 a->q_next, a->q_alias, 2425 (int) a->q_uid, (int) a->q_gid); 2426 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 2427 a->q_flags); 2428 firstone = true; 2429 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2430 { 2431 if (!bitset(qfp->qf_bit, a->q_flags)) 2432 continue; 2433 if (!firstone) 2434 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2435 ","); 2436 firstone = false; 2437 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 2438 qfp->qf_name); 2439 } 2440 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2441 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2442 "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2443 a->q_owner == NULL ? "(none)" : a->q_owner, 2444 a->q_home == NULL ? "(none)" : a->q_home, 2445 a->q_fullname == NULL ? "(none)" : a->q_fullname); 2446 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2447 "\torcpt=\"%s\", statmta=%s, status=%s\n", 2448 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2449 a->q_statmta == NULL ? "(none)" : a->q_statmta, 2450 a->q_status == NULL ? "(none)" : a->q_status); 2451 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2452 "\tfinalrcpt=\"%s\"\n", 2453 a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2454 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2455 "\trstatus=\"%s\"\n", 2456 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2457 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2458 "\tstatdate=%s\n", 2459 a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2460 2461 if (!follow) 2462 return; 2463 a = a->q_next; 2464 } 2465 } 2466 /* 2467 ** EMPTYADDR -- return true if this address is empty (``<>'') 2468 ** 2469 ** Parameters: 2470 ** a -- pointer to the address 2471 ** 2472 ** Returns: 2473 ** true -- if this address is "empty" (i.e., no one should 2474 ** ever generate replies to it. 2475 ** false -- if it is a "regular" (read: replyable) address. 2476 */ 2477 2478 bool 2479 emptyaddr(a) 2480 register ADDRESS *a; 2481 { 2482 return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2483 a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2484 } 2485 /* 2486 ** REMOTENAME -- return the name relative to the current mailer 2487 ** 2488 ** Parameters: 2489 ** name -- the name to translate. 2490 ** m -- the mailer that we want to do rewriting relative to. 2491 ** flags -- fine tune operations. 2492 ** pstat -- pointer to status word. 2493 ** e -- the current envelope. 2494 ** 2495 ** Returns: 2496 ** the text string representing this address relative to 2497 ** the receiving mailer. 2498 ** 2499 ** Side Effects: 2500 ** none. 2501 ** 2502 ** Warnings: 2503 ** The text string returned is tucked away locally; 2504 ** copy it if you intend to save it. 2505 */ 2506 2507 char * 2508 remotename(name, m, flags, pstat, e) 2509 char *name; 2510 struct mailer *m; 2511 int flags; 2512 int *pstat; 2513 register ENVELOPE *e; 2514 { 2515 register char **pvp; 2516 char *SM_NONVOLATILE fancy; 2517 char *oldg; 2518 int rwset; 2519 static char buf[MAXNAME + 1]; 2520 char lbuf[MAXNAME + 1]; 2521 char pvpbuf[PSBUFSIZE]; 2522 char addrtype[4]; 2523 2524 if (tTd(12, 1)) 2525 sm_dprintf("remotename(%s)\n", name); 2526 2527 /* don't do anything if we are tagging it as special */ 2528 if (bitset(RF_SENDERADDR, flags)) 2529 { 2530 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2531 : m->m_se_rwset; 2532 addrtype[2] = 's'; 2533 } 2534 else 2535 { 2536 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2537 : m->m_re_rwset; 2538 addrtype[2] = 'r'; 2539 } 2540 if (rwset < 0) 2541 return name; 2542 addrtype[1] = ' '; 2543 addrtype[3] = '\0'; 2544 addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 2545 macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 2546 2547 /* 2548 ** Do a heuristic crack of this name to extract any comment info. 2549 ** This will leave the name as a comment and a $g macro. 2550 */ 2551 2552 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2553 fancy = "\201g"; 2554 else 2555 fancy = crackaddr(name, e); 2556 2557 /* 2558 ** Turn the name into canonical form. 2559 ** Normally this will be RFC 822 style, i.e., "user@domain". 2560 ** If this only resolves to "user", and the "C" flag is 2561 ** specified in the sending mailer, then the sender's 2562 ** domain will be appended. 2563 */ 2564 2565 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 2566 if (pvp == NULL) 2567 return name; 2568 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2569 *pstat = EX_TEMPFAIL; 2570 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2571 { 2572 /* append from domain to this address */ 2573 register char **pxp = pvp; 2574 int l = MAXATOM; /* size of buffer for pvp */ 2575 2576 /* see if there is an "@domain" in the current name */ 2577 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 2578 { 2579 pxp++; 2580 --l; 2581 } 2582 if (*pxp == NULL) 2583 { 2584 /* no.... append the "@domain" from the sender */ 2585 register char **qxq = e->e_fromdomain; 2586 2587 while ((*pxp++ = *qxq++) != NULL) 2588 { 2589 if (--l <= 0) 2590 { 2591 *--pxp = NULL; 2592 usrerr("553 5.1.0 remotename: too many tokens"); 2593 *pstat = EX_UNAVAILABLE; 2594 break; 2595 } 2596 } 2597 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2598 *pstat = EX_TEMPFAIL; 2599 } 2600 } 2601 2602 /* 2603 ** Do more specific rewriting. 2604 ** Rewrite using ruleset 1 or 2 depending on whether this is 2605 ** a sender address or not. 2606 ** Then run it through any receiving-mailer-specific rulesets. 2607 */ 2608 2609 if (bitset(RF_SENDERADDR, flags)) 2610 { 2611 if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 2612 *pstat = EX_TEMPFAIL; 2613 } 2614 else 2615 { 2616 if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 2617 *pstat = EX_TEMPFAIL; 2618 } 2619 if (rwset > 0) 2620 { 2621 if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 2622 *pstat = EX_TEMPFAIL; 2623 } 2624 2625 /* 2626 ** Do any final sanitation the address may require. 2627 ** This will normally be used to turn internal forms 2628 ** (e.g., user@host.LOCAL) into external form. This 2629 ** may be used as a default to the above rules. 2630 */ 2631 2632 if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 2633 *pstat = EX_TEMPFAIL; 2634 2635 /* 2636 ** Now restore the comment information we had at the beginning. 2637 */ 2638 2639 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 2640 oldg = macget(&e->e_macro, 'g'); 2641 macset(&e->e_macro, 'g', lbuf); 2642 2643 SM_TRY 2644 /* need to make sure route-addrs have <angle brackets> */ 2645 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2646 expand("<\201g>", buf, sizeof buf, e); 2647 else 2648 expand(fancy, buf, sizeof buf, e); 2649 SM_FINALLY 2650 macset(&e->e_macro, 'g', oldg); 2651 SM_END_TRY 2652 2653 if (tTd(12, 1)) 2654 sm_dprintf("remotename => `%s'\n", buf); 2655 return buf; 2656 } 2657 /* 2658 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2659 ** 2660 ** Parameters: 2661 ** a -- the address to map (but just the user name part). 2662 ** sendq -- the sendq in which to install any replacement 2663 ** addresses. 2664 ** aliaslevel -- the alias nesting depth. 2665 ** e -- the envelope. 2666 ** 2667 ** Returns: 2668 ** none. 2669 */ 2670 2671 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2672 Q_PINGFLAGS|QHASNOTIFY|\ 2673 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 2674 QBYTRACE|QBYNDELAY|QBYNRELAY) 2675 2676 void 2677 maplocaluser(a, sendq, aliaslevel, e) 2678 register ADDRESS *a; 2679 ADDRESS **sendq; 2680 int aliaslevel; 2681 ENVELOPE *e; 2682 { 2683 register char **pvp; 2684 register ADDRESS *SM_NONVOLATILE a1 = NULL; 2685 char pvpbuf[PSBUFSIZE]; 2686 2687 if (tTd(29, 1)) 2688 { 2689 sm_dprintf("maplocaluser: "); 2690 printaddr(sm_debug_file(), a, false); 2691 } 2692 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 2693 if (pvp == NULL) 2694 { 2695 if (tTd(29, 9)) 2696 sm_dprintf("maplocaluser: cannot prescan %s\n", 2697 a->q_user); 2698 return; 2699 } 2700 2701 macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 2702 macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 2703 macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 2704 2705 macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 2706 if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 2707 { 2708 if (tTd(29, 9)) 2709 sm_dprintf("maplocaluser: rewrite tempfail\n"); 2710 a->q_state = QS_QUEUEUP; 2711 a->q_status = "4.4.3"; 2712 return; 2713 } 2714 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2715 { 2716 if (tTd(29, 9)) 2717 sm_dprintf("maplocaluser: doesn't resolve\n"); 2718 return; 2719 } 2720 2721 SM_TRY 2722 a1 = buildaddr(pvp, NULL, 0, e); 2723 SM_EXCEPT(exc, "E:mta.quickabort") 2724 2725 /* 2726 ** mark address as bad, S5 returned an error 2727 ** and we gave that back to the SMTP client. 2728 */ 2729 2730 a->q_state = QS_DONTSEND; 2731 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 2732 SM_END_TRY 2733 2734 /* if non-null, mailer destination specified -- has it changed? */ 2735 if (a1 == NULL || sameaddr(a, a1)) 2736 { 2737 if (tTd(29, 9)) 2738 sm_dprintf("maplocaluser: address unchanged\n"); 2739 return; 2740 } 2741 2742 /* make new address take on flags and print attributes of old */ 2743 a1->q_flags &= ~Q_COPYFLAGS; 2744 a1->q_flags |= a->q_flags & Q_COPYFLAGS; 2745 a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 2746 a1->q_finalrcpt = a->q_finalrcpt; 2747 a1->q_orcpt = a->q_orcpt; 2748 2749 /* mark old address as dead; insert new address */ 2750 a->q_state = QS_REPLACED; 2751 if (tTd(29, 5)) 2752 { 2753 sm_dprintf("maplocaluser: QS_REPLACED "); 2754 printaddr(sm_debug_file(), a, false); 2755 } 2756 a1->q_alias = a; 2757 allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 2758 (void) recipient(a1, sendq, aliaslevel, e); 2759 } 2760 /* 2761 ** DEQUOTE_INIT -- initialize dequote map 2762 ** 2763 ** Parameters: 2764 ** map -- the internal map structure. 2765 ** args -- arguments. 2766 ** 2767 ** Returns: 2768 ** true. 2769 */ 2770 2771 bool 2772 dequote_init(map, args) 2773 MAP *map; 2774 char *args; 2775 { 2776 register char *p = args; 2777 2778 /* there is no check whether there is really an argument */ 2779 map->map_mflags |= MF_KEEPQUOTES; 2780 for (;;) 2781 { 2782 while (isascii(*p) && isspace(*p)) 2783 p++; 2784 if (*p != '-') 2785 break; 2786 switch (*++p) 2787 { 2788 case 'a': 2789 map->map_app = ++p; 2790 break; 2791 2792 case 'D': 2793 map->map_mflags |= MF_DEFER; 2794 break; 2795 2796 case 'S': 2797 case 's': 2798 map->map_spacesub = *++p; 2799 break; 2800 } 2801 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2802 p++; 2803 if (*p != '\0') 2804 *p = '\0'; 2805 } 2806 if (map->map_app != NULL) 2807 map->map_app = newstr(map->map_app); 2808 2809 return true; 2810 } 2811 /* 2812 ** DEQUOTE_MAP -- unquote an address 2813 ** 2814 ** Parameters: 2815 ** map -- the internal map structure (ignored). 2816 ** name -- the name to dequote. 2817 ** av -- arguments (ignored). 2818 ** statp -- pointer to status out-parameter. 2819 ** 2820 ** Returns: 2821 ** NULL -- if there were no quotes, or if the resulting 2822 ** unquoted buffer would not be acceptable to prescan. 2823 ** else -- The dequoted buffer. 2824 */ 2825 2826 /* ARGSUSED2 */ 2827 char * 2828 dequote_map(map, name, av, statp) 2829 MAP *map; 2830 char *name; 2831 char **av; 2832 int *statp; 2833 { 2834 register char *p; 2835 register char *q; 2836 register char c; 2837 int anglecnt = 0; 2838 int cmntcnt = 0; 2839 int quotecnt = 0; 2840 int spacecnt = 0; 2841 bool quotemode = false; 2842 bool bslashmode = false; 2843 char spacesub = map->map_spacesub; 2844 2845 for (p = q = name; (c = *p++) != '\0'; ) 2846 { 2847 if (bslashmode) 2848 { 2849 bslashmode = false; 2850 *q++ = c; 2851 continue; 2852 } 2853 2854 if (c == ' ' && spacesub != '\0') 2855 c = spacesub; 2856 2857 switch (c) 2858 { 2859 case '\\': 2860 bslashmode = true; 2861 break; 2862 2863 case '(': 2864 cmntcnt++; 2865 break; 2866 2867 case ')': 2868 if (cmntcnt-- <= 0) 2869 return NULL; 2870 break; 2871 2872 case ' ': 2873 case '\t': 2874 spacecnt++; 2875 break; 2876 } 2877 2878 if (cmntcnt > 0) 2879 { 2880 *q++ = c; 2881 continue; 2882 } 2883 2884 switch (c) 2885 { 2886 case '"': 2887 quotemode = !quotemode; 2888 quotecnt++; 2889 continue; 2890 2891 case '<': 2892 anglecnt++; 2893 break; 2894 2895 case '>': 2896 if (anglecnt-- <= 0) 2897 return NULL; 2898 break; 2899 } 2900 *q++ = c; 2901 } 2902 2903 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2904 quotemode || quotecnt <= 0 || spacecnt != 0) 2905 return NULL; 2906 *q++ = '\0'; 2907 return map_rewrite(map, name, strlen(name), NULL); 2908 } 2909 /* 2910 ** RSCHECK -- check string(s) for validity using rewriting sets 2911 ** 2912 ** Parameters: 2913 ** rwset -- the rewriting set to use. 2914 ** p1 -- the first string to check. 2915 ** p2 -- the second string to check -- may be null. 2916 ** e -- the current envelope. 2917 ** flags -- control some behavior, see RSF_ in sendmail.h 2918 ** logl -- logging level. 2919 ** host -- NULL or relay host. 2920 ** logid -- id for sm_syslog. 2921 ** 2922 ** Returns: 2923 ** EX_OK -- if the rwset doesn't resolve to $#error 2924 ** else -- the failure status (message printed) 2925 */ 2926 2927 int 2928 rscheck(rwset, p1, p2, e, flags, logl, host, logid) 2929 char *rwset; 2930 char *p1; 2931 char *p2; 2932 ENVELOPE *e; 2933 int flags; 2934 int logl; 2935 char *host; 2936 char *logid; 2937 { 2938 char *volatile buf; 2939 int bufsize; 2940 int saveexitstat; 2941 int volatile rstat = EX_OK; 2942 char **pvp; 2943 int rsno; 2944 bool volatile discard = false; 2945 auto ADDRESS a1; 2946 bool saveQuickAbort = QuickAbort; 2947 bool saveSuprErrs = SuprErrs; 2948 bool quarantine = false; 2949 char ubuf[BUFSIZ * 2]; 2950 char buf0[MAXLINE]; 2951 char pvpbuf[PSBUFSIZE]; 2952 extern char MsgBuf[]; 2953 2954 if (tTd(48, 2)) 2955 sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 2956 p2 == NULL ? "(NULL)" : p2); 2957 2958 rsno = strtorwset(rwset, NULL, ST_FIND); 2959 if (rsno < 0) 2960 return EX_OK; 2961 2962 if (p2 != NULL) 2963 { 2964 bufsize = strlen(p1) + strlen(p2) + 2; 2965 if (bufsize > sizeof buf0) 2966 buf = sm_malloc_x(bufsize); 2967 else 2968 { 2969 buf = buf0; 2970 bufsize = sizeof buf0; 2971 } 2972 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2973 } 2974 else 2975 { 2976 bufsize = strlen(p1) + 1; 2977 if (bufsize > sizeof buf0) 2978 buf = sm_malloc_x(bufsize); 2979 else 2980 { 2981 buf = buf0; 2982 bufsize = sizeof buf0; 2983 } 2984 (void) sm_strlcpy(buf, p1, bufsize); 2985 } 2986 SM_TRY 2987 { 2988 SuprErrs = true; 2989 QuickAbort = false; 2990 pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 2991 bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC, 2992 bitset(RSF_RMCOMM, flags) ? false : true); 2993 SuprErrs = saveSuprErrs; 2994 if (pvp == NULL) 2995 { 2996 if (tTd(48, 2)) 2997 sm_dprintf("rscheck: cannot prescan input\n"); 2998 /* 2999 syserr("rscheck: cannot prescan input: \"%s\"", 3000 shortenstring(buf, MAXSHORTSTR)); 3001 rstat = EX_DATAERR; 3002 */ 3003 goto finis; 3004 } 3005 if (bitset(RSF_UNSTRUCTURED, flags)) 3006 SuprErrs = true; 3007 (void) REWRITE(pvp, rsno, e); 3008 if (bitset(RSF_UNSTRUCTURED, flags)) 3009 SuprErrs = saveSuprErrs; 3010 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 3011 pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 3012 strcmp(pvp[1], "discard") != 0)) 3013 { 3014 goto finis; 3015 } 3016 3017 if (strcmp(pvp[1], "discard") == 0) 3018 { 3019 if (tTd(48, 2)) 3020 sm_dprintf("rscheck: discard mailer selected\n"); 3021 e->e_flags |= EF_DISCARD; 3022 discard = true; 3023 } 3024 else if (strcmp(pvp[1], "error") == 0 && 3025 pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 3026 pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 3027 { 3028 if (pvp[4] == NULL || 3029 (pvp[4][0] & 0377) != CANONUSER || 3030 pvp[5] == NULL) 3031 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 3032 rwset); 3033 else 3034 { 3035 cataddr(&(pvp[5]), NULL, ubuf, 3036 sizeof ubuf, ' '); 3037 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 3038 ubuf); 3039 } 3040 macdefine(&e->e_macro, A_PERM, 3041 macid("{quarantine}"), e->e_quarmsg); 3042 quarantine = true; 3043 } 3044 else 3045 { 3046 int savelogusrerrs = LogUsrErrs; 3047 static bool logged = false; 3048 3049 /* got an error -- process it */ 3050 saveexitstat = ExitStat; 3051 LogUsrErrs = false; 3052 (void) buildaddr(pvp, &a1, 0, e); 3053 LogUsrErrs = savelogusrerrs; 3054 rstat = ExitStat; 3055 ExitStat = saveexitstat; 3056 if (!logged) 3057 { 3058 if (bitset(RSF_COUNT, flags)) 3059 markstats(e, &a1, STATS_REJECT); 3060 logged = true; 3061 } 3062 } 3063 3064 if (LogLevel > logl) 3065 { 3066 char *relay; 3067 char *p; 3068 char lbuf[MAXLINE]; 3069 3070 p = lbuf; 3071 if (p2 != NULL) 3072 { 3073 (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3074 ", arg2=%s", 3075 p2); 3076 p += strlen(p); 3077 } 3078 3079 if (host != NULL) 3080 relay = host; 3081 else 3082 relay = macvalue('_', e); 3083 if (relay != NULL) 3084 { 3085 (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3086 ", relay=%s", relay); 3087 p += strlen(p); 3088 } 3089 *p = '\0'; 3090 if (discard) 3091 sm_syslog(LOG_NOTICE, logid, 3092 "ruleset=%s, arg1=%s%s, discard", 3093 rwset, p1, lbuf); 3094 else if (quarantine) 3095 sm_syslog(LOG_NOTICE, logid, 3096 "ruleset=%s, arg1=%s%s, quarantine=%s", 3097 rwset, p1, lbuf, ubuf); 3098 else 3099 sm_syslog(LOG_NOTICE, logid, 3100 "ruleset=%s, arg1=%s%s, reject=%s", 3101 rwset, p1, lbuf, MsgBuf); 3102 } 3103 3104 finis: ; 3105 } 3106 SM_FINALLY 3107 { 3108 /* clean up */ 3109 if (buf != buf0) 3110 sm_free(buf); 3111 QuickAbort = saveQuickAbort; 3112 } 3113 SM_END_TRY 3114 3115 setstat(rstat); 3116 3117 /* rulesets don't set errno */ 3118 errno = 0; 3119 if (rstat != EX_OK && QuickAbort) 3120 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 3121 return rstat; 3122 } 3123 /* 3124 ** RSCAP -- call rewriting set to return capabilities 3125 ** 3126 ** Parameters: 3127 ** rwset -- the rewriting set to use. 3128 ** p1 -- the first string to check. 3129 ** p2 -- the second string to check -- may be null. 3130 ** e -- the current envelope. 3131 ** pvp -- pointer to token vector. 3132 ** pvpbuf -- buffer space. 3133 ** size -- size of buffer space. 3134 ** 3135 ** Returns: 3136 ** EX_UNAVAILABLE -- ruleset doesn't exist. 3137 ** EX_DATAERR -- prescan() failed. 3138 ** EX_OK -- rewrite() was successful. 3139 ** else -- return status from rewrite(). 3140 */ 3141 3142 int 3143 rscap(rwset, p1, p2, e, pvp, pvpbuf, size) 3144 char *rwset; 3145 char *p1; 3146 char *p2; 3147 ENVELOPE *e; 3148 char ***pvp; 3149 char *pvpbuf; 3150 int size; 3151 { 3152 char *volatile buf; 3153 int bufsize; 3154 int volatile rstat = EX_OK; 3155 int rsno; 3156 bool saveQuickAbort = QuickAbort; 3157 bool saveSuprErrs = SuprErrs; 3158 char buf0[MAXLINE]; 3159 extern char MsgBuf[]; 3160 3161 if (tTd(48, 2)) 3162 sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 3163 p2 == NULL ? "(NULL)" : p2); 3164 3165 if (pvp != NULL) 3166 *pvp = NULL; 3167 rsno = strtorwset(rwset, NULL, ST_FIND); 3168 if (rsno < 0) 3169 return EX_UNAVAILABLE; 3170 3171 if (p2 != NULL) 3172 { 3173 bufsize = strlen(p1) + strlen(p2) + 2; 3174 if (bufsize > sizeof buf0) 3175 buf = sm_malloc_x(bufsize); 3176 else 3177 { 3178 buf = buf0; 3179 bufsize = sizeof buf0; 3180 } 3181 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 3182 } 3183 else 3184 { 3185 bufsize = strlen(p1) + 1; 3186 if (bufsize > sizeof buf0) 3187 buf = sm_malloc_x(bufsize); 3188 else 3189 { 3190 buf = buf0; 3191 bufsize = sizeof buf0; 3192 } 3193 (void) sm_strlcpy(buf, p1, bufsize); 3194 } 3195 SM_TRY 3196 { 3197 SuprErrs = true; 3198 QuickAbort = false; 3199 *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL, false); 3200 if (*pvp != NULL) 3201 rstat = rewrite(*pvp, rsno, 0, e, size); 3202 else 3203 { 3204 if (tTd(48, 2)) 3205 sm_dprintf("rscap: cannot prescan input\n"); 3206 rstat = EX_DATAERR; 3207 } 3208 } 3209 SM_FINALLY 3210 { 3211 /* clean up */ 3212 if (buf != buf0) 3213 sm_free(buf); 3214 SuprErrs = saveSuprErrs; 3215 QuickAbort = saveQuickAbort; 3216 3217 /* prevent information leak, this may contain rewrite error */ 3218 MsgBuf[0] = '\0'; 3219 } 3220 SM_END_TRY 3221 return rstat; 3222 } 3223