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