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