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