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.400 2006/12/21 00:24:06 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: queuing 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 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 1581 /* if no replacement, use default */ 1582 if (replac == NULL && default_rvp != NULL) 1583 { 1584 /* create the default */ 1585 cataddr(default_rvp, NULL, cbuf, sizeof(cbuf), 1586 '\0', false); 1587 replac = cbuf; 1588 } 1589 1590 if (replac == NULL) 1591 { 1592 xpvp = key_rvp; 1593 } 1594 else if (*replac == '\0') 1595 { 1596 /* null replacement */ 1597 nullpvp[0] = NULL; 1598 xpvp = nullpvp; 1599 } 1600 else 1601 { 1602 /* scan the new replacement */ 1603 xpvp = prescan(replac, '\0', pvpbuf, 1604 sizeof(pvpbuf), NULL, NULL, 1605 false); 1606 if (xpvp == NULL) 1607 { 1608 /* prescan already printed error */ 1609 return EX_DATAERR; 1610 } 1611 } 1612 1613 /* append it to the token list */ 1614 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1615 { 1616 *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 1617 if (avp >= &npvp[maxatom]) 1618 goto toolong; 1619 } 1620 1621 /* restore the old trailing information */ 1622 rvp = avp - 1; 1623 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1624 if (avp >= &npvp[maxatom]) 1625 goto toolong; 1626 } 1627 1628 /* 1629 ** Check for subroutine calls. 1630 */ 1631 1632 status = callsubr(npvp, reclevel, e); 1633 if (rstat == EX_OK || status == EX_TEMPFAIL) 1634 rstat = status; 1635 1636 /* copy vector back into original space. */ 1637 for (avp = npvp; *avp++ != NULL;) 1638 continue; 1639 memmove((char *) pvp, (char *) npvp, 1640 (int) (avp - npvp) * sizeof(*avp)); 1641 1642 if (tTd(21, 4)) 1643 { 1644 sm_dprintf("rewritten as:"); 1645 printav(sm_debug_file(), pvp); 1646 } 1647 } 1648 1649 if (OpMode == MD_TEST) 1650 { 1651 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 1652 "%s%-16.16s returns:", prefix, rulename); 1653 printav(smioout, pvp); 1654 } 1655 else if (tTd(21, 1)) 1656 { 1657 sm_dprintf("%s%-16.16s returns:", prefix, rulename); 1658 printav(sm_debug_file(), pvp); 1659 } 1660 return rstat; 1661 } 1662 /* 1663 ** CALLSUBR -- call subroutines in rewrite vector 1664 ** 1665 ** Parameters: 1666 ** pvp -- pointer to token vector. 1667 ** reclevel -- the current recursion level. 1668 ** e -- the current envelope. 1669 ** 1670 ** Returns: 1671 ** The status from the subroutine call. 1672 ** 1673 ** Side Effects: 1674 ** pvp is modified. 1675 */ 1676 1677 static int 1678 callsubr(pvp, reclevel, e) 1679 char **pvp; 1680 int reclevel; 1681 ENVELOPE *e; 1682 { 1683 char **avp; 1684 register int i; 1685 int subr, j; 1686 int nsubr; 1687 int status; 1688 int rstat = EX_OK; 1689 #define MAX_SUBR 16 1690 int subrnumber[MAX_SUBR]; 1691 int subrindex[MAX_SUBR]; 1692 1693 nsubr = 0; 1694 1695 /* 1696 ** Look for subroutine calls in pvp, collect them into subr*[] 1697 ** We will perform the calls in the next loop, because we will 1698 ** call the "last" subroutine first to avoid recursive calls 1699 ** and too much copying. 1700 */ 1701 1702 for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 1703 { 1704 if ((avp[0][0] & 0377) == CALLSUBR && avp[1] != NULL) 1705 { 1706 stripquotes(avp[1]); 1707 subr = strtorwset(avp[1], NULL, ST_FIND); 1708 if (subr < 0) 1709 { 1710 syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 1711 return EX_CONFIG; 1712 } 1713 1714 /* 1715 ** XXX instead of doing this we could optimize 1716 ** the rules after reading them: just remove 1717 ** calls to empty rulesets 1718 */ 1719 1720 /* subroutine is an empty ruleset? don't call it */ 1721 if (RewriteRules[subr] == NULL) 1722 { 1723 if (tTd(21, 3)) 1724 sm_dprintf("-----skip subr %s (%d)\n", 1725 avp[1], subr); 1726 for (i = 2; avp[i] != NULL; i++) 1727 avp[i - 2] = avp[i]; 1728 avp[i - 2] = NULL; 1729 continue; 1730 } 1731 if (++nsubr >= MAX_SUBR) 1732 { 1733 syserr("554 5.3.0 Too many subroutine calls (%d max)", 1734 MAX_SUBR); 1735 return EX_CONFIG; 1736 } 1737 subrnumber[nsubr] = subr; 1738 subrindex[nsubr] = j; 1739 } 1740 } 1741 1742 /* 1743 ** Perform the actual subroutines calls, "last" one first, i.e., 1744 ** go from the right to the left through all calls, 1745 ** do the rewriting in place. 1746 */ 1747 1748 for (; nsubr > 0; nsubr--) 1749 { 1750 subr = subrnumber[nsubr]; 1751 avp = pvp + subrindex[nsubr]; 1752 1753 /* remove the subroutine call and name */ 1754 for (i = 2; avp[i] != NULL; i++) 1755 avp[i - 2] = avp[i]; 1756 avp[i - 2] = NULL; 1757 1758 /* 1759 ** Now we need to call the ruleset specified for 1760 ** the subroutine. We can do this in place since 1761 ** we call the "last" subroutine first. 1762 */ 1763 1764 status = rewrite(avp, subr, reclevel, e, 1765 MAXATOM - subrindex[nsubr]); 1766 if (status != EX_OK && status != EX_TEMPFAIL) 1767 return status; 1768 if (rstat == EX_OK || status == EX_TEMPFAIL) 1769 rstat = status; 1770 } 1771 return rstat; 1772 } 1773 /* 1774 ** MAP_LOOKUP -- do lookup in map 1775 ** 1776 ** Parameters: 1777 ** smap -- the map to use for the lookup. 1778 ** key -- the key to look up. 1779 ** argvect -- arguments to pass to the map lookup. 1780 ** pstat -- a pointer to an integer in which to store the 1781 ** status from the lookup. 1782 ** e -- the current envelope. 1783 ** 1784 ** Returns: 1785 ** The result of the lookup. 1786 ** NULL -- if there was no data for the given key. 1787 */ 1788 1789 static char * 1790 map_lookup(smap, key, argvect, pstat, e) 1791 STAB *smap; 1792 char key[]; 1793 char **argvect; 1794 int *pstat; 1795 ENVELOPE *e; 1796 { 1797 auto int status = EX_OK; 1798 MAP *map; 1799 char *replac; 1800 1801 if (smap == NULL) 1802 return NULL; 1803 1804 map = &smap->s_map; 1805 DYNOPENMAP(map); 1806 1807 if (e->e_sendmode == SM_DEFER && 1808 bitset(MF_DEFER, map->map_mflags)) 1809 { 1810 /* don't do any map lookups */ 1811 if (tTd(60, 1)) 1812 sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 1813 smap->s_name, key); 1814 *pstat = EX_TEMPFAIL; 1815 return NULL; 1816 } 1817 1818 if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1819 stripquotes(key); 1820 1821 if (tTd(60, 1)) 1822 { 1823 sm_dprintf("map_lookup(%s, ", smap->s_name); 1824 xputs(sm_debug_file(), key); 1825 if (tTd(60, 5)) 1826 { 1827 int i; 1828 1829 for (i = 0; argvect[i] != NULL; i++) 1830 sm_dprintf(", %%%d=%s", i, argvect[i]); 1831 } 1832 sm_dprintf(") => "); 1833 } 1834 replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1835 if (tTd(60, 1)) 1836 sm_dprintf("%s (%d)\n", 1837 replac != NULL ? replac : "NOT FOUND", 1838 status); 1839 1840 /* should recover if status == EX_TEMPFAIL */ 1841 if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1842 { 1843 *pstat = EX_TEMPFAIL; 1844 if (tTd(60, 1)) 1845 sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 1846 smap->s_name, key, errno); 1847 if (e->e_message == NULL) 1848 { 1849 char mbuf[320]; 1850 1851 (void) sm_snprintf(mbuf, sizeof(mbuf), 1852 "%.80s map: lookup (%s): deferred", 1853 smap->s_name, 1854 shortenstring(key, MAXSHORTSTR)); 1855 e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 1856 } 1857 } 1858 if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1859 { 1860 size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1861 static char *rwbuf = NULL; 1862 static size_t rwbuflen = 0; 1863 1864 if (i > rwbuflen) 1865 { 1866 if (rwbuf != NULL) 1867 sm_free(rwbuf); 1868 rwbuflen = i; 1869 rwbuf = (char *) sm_pmalloc_x(rwbuflen); 1870 } 1871 (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 1872 if (tTd(60, 4)) 1873 sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 1874 rwbuf); 1875 return rwbuf; 1876 } 1877 return replac; 1878 } 1879 /* 1880 ** INITERRMAILERS -- initialize error and discard mailers 1881 ** 1882 ** Parameters: 1883 ** none. 1884 ** 1885 ** Returns: 1886 ** none. 1887 ** 1888 ** Side Effects: 1889 ** initializes error and discard mailers. 1890 */ 1891 1892 static MAILER discardmailer; 1893 static MAILER errormailer; 1894 static char *discardargv[] = { "DISCARD", NULL }; 1895 static char *errorargv[] = { "ERROR", NULL }; 1896 1897 void 1898 initerrmailers() 1899 { 1900 if (discardmailer.m_name == NULL) 1901 { 1902 /* initialize the discard mailer */ 1903 discardmailer.m_name = "*discard*"; 1904 discardmailer.m_mailer = "DISCARD"; 1905 discardmailer.m_argv = discardargv; 1906 } 1907 if (errormailer.m_name == NULL) 1908 { 1909 /* initialize the bogus mailer */ 1910 errormailer.m_name = "*error*"; 1911 errormailer.m_mailer = "ERROR"; 1912 errormailer.m_argv = errorargv; 1913 } 1914 } 1915 /* 1916 ** BUILDADDR -- build address from token vector. 1917 ** 1918 ** Parameters: 1919 ** tv -- token vector. 1920 ** a -- pointer to address descriptor to fill. 1921 ** If NULL, one will be allocated. 1922 ** flags -- info regarding whether this is a sender or 1923 ** a recipient. 1924 ** e -- the current envelope. 1925 ** 1926 ** Returns: 1927 ** NULL if there was an error. 1928 ** 'a' otherwise. 1929 ** 1930 ** Side Effects: 1931 ** fills in 'a' 1932 */ 1933 1934 static struct errcodes 1935 { 1936 char *ec_name; /* name of error code */ 1937 int ec_code; /* numeric code */ 1938 } ErrorCodes[] = 1939 { 1940 { "usage", EX_USAGE }, 1941 { "nouser", EX_NOUSER }, 1942 { "nohost", EX_NOHOST }, 1943 { "unavailable", EX_UNAVAILABLE }, 1944 { "software", EX_SOFTWARE }, 1945 { "tempfail", EX_TEMPFAIL }, 1946 { "protocol", EX_PROTOCOL }, 1947 { "config", EX_CONFIG }, 1948 { NULL, EX_UNAVAILABLE } 1949 }; 1950 1951 static ADDRESS * 1952 buildaddr(tv, a, flags, e) 1953 register char **tv; 1954 register ADDRESS *a; 1955 int flags; 1956 register ENVELOPE *e; 1957 { 1958 bool tempfail = false; 1959 int maxatom; 1960 struct mailer **mp; 1961 register struct mailer *m; 1962 register char *p; 1963 char *mname; 1964 char **hostp; 1965 char hbuf[MAXNAME + 1]; 1966 static char ubuf[MAXNAME + 2]; 1967 1968 if (tTd(24, 5)) 1969 { 1970 sm_dprintf("buildaddr, flags=%x, tv=", flags); 1971 printav(sm_debug_file(), tv); 1972 } 1973 1974 maxatom = MAXATOM; 1975 if (a == NULL) 1976 a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a)); 1977 memset((char *) a, '\0', sizeof(*a)); 1978 hbuf[0] = '\0'; 1979 1980 /* set up default error return flags */ 1981 a->q_flags |= DefaultNotify; 1982 1983 /* figure out what net/mailer to use */ 1984 if (*tv == NULL || (**tv & 0377) != CANONNET) 1985 { 1986 syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 1987 badaddr: 1988 /* 1989 ** ExitStat may have been set by an earlier map open 1990 ** failure (to a permanent error (EX_OSERR) in syserr()) 1991 ** so we also need to check if this particular $#error 1992 ** return wanted a 4XX failure. 1993 ** 1994 ** XXX the real fix is probably to set ExitStat correctly, 1995 ** i.e., to EX_TEMPFAIL if the map open is just a temporary 1996 ** error. 1997 */ 1998 1999 if (ExitStat == EX_TEMPFAIL || tempfail) 2000 a->q_state = QS_QUEUEUP; 2001 else 2002 { 2003 a->q_state = QS_BADADDR; 2004 a->q_mailer = &errormailer; 2005 } 2006 return a; 2007 } 2008 mname = *++tv; 2009 --maxatom; 2010 2011 /* extract host and user portions */ 2012 if (*++tv != NULL && (**tv & 0377) == CANONHOST) 2013 { 2014 hostp = ++tv; 2015 --maxatom; 2016 } 2017 else 2018 hostp = NULL; 2019 --maxatom; 2020 while (*tv != NULL && (**tv & 0377) != CANONUSER) 2021 { 2022 tv++; 2023 --maxatom; 2024 } 2025 if (*tv == NULL) 2026 { 2027 syserr("554 5.3.5 buildaddr: no user"); 2028 goto badaddr; 2029 } 2030 if (tv == hostp) 2031 hostp = NULL; 2032 else if (hostp != NULL) 2033 cataddr(hostp, tv - 1, hbuf, sizeof(hbuf), '\0', false); 2034 cataddr(++tv, NULL, ubuf, sizeof(ubuf), ' ', false); 2035 --maxatom; 2036 2037 /* save away the host name */ 2038 if (sm_strcasecmp(mname, "error") == 0) 2039 { 2040 /* Set up triplet for use by -bv */ 2041 a->q_mailer = &errormailer; 2042 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 2043 /* XXX wrong place? */ 2044 2045 if (hostp != NULL) 2046 { 2047 register struct errcodes *ep; 2048 2049 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 2050 if (strchr(hbuf, '.') != NULL) 2051 { 2052 a->q_status = sm_rpool_strdup_x(e->e_rpool, 2053 hbuf); 2054 setstat(dsntoexitstat(hbuf)); 2055 } 2056 else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 2057 { 2058 setstat(atoi(hbuf)); 2059 } 2060 else 2061 { 2062 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 2063 if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 2064 break; 2065 setstat(ep->ec_code); 2066 } 2067 } 2068 else 2069 { 2070 a->q_host = NULL; 2071 setstat(EX_UNAVAILABLE); 2072 } 2073 stripquotes(ubuf); 2074 if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 2075 { 2076 char fmt[16]; 2077 int off; 2078 2079 if ((off = isenhsc(ubuf + 4, ' ')) > 0) 2080 { 2081 ubuf[off + 4] = '\0'; 2082 off += 5; 2083 } 2084 else 2085 { 2086 off = 4; 2087 ubuf[3] = '\0'; 2088 } 2089 (void) sm_strlcpyn(fmt, sizeof(fmt), 2, ubuf, " %s"); 2090 if (off > 4) 2091 usrerr(fmt, ubuf + off); 2092 else if (isenhsc(hbuf, '\0') > 0) 2093 usrerrenh(hbuf, fmt, ubuf + off); 2094 else 2095 usrerr(fmt, ubuf + off); 2096 /* XXX ubuf[off - 1] = ' '; */ 2097 if (ubuf[0] == '4') 2098 tempfail = true; 2099 } 2100 else 2101 { 2102 usrerr("553 5.3.0 %s", ubuf); 2103 } 2104 goto badaddr; 2105 } 2106 2107 for (mp = Mailer; (m = *mp++) != NULL; ) 2108 { 2109 if (sm_strcasecmp(m->m_name, mname) == 0) 2110 break; 2111 } 2112 if (m == NULL) 2113 { 2114 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 2115 goto badaddr; 2116 } 2117 a->q_mailer = m; 2118 2119 /* figure out what host (if any) */ 2120 if (hostp == NULL) 2121 { 2122 if (!bitnset(M_LOCALMAILER, m->m_flags)) 2123 { 2124 syserr("554 5.3.5 buildaddr: no host"); 2125 goto badaddr; 2126 } 2127 a->q_host = NULL; 2128 } 2129 else 2130 a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 2131 2132 /* figure out the user */ 2133 p = ubuf; 2134 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 2135 { 2136 p++; 2137 tv++; 2138 --maxatom; 2139 a->q_flags |= QNOTREMOTE; 2140 } 2141 2142 /* do special mapping for local mailer */ 2143 if (*p == '"') 2144 p++; 2145 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 2146 a->q_mailer = m = ProgMailer; 2147 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 2148 a->q_mailer = m = FileMailer; 2149 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 2150 { 2151 /* may be :include: */ 2152 stripquotes(ubuf); 2153 if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 2154 { 2155 /* if :include:, don't need further rewriting */ 2156 a->q_mailer = m = InclMailer; 2157 a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 2158 return a; 2159 } 2160 } 2161 2162 /* rewrite according recipient mailer rewriting rules */ 2163 macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 2164 2165 if (ConfigLevel >= 10 || 2166 !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 2167 { 2168 /* sender addresses done later */ 2169 (void) rewrite(tv, 2, 0, e, maxatom); 2170 if (m->m_re_rwset > 0) 2171 (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom); 2172 } 2173 (void) rewrite(tv, 4, 0, e, maxatom); 2174 2175 /* save the result for the command line/RCPT argument */ 2176 cataddr(tv, NULL, ubuf, sizeof(ubuf), '\0', true); 2177 a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 2178 2179 /* 2180 ** Do mapping to lower case as requested by mailer 2181 */ 2182 2183 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 2184 makelower(a->q_host); 2185 if (!bitnset(M_USR_UPPER, m->m_flags)) 2186 makelower(a->q_user); 2187 2188 if (tTd(24, 6)) 2189 { 2190 sm_dprintf("buildaddr => "); 2191 printaddr(sm_debug_file(), a, false); 2192 } 2193 return a; 2194 } 2195 2196 /* 2197 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 2198 ** 2199 ** Parameters: 2200 ** pvp -- parameter vector to rebuild. 2201 ** evp -- last parameter to include. Can be NULL to 2202 ** use entire pvp. 2203 ** buf -- buffer to build the string into. 2204 ** sz -- size of buf. 2205 ** spacesub -- the space separator character; if '\0', 2206 ** use SpaceSub. 2207 ** external -- convert to external form? 2208 ** (no metacharacters; METAQUOTEs removed, see below) 2209 ** 2210 ** Returns: 2211 ** none. 2212 ** 2213 ** Side Effects: 2214 ** Destroys buf. 2215 ** 2216 ** Notes: 2217 ** There are two formats for strings: internal and external. 2218 ** The external format is just an eight-bit clean string (no 2219 ** null bytes, everything else OK). The internal format can 2220 ** include sendmail metacharacters. The special character 2221 ** METAQUOTE essentially quotes the character following, stripping 2222 ** it of all special semantics. 2223 ** 2224 ** The cataddr routine needs to be aware of whether it is producing 2225 ** an internal or external form as output (it only takes internal 2226 ** form as input). 2227 ** 2228 ** The parseaddr routine has a similar issue on input, but that 2229 ** is flagged on the basis of which token table is passed in. 2230 */ 2231 2232 void 2233 cataddr(pvp, evp, buf, sz, spacesub, external) 2234 char **pvp; 2235 char **evp; 2236 char *buf; 2237 register int sz; 2238 int spacesub; 2239 bool external; 2240 { 2241 bool oatomtok, natomtok; 2242 char *p; 2243 2244 oatomtok = natomtok = false; 2245 if (tTd(59, 14)) 2246 { 2247 sm_dprintf("cataddr(%d) <==", external); 2248 printav(sm_debug_file(), pvp); 2249 } 2250 2251 if (sz <= 0) 2252 return; 2253 2254 if (spacesub == '\0') 2255 spacesub = SpaceSub; 2256 2257 if (pvp == NULL) 2258 { 2259 *buf = '\0'; 2260 return; 2261 } 2262 p = buf; 2263 sz -= 2; 2264 while (*pvp != NULL && sz > 0) 2265 { 2266 char *q; 2267 2268 natomtok = (ExtTokenTab[**pvp & 0xff] == ATM); 2269 if (oatomtok && natomtok) 2270 { 2271 *p++ = spacesub; 2272 if (--sz <= 0) 2273 break; 2274 } 2275 for (q = *pvp; *q != '\0'; ) 2276 { 2277 int c; 2278 2279 if (--sz <= 0) 2280 break; 2281 *p++ = c = *q++; 2282 2283 /* 2284 ** If the current character (c) is METAQUOTE and we 2285 ** want the "external" form and the next character 2286 ** is not NUL, then overwrite METAQUOTE with that 2287 ** character (i.e., METAQUOTE ch is changed to 2288 ** ch). p[-1] is used because p is advanced (above). 2289 */ 2290 2291 if ((c & 0377) == METAQUOTE && external && *q != '\0') 2292 p[-1] = *q++; 2293 } 2294 if (sz <= 0) 2295 break; 2296 oatomtok = natomtok; 2297 if (pvp++ == evp) 2298 break; 2299 } 2300 2301 #if 0 2302 /* 2303 ** Silently truncate long strings: even though this doesn't 2304 ** seem like a good idea it is necessary because header checks 2305 ** send the whole header value to rscheck() and hence rewrite(). 2306 ** The latter however sometimes uses a "short" buffer (e.g., 2307 ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this 2308 ** error function. One possible fix to the problem is to pass 2309 ** flags to rscheck() and rewrite() to distinguish the various 2310 ** calls and only trigger the error if necessary. For now just 2311 ** undo the change from 8.13.0. 2312 */ 2313 2314 if (sz <= 0) 2315 usrerr("cataddr: string too long"); 2316 #endif 2317 *p = '\0'; 2318 2319 if (tTd(59, 14)) 2320 sm_dprintf(" cataddr => %s\n", str2prt(buf)); 2321 } 2322 2323 /* 2324 ** SAMEADDR -- Determine if two addresses are the same 2325 ** 2326 ** This is not just a straight comparison -- if the mailer doesn't 2327 ** care about the host we just ignore it, etc. 2328 ** 2329 ** Parameters: 2330 ** a, b -- pointers to the internal forms to compare. 2331 ** 2332 ** Returns: 2333 ** true -- they represent the same mailbox. 2334 ** false -- they don't. 2335 ** 2336 ** Side Effects: 2337 ** none. 2338 */ 2339 2340 bool 2341 sameaddr(a, b) 2342 register ADDRESS *a; 2343 register ADDRESS *b; 2344 { 2345 register ADDRESS *ca, *cb; 2346 2347 /* if they don't have the same mailer, forget it */ 2348 if (a->q_mailer != b->q_mailer) 2349 return false; 2350 2351 /* if the user isn't the same, we can drop out */ 2352 if (strcmp(a->q_user, b->q_user) != 0) 2353 return false; 2354 2355 /* if we have good uids for both but they differ, these are different */ 2356 if (a->q_mailer == ProgMailer) 2357 { 2358 ca = getctladdr(a); 2359 cb = getctladdr(b); 2360 if (ca != NULL && cb != NULL && 2361 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 2362 ca->q_uid != cb->q_uid) 2363 return false; 2364 } 2365 2366 /* otherwise compare hosts (but be careful for NULL ptrs) */ 2367 if (a->q_host == b->q_host) 2368 { 2369 /* probably both null pointers */ 2370 return true; 2371 } 2372 if (a->q_host == NULL || b->q_host == NULL) 2373 { 2374 /* only one is a null pointer */ 2375 return false; 2376 } 2377 if (strcmp(a->q_host, b->q_host) != 0) 2378 return false; 2379 2380 return true; 2381 } 2382 /* 2383 ** PRINTADDR -- print address (for debugging) 2384 ** 2385 ** Parameters: 2386 ** a -- the address to print 2387 ** follow -- follow the q_next chain. 2388 ** 2389 ** Returns: 2390 ** none. 2391 ** 2392 ** Side Effects: 2393 ** none. 2394 */ 2395 2396 struct qflags 2397 { 2398 char *qf_name; 2399 unsigned long qf_bit; 2400 }; 2401 2402 static struct qflags AddressFlags[] = 2403 { 2404 { "QGOODUID", QGOODUID }, 2405 { "QPRIMARY", QPRIMARY }, 2406 { "QNOTREMOTE", QNOTREMOTE }, 2407 { "QSELFREF", QSELFREF }, 2408 { "QBOGUSSHELL", QBOGUSSHELL }, 2409 { "QUNSAFEADDR", QUNSAFEADDR }, 2410 { "QPINGONSUCCESS", QPINGONSUCCESS }, 2411 { "QPINGONFAILURE", QPINGONFAILURE }, 2412 { "QPINGONDELAY", QPINGONDELAY }, 2413 { "QHASNOTIFY", QHASNOTIFY }, 2414 { "QRELAYED", QRELAYED }, 2415 { "QEXPANDED", QEXPANDED }, 2416 { "QDELIVERED", QDELIVERED }, 2417 { "QDELAYED", QDELAYED }, 2418 { "QTHISPASS", QTHISPASS }, 2419 { "QRCPTOK", QRCPTOK }, 2420 { NULL, 0 } 2421 }; 2422 2423 void 2424 printaddr(fp, a, follow) 2425 SM_FILE_T *fp; 2426 register ADDRESS *a; 2427 bool follow; 2428 { 2429 register MAILER *m; 2430 MAILER pseudomailer; 2431 register struct qflags *qfp; 2432 bool firstone; 2433 2434 if (a == NULL) 2435 { 2436 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 2437 return; 2438 } 2439 2440 while (a != NULL) 2441 { 2442 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); 2443 (void) sm_io_flush(fp, SM_TIME_DEFAULT); 2444 2445 /* find the mailer -- carefully */ 2446 m = a->q_mailer; 2447 if (m == NULL) 2448 { 2449 m = &pseudomailer; 2450 m->m_mno = -1; 2451 m->m_name = "NULL"; 2452 } 2453 2454 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2455 "%s:\n\tmailer %d (%s), host `%s'\n", 2456 a->q_paddr == NULL ? "<null>" : a->q_paddr, 2457 m->m_mno, m->m_name, 2458 a->q_host == NULL ? "<null>" : a->q_host); 2459 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2460 "\tuser `%s', ruser `%s'\n", 2461 a->q_user, 2462 a->q_ruser == NULL ? "<null>" : a->q_ruser); 2463 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 2464 switch (a->q_state) 2465 { 2466 case QS_OK: 2467 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 2468 break; 2469 2470 case QS_DONTSEND: 2471 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2472 "DONTSEND"); 2473 break; 2474 2475 case QS_BADADDR: 2476 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2477 "BADADDR"); 2478 break; 2479 2480 case QS_QUEUEUP: 2481 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2482 "QUEUEUP"); 2483 break; 2484 2485 case QS_RETRY: 2486 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 2487 break; 2488 2489 case QS_SENT: 2490 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 2491 break; 2492 2493 case QS_VERIFIED: 2494 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2495 "VERIFIED"); 2496 break; 2497 2498 case QS_EXPANDED: 2499 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2500 "EXPANDED"); 2501 break; 2502 2503 case QS_SENDER: 2504 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2505 "SENDER"); 2506 break; 2507 2508 case QS_CLONED: 2509 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2510 "CLONED"); 2511 break; 2512 2513 case QS_DISCARDED: 2514 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2515 "DISCARDED"); 2516 break; 2517 2518 case QS_REPLACED: 2519 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2520 "REPLACED"); 2521 break; 2522 2523 case QS_REMOVED: 2524 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2525 "REMOVED"); 2526 break; 2527 2528 case QS_DUPLICATE: 2529 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2530 "DUPLICATE"); 2531 break; 2532 2533 case QS_INCLUDED: 2534 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2535 "INCLUDED"); 2536 break; 2537 2538 default: 2539 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2540 "%d", a->q_state); 2541 break; 2542 } 2543 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2544 ", next=%p, alias %p, uid %d, gid %d\n", 2545 a->q_next, a->q_alias, 2546 (int) a->q_uid, (int) a->q_gid); 2547 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 2548 a->q_flags); 2549 firstone = true; 2550 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2551 { 2552 if (!bitset(qfp->qf_bit, a->q_flags)) 2553 continue; 2554 if (!firstone) 2555 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2556 ","); 2557 firstone = false; 2558 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 2559 qfp->qf_name); 2560 } 2561 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2562 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2563 "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2564 a->q_owner == NULL ? "(none)" : a->q_owner, 2565 a->q_home == NULL ? "(none)" : a->q_home, 2566 a->q_fullname == NULL ? "(none)" : a->q_fullname); 2567 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2568 "\torcpt=\"%s\", statmta=%s, status=%s\n", 2569 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2570 a->q_statmta == NULL ? "(none)" : a->q_statmta, 2571 a->q_status == NULL ? "(none)" : a->q_status); 2572 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2573 "\tfinalrcpt=\"%s\"\n", 2574 a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2575 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2576 "\trstatus=\"%s\"\n", 2577 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2578 (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 2579 "\tstatdate=%s\n", 2580 a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2581 2582 if (!follow) 2583 return; 2584 a = a->q_next; 2585 } 2586 } 2587 /* 2588 ** EMPTYADDR -- return true if this address is empty (``<>'') 2589 ** 2590 ** Parameters: 2591 ** a -- pointer to the address 2592 ** 2593 ** Returns: 2594 ** true -- if this address is "empty" (i.e., no one should 2595 ** ever generate replies to it. 2596 ** false -- if it is a "regular" (read: replyable) address. 2597 */ 2598 2599 bool 2600 emptyaddr(a) 2601 register ADDRESS *a; 2602 { 2603 return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2604 a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2605 } 2606 /* 2607 ** REMOTENAME -- return the name relative to the current mailer 2608 ** 2609 ** Parameters: 2610 ** name -- the name to translate. 2611 ** m -- the mailer that we want to do rewriting relative to. 2612 ** flags -- fine tune operations. 2613 ** pstat -- pointer to status word. 2614 ** e -- the current envelope. 2615 ** 2616 ** Returns: 2617 ** the text string representing this address relative to 2618 ** the receiving mailer. 2619 ** 2620 ** Side Effects: 2621 ** none. 2622 ** 2623 ** Warnings: 2624 ** The text string returned is tucked away locally; 2625 ** copy it if you intend to save it. 2626 */ 2627 2628 char * 2629 remotename(name, m, flags, pstat, e) 2630 char *name; 2631 struct mailer *m; 2632 int flags; 2633 int *pstat; 2634 register ENVELOPE *e; 2635 { 2636 register char **pvp; 2637 char *SM_NONVOLATILE fancy; 2638 char *oldg; 2639 int rwset; 2640 static char buf[MAXNAME + 1]; 2641 char lbuf[MAXNAME + 1]; 2642 char pvpbuf[PSBUFSIZE]; 2643 char addrtype[4]; 2644 2645 if (tTd(12, 1)) 2646 { 2647 sm_dprintf("remotename("); 2648 xputs(sm_debug_file(), name); 2649 sm_dprintf(")\n"); 2650 } 2651 2652 /* don't do anything if we are tagging it as special */ 2653 if (bitset(RF_SENDERADDR, flags)) 2654 { 2655 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2656 : m->m_se_rwset; 2657 addrtype[2] = 's'; 2658 } 2659 else 2660 { 2661 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2662 : m->m_re_rwset; 2663 addrtype[2] = 'r'; 2664 } 2665 if (rwset < 0) 2666 return name; 2667 addrtype[1] = ' '; 2668 addrtype[3] = '\0'; 2669 addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 2670 macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 2671 2672 /* 2673 ** Do a heuristic crack of this name to extract any comment info. 2674 ** This will leave the name as a comment and a $g macro. 2675 */ 2676 2677 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2678 fancy = "\201g"; 2679 else 2680 fancy = crackaddr(name, e); 2681 2682 /* 2683 ** Turn the name into canonical form. 2684 ** Normally this will be RFC 822 style, i.e., "user@domain". 2685 ** If this only resolves to "user", and the "C" flag is 2686 ** specified in the sending mailer, then the sender's 2687 ** domain will be appended. 2688 */ 2689 2690 pvp = prescan(name, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, false); 2691 if (pvp == NULL) 2692 return name; 2693 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2694 *pstat = EX_TEMPFAIL; 2695 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2696 { 2697 /* append from domain to this address */ 2698 register char **pxp = pvp; 2699 int l = MAXATOM; /* size of buffer for pvp */ 2700 2701 /* see if there is an "@domain" in the current name */ 2702 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 2703 { 2704 pxp++; 2705 --l; 2706 } 2707 if (*pxp == NULL) 2708 { 2709 /* no.... append the "@domain" from the sender */ 2710 register char **qxq = e->e_fromdomain; 2711 2712 while ((*pxp++ = *qxq++) != NULL) 2713 { 2714 if (--l <= 0) 2715 { 2716 *--pxp = NULL; 2717 usrerr("553 5.1.0 remotename: too many tokens"); 2718 *pstat = EX_UNAVAILABLE; 2719 break; 2720 } 2721 } 2722 if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2723 *pstat = EX_TEMPFAIL; 2724 } 2725 } 2726 2727 /* 2728 ** Do more specific rewriting. 2729 ** Rewrite using ruleset 1 or 2 depending on whether this is 2730 ** a sender address or not. 2731 ** Then run it through any receiving-mailer-specific rulesets. 2732 */ 2733 2734 if (bitset(RF_SENDERADDR, flags)) 2735 { 2736 if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 2737 *pstat = EX_TEMPFAIL; 2738 } 2739 else 2740 { 2741 if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 2742 *pstat = EX_TEMPFAIL; 2743 } 2744 if (rwset > 0) 2745 { 2746 if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 2747 *pstat = EX_TEMPFAIL; 2748 } 2749 2750 /* 2751 ** Do any final sanitation the address may require. 2752 ** This will normally be used to turn internal forms 2753 ** (e.g., user@host.LOCAL) into external form. This 2754 ** may be used as a default to the above rules. 2755 */ 2756 2757 if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 2758 *pstat = EX_TEMPFAIL; 2759 2760 /* 2761 ** Now restore the comment information we had at the beginning. 2762 */ 2763 2764 cataddr(pvp, NULL, lbuf, sizeof(lbuf), '\0', false); 2765 oldg = macget(&e->e_macro, 'g'); 2766 macset(&e->e_macro, 'g', lbuf); 2767 2768 SM_TRY 2769 /* need to make sure route-addrs have <angle brackets> */ 2770 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2771 expand("<\201g>", buf, sizeof(buf), e); 2772 else 2773 expand(fancy, buf, sizeof(buf), e); 2774 SM_FINALLY 2775 macset(&e->e_macro, 'g', oldg); 2776 SM_END_TRY 2777 2778 if (tTd(12, 1)) 2779 { 2780 sm_dprintf("remotename => `"); 2781 xputs(sm_debug_file(), buf); 2782 sm_dprintf("'\n"); 2783 } 2784 return buf; 2785 } 2786 /* 2787 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2788 ** 2789 ** Parameters: 2790 ** a -- the address to map (but just the user name part). 2791 ** sendq -- the sendq in which to install any replacement 2792 ** addresses. 2793 ** aliaslevel -- the alias nesting depth. 2794 ** e -- the envelope. 2795 ** 2796 ** Returns: 2797 ** none. 2798 */ 2799 2800 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2801 Q_PINGFLAGS|QHASNOTIFY|\ 2802 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 2803 QBYTRACE|QBYNDELAY|QBYNRELAY) 2804 2805 void 2806 maplocaluser(a, sendq, aliaslevel, e) 2807 register ADDRESS *a; 2808 ADDRESS **sendq; 2809 int aliaslevel; 2810 ENVELOPE *e; 2811 { 2812 register char **pvp; 2813 register ADDRESS *SM_NONVOLATILE a1 = NULL; 2814 char pvpbuf[PSBUFSIZE]; 2815 2816 if (tTd(29, 1)) 2817 { 2818 sm_dprintf("maplocaluser: "); 2819 printaddr(sm_debug_file(), a, false); 2820 } 2821 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, 2822 false); 2823 if (pvp == NULL) 2824 { 2825 if (tTd(29, 9)) 2826 sm_dprintf("maplocaluser: cannot prescan %s\n", 2827 a->q_user); 2828 return; 2829 } 2830 2831 macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 2832 macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 2833 macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 2834 2835 macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 2836 if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 2837 { 2838 if (tTd(29, 9)) 2839 sm_dprintf("maplocaluser: rewrite tempfail\n"); 2840 a->q_state = QS_QUEUEUP; 2841 a->q_status = "4.4.3"; 2842 return; 2843 } 2844 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2845 { 2846 if (tTd(29, 9)) 2847 sm_dprintf("maplocaluser: doesn't resolve\n"); 2848 return; 2849 } 2850 2851 SM_TRY 2852 a1 = buildaddr(pvp, NULL, 0, e); 2853 SM_EXCEPT(exc, "E:mta.quickabort") 2854 2855 /* 2856 ** mark address as bad, S5 returned an error 2857 ** and we gave that back to the SMTP client. 2858 */ 2859 2860 a->q_state = QS_DONTSEND; 2861 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 2862 SM_END_TRY 2863 2864 /* if non-null, mailer destination specified -- has it changed? */ 2865 if (a1 == NULL || sameaddr(a, a1)) 2866 { 2867 if (tTd(29, 9)) 2868 sm_dprintf("maplocaluser: address unchanged\n"); 2869 return; 2870 } 2871 2872 /* make new address take on flags and print attributes of old */ 2873 a1->q_flags &= ~Q_COPYFLAGS; 2874 a1->q_flags |= a->q_flags & Q_COPYFLAGS; 2875 a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 2876 a1->q_finalrcpt = a->q_finalrcpt; 2877 a1->q_orcpt = a->q_orcpt; 2878 2879 /* mark old address as dead; insert new address */ 2880 a->q_state = QS_REPLACED; 2881 if (tTd(29, 5)) 2882 { 2883 sm_dprintf("maplocaluser: QS_REPLACED "); 2884 printaddr(sm_debug_file(), a, false); 2885 } 2886 a1->q_alias = a; 2887 allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 2888 (void) recipient(a1, sendq, aliaslevel, e); 2889 } 2890 /* 2891 ** DEQUOTE_INIT -- initialize dequote map 2892 ** 2893 ** Parameters: 2894 ** map -- the internal map structure. 2895 ** args -- arguments. 2896 ** 2897 ** Returns: 2898 ** true. 2899 */ 2900 2901 bool 2902 dequote_init(map, args) 2903 MAP *map; 2904 char *args; 2905 { 2906 register char *p = args; 2907 2908 /* there is no check whether there is really an argument */ 2909 map->map_mflags |= MF_KEEPQUOTES; 2910 for (;;) 2911 { 2912 while (isascii(*p) && isspace(*p)) 2913 p++; 2914 if (*p != '-') 2915 break; 2916 switch (*++p) 2917 { 2918 case 'a': 2919 map->map_app = ++p; 2920 break; 2921 2922 case 'D': 2923 map->map_mflags |= MF_DEFER; 2924 break; 2925 2926 case 'S': 2927 case 's': 2928 map->map_spacesub = *++p; 2929 break; 2930 } 2931 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2932 p++; 2933 if (*p != '\0') 2934 *p = '\0'; 2935 } 2936 if (map->map_app != NULL) 2937 map->map_app = newstr(map->map_app); 2938 2939 return true; 2940 } 2941 /* 2942 ** DEQUOTE_MAP -- unquote an address 2943 ** 2944 ** Parameters: 2945 ** map -- the internal map structure (ignored). 2946 ** name -- the name to dequote. 2947 ** av -- arguments (ignored). 2948 ** statp -- pointer to status out-parameter. 2949 ** 2950 ** Returns: 2951 ** NULL -- if there were no quotes, or if the resulting 2952 ** unquoted buffer would not be acceptable to prescan. 2953 ** else -- The dequoted buffer. 2954 */ 2955 2956 /* ARGSUSED2 */ 2957 char * 2958 dequote_map(map, name, av, statp) 2959 MAP *map; 2960 char *name; 2961 char **av; 2962 int *statp; 2963 { 2964 register char *p; 2965 register char *q; 2966 register char c; 2967 int anglecnt = 0; 2968 int cmntcnt = 0; 2969 int quotecnt = 0; 2970 int spacecnt = 0; 2971 bool quotemode = false; 2972 bool bslashmode = false; 2973 char spacesub = map->map_spacesub; 2974 2975 for (p = q = name; (c = *p++) != '\0'; ) 2976 { 2977 if (bslashmode) 2978 { 2979 bslashmode = false; 2980 *q++ = c; 2981 continue; 2982 } 2983 2984 if (c == ' ' && spacesub != '\0') 2985 c = spacesub; 2986 2987 switch (c) 2988 { 2989 case '\\': 2990 bslashmode = true; 2991 break; 2992 2993 case '(': 2994 cmntcnt++; 2995 break; 2996 2997 case ')': 2998 if (cmntcnt-- <= 0) 2999 return NULL; 3000 break; 3001 3002 case ' ': 3003 case '\t': 3004 spacecnt++; 3005 break; 3006 } 3007 3008 if (cmntcnt > 0) 3009 { 3010 *q++ = c; 3011 continue; 3012 } 3013 3014 switch (c) 3015 { 3016 case '"': 3017 quotemode = !quotemode; 3018 quotecnt++; 3019 continue; 3020 3021 case '<': 3022 anglecnt++; 3023 break; 3024 3025 case '>': 3026 if (anglecnt-- <= 0) 3027 return NULL; 3028 break; 3029 } 3030 *q++ = c; 3031 } 3032 3033 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 3034 quotemode || quotecnt <= 0 || spacecnt != 0) 3035 return NULL; 3036 *q++ = '\0'; 3037 return map_rewrite(map, name, strlen(name), NULL); 3038 } 3039 /* 3040 ** RSCHECK -- check string(s) for validity using rewriting sets 3041 ** 3042 ** Parameters: 3043 ** rwset -- the rewriting set to use. 3044 ** p1 -- the first string to check. 3045 ** p2 -- the second string to check -- may be null. 3046 ** e -- the current envelope. 3047 ** flags -- control some behavior, see RSF_ in sendmail.h 3048 ** logl -- logging level. 3049 ** host -- NULL or relay host. 3050 ** logid -- id for sm_syslog. 3051 ** addr -- if not NULL and ruleset returns $#error: 3052 ** store mailer triple here. 3053 ** 3054 ** Returns: 3055 ** EX_OK -- if the rwset doesn't resolve to $#error 3056 ** else -- the failure status (message printed) 3057 */ 3058 3059 int 3060 rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr) 3061 char *rwset; 3062 char *p1; 3063 char *p2; 3064 ENVELOPE *e; 3065 int flags; 3066 int logl; 3067 char *host; 3068 char *logid; 3069 ADDRESS *addr; 3070 { 3071 char *volatile buf; 3072 size_t bufsize; 3073 int saveexitstat; 3074 int volatile rstat = EX_OK; 3075 char **pvp; 3076 int rsno; 3077 bool volatile discard = false; 3078 bool saveQuickAbort = QuickAbort; 3079 bool saveSuprErrs = SuprErrs; 3080 bool quarantine = false; 3081 char ubuf[BUFSIZ * 2]; 3082 char buf0[MAXLINE]; 3083 char pvpbuf[PSBUFSIZE]; 3084 extern char MsgBuf[]; 3085 3086 if (tTd(48, 2)) 3087 sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 3088 p2 == NULL ? "(NULL)" : p2); 3089 3090 rsno = strtorwset(rwset, NULL, ST_FIND); 3091 if (rsno < 0) 3092 return EX_OK; 3093 3094 if (p2 != NULL) 3095 { 3096 bufsize = strlen(p1) + strlen(p2) + 2; 3097 if (bufsize > sizeof(buf0)) 3098 buf = sm_malloc_x(bufsize); 3099 else 3100 { 3101 buf = buf0; 3102 bufsize = sizeof(buf0); 3103 } 3104 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 3105 } 3106 else 3107 { 3108 bufsize = strlen(p1) + 1; 3109 if (bufsize > sizeof(buf0)) 3110 buf = sm_malloc_x(bufsize); 3111 else 3112 { 3113 buf = buf0; 3114 bufsize = sizeof(buf0); 3115 } 3116 (void) sm_strlcpy(buf, p1, bufsize); 3117 } 3118 SM_TRY 3119 { 3120 SuprErrs = true; 3121 QuickAbort = false; 3122 pvp = prescan(buf, '\0', pvpbuf, sizeof(pvpbuf), NULL, 3123 bitset(RSF_RMCOMM, flags) ? 3124 IntTokenTab : TokTypeNoC, 3125 bitset(RSF_RMCOMM, flags) ? false : true); 3126 SuprErrs = saveSuprErrs; 3127 if (pvp == NULL) 3128 { 3129 if (tTd(48, 2)) 3130 sm_dprintf("rscheck: cannot prescan input\n"); 3131 /* 3132 syserr("rscheck: cannot prescan input: \"%s\"", 3133 shortenstring(buf, MAXSHORTSTR)); 3134 rstat = EX_DATAERR; 3135 */ 3136 goto finis; 3137 } 3138 if (bitset(RSF_UNSTRUCTURED, flags)) 3139 SuprErrs = true; 3140 (void) REWRITE(pvp, rsno, e); 3141 if (bitset(RSF_UNSTRUCTURED, flags)) 3142 SuprErrs = saveSuprErrs; 3143 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 3144 pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 3145 strcmp(pvp[1], "discard") != 0)) 3146 { 3147 goto finis; 3148 } 3149 3150 if (strcmp(pvp[1], "discard") == 0) 3151 { 3152 if (tTd(48, 2)) 3153 sm_dprintf("rscheck: discard mailer selected\n"); 3154 e->e_flags |= EF_DISCARD; 3155 discard = true; 3156 } 3157 else if (strcmp(pvp[1], "error") == 0 && 3158 pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 3159 pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 3160 { 3161 if (pvp[4] == NULL || 3162 (pvp[4][0] & 0377) != CANONUSER || 3163 pvp[5] == NULL) 3164 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 3165 rwset); 3166 else 3167 { 3168 cataddr(&(pvp[5]), NULL, ubuf, 3169 sizeof(ubuf), ' ', true); 3170 e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 3171 ubuf); 3172 } 3173 macdefine(&e->e_macro, A_PERM, 3174 macid("{quarantine}"), e->e_quarmsg); 3175 quarantine = true; 3176 } 3177 else 3178 { 3179 auto ADDRESS a1; 3180 int savelogusrerrs = LogUsrErrs; 3181 static bool logged = false; 3182 3183 /* got an error -- process it */ 3184 saveexitstat = ExitStat; 3185 LogUsrErrs = false; 3186 (void) buildaddr(pvp, &a1, 0, e); 3187 if (addr != NULL) 3188 { 3189 addr->q_mailer = a1.q_mailer; 3190 addr->q_user = a1.q_user; 3191 addr->q_host = a1.q_host; 3192 } 3193 LogUsrErrs = savelogusrerrs; 3194 rstat = ExitStat; 3195 ExitStat = saveexitstat; 3196 if (!logged) 3197 { 3198 if (bitset(RSF_COUNT, flags)) 3199 markstats(e, &a1, STATS_REJECT); 3200 logged = true; 3201 } 3202 } 3203 3204 if (LogLevel > logl) 3205 { 3206 char *relay; 3207 char *p; 3208 char lbuf[MAXLINE]; 3209 3210 p = lbuf; 3211 if (p2 != NULL) 3212 { 3213 (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3214 ", arg2=%s", 3215 p2); 3216 p += strlen(p); 3217 } 3218 3219 if (host != NULL) 3220 relay = host; 3221 else 3222 relay = macvalue('_', e); 3223 if (relay != NULL) 3224 { 3225 (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3226 ", relay=%s", relay); 3227 p += strlen(p); 3228 } 3229 *p = '\0'; 3230 if (discard) 3231 sm_syslog(LOG_NOTICE, logid, 3232 "ruleset=%s, arg1=%s%s, discard", 3233 rwset, p1, lbuf); 3234 else if (quarantine) 3235 sm_syslog(LOG_NOTICE, logid, 3236 "ruleset=%s, arg1=%s%s, quarantine=%s", 3237 rwset, p1, lbuf, ubuf); 3238 else 3239 sm_syslog(LOG_NOTICE, logid, 3240 "ruleset=%s, arg1=%s%s, reject=%s", 3241 rwset, p1, lbuf, MsgBuf); 3242 } 3243 3244 finis: ; 3245 } 3246 SM_FINALLY 3247 { 3248 /* clean up */ 3249 if (buf != buf0) 3250 sm_free(buf); 3251 QuickAbort = saveQuickAbort; 3252 } 3253 SM_END_TRY 3254 3255 setstat(rstat); 3256 3257 /* rulesets don't set errno */ 3258 errno = 0; 3259 if (rstat != EX_OK && QuickAbort) 3260 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 3261 return rstat; 3262 } 3263 /* 3264 ** RSCAP -- call rewriting set to return capabilities 3265 ** 3266 ** Parameters: 3267 ** rwset -- the rewriting set to use. 3268 ** p1 -- the first string to check. 3269 ** p2 -- the second string to check -- may be null. 3270 ** e -- the current envelope. 3271 ** pvp -- pointer to token vector. 3272 ** pvpbuf -- buffer space. 3273 ** size -- size of buffer space. 3274 ** 3275 ** Returns: 3276 ** EX_UNAVAILABLE -- ruleset doesn't exist. 3277 ** EX_DATAERR -- prescan() failed. 3278 ** EX_OK -- rewrite() was successful. 3279 ** else -- return status from rewrite(). 3280 */ 3281 3282 int 3283 rscap(rwset, p1, p2, e, pvp, pvpbuf, size) 3284 char *rwset; 3285 char *p1; 3286 char *p2; 3287 ENVELOPE *e; 3288 char ***pvp; 3289 char *pvpbuf; 3290 int size; 3291 { 3292 char *volatile buf; 3293 size_t bufsize; 3294 int volatile rstat = EX_OK; 3295 int rsno; 3296 bool saveQuickAbort = QuickAbort; 3297 bool saveSuprErrs = SuprErrs; 3298 char buf0[MAXLINE]; 3299 extern char MsgBuf[]; 3300 3301 if (tTd(48, 2)) 3302 sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 3303 p2 == NULL ? "(NULL)" : p2); 3304 3305 SM_REQUIRE(pvp != NULL); 3306 rsno = strtorwset(rwset, NULL, ST_FIND); 3307 if (rsno < 0) 3308 return EX_UNAVAILABLE; 3309 3310 if (p2 != NULL) 3311 { 3312 bufsize = strlen(p1) + strlen(p2) + 2; 3313 if (bufsize > sizeof(buf0)) 3314 buf = sm_malloc_x(bufsize); 3315 else 3316 { 3317 buf = buf0; 3318 bufsize = sizeof(buf0); 3319 } 3320 (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 3321 } 3322 else 3323 { 3324 bufsize = strlen(p1) + 1; 3325 if (bufsize > sizeof(buf0)) 3326 buf = sm_malloc_x(bufsize); 3327 else 3328 { 3329 buf = buf0; 3330 bufsize = sizeof(buf0); 3331 } 3332 (void) sm_strlcpy(buf, p1, bufsize); 3333 } 3334 SM_TRY 3335 { 3336 SuprErrs = true; 3337 QuickAbort = false; 3338 *pvp = prescan(buf, '\0', pvpbuf, size, NULL, IntTokenTab, 3339 false); 3340 if (*pvp != NULL) 3341 rstat = rewrite(*pvp, rsno, 0, e, size); 3342 else 3343 { 3344 if (tTd(48, 2)) 3345 sm_dprintf("rscap: cannot prescan input\n"); 3346 rstat = EX_DATAERR; 3347 } 3348 } 3349 SM_FINALLY 3350 { 3351 /* clean up */ 3352 if (buf != buf0) 3353 sm_free(buf); 3354 SuprErrs = saveSuprErrs; 3355 QuickAbort = saveQuickAbort; 3356 3357 /* prevent information leak, this may contain rewrite error */ 3358 MsgBuf[0] = '\0'; 3359 } 3360 SM_END_TRY 3361 return rstat; 3362 } 3363