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