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