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