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