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