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