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