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