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