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