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.12 2001/05/03 17:24:11 gshapiro 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 #define MAXMATCH 9 /* max params per rewrite */ 771 772 773 int 774 rewrite(pvp, ruleset, reclevel, e) 775 char **pvp; 776 int ruleset; 777 int reclevel; 778 register ENVELOPE *e; 779 { 780 register char *ap; /* address pointer */ 781 register char *rp; /* rewrite pointer */ 782 register char *rulename; /* ruleset name */ 783 register char *prefix; 784 register char **avp; /* address vector pointer */ 785 register char **rvp; /* rewrite vector pointer */ 786 register struct match *mlp; /* cur ptr into mlist */ 787 register struct rewrite *rwr; /* pointer to current rewrite rule */ 788 int ruleno; /* current rule number */ 789 int rstat = EX_OK; /* return status */ 790 int loopcount; 791 struct match mlist[MAXMATCH]; /* stores match on LHS */ 792 char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 793 char buf[MAXLINE]; 794 char name[6]; 795 796 if (ruleset < 0 || ruleset >= MAXRWSETS) 797 { 798 syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 799 return EX_CONFIG; 800 } 801 rulename = RuleSetNames[ruleset]; 802 if (rulename == NULL) 803 { 804 snprintf(name, sizeof name, "%d", ruleset); 805 rulename = name; 806 } 807 if (OpMode == MD_TEST) 808 prefix = ""; 809 else 810 prefix = "rewrite: ruleset "; 811 if (OpMode == MD_TEST) 812 { 813 printf("%s%-16.16s input:", prefix, rulename); 814 printav(pvp); 815 } 816 else if (tTd(21, 1)) 817 { 818 dprintf("%s%-16.16s input:", prefix, rulename); 819 printav(pvp); 820 } 821 if (reclevel++ > MaxRuleRecursion) 822 { 823 syserr("rewrite: excessive recursion (max %d), ruleset %s", 824 MaxRuleRecursion, rulename); 825 return EX_CONFIG; 826 } 827 if (pvp == NULL) 828 return EX_USAGE; 829 830 /* 831 ** Run through the list of rewrite rules, applying 832 ** any that match. 833 */ 834 835 ruleno = 1; 836 loopcount = 0; 837 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 838 { 839 int status; 840 841 /* if already canonical, quit now */ 842 if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 843 break; 844 845 if (tTd(21, 12)) 846 { 847 if (tTd(21, 15)) 848 dprintf("-----trying rule (line %d):", 849 rwr->r_line); 850 else 851 dprintf("-----trying rule:"); 852 printav(rwr->r_lhs); 853 } 854 855 /* try to match on this rule */ 856 mlp = mlist; 857 rvp = rwr->r_lhs; 858 avp = pvp; 859 if (++loopcount > 100) 860 { 861 syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 862 rulename, ruleno); 863 if (tTd(21, 1)) 864 { 865 dprintf("workspace: "); 866 printav(pvp); 867 } 868 break; 869 } 870 871 while ((ap = *avp) != NULL || *rvp != NULL) 872 { 873 rp = *rvp; 874 if (tTd(21, 35)) 875 { 876 dprintf("ADVANCE rp="); 877 xputs(rp); 878 dprintf(", ap="); 879 xputs(ap); 880 dprintf("\n"); 881 } 882 if (rp == NULL) 883 { 884 /* end-of-pattern before end-of-address */ 885 goto backup; 886 } 887 if (ap == NULL && (*rp & 0377) != MATCHZANY && 888 (*rp & 0377) != MATCHZERO) 889 { 890 /* end-of-input with patterns left */ 891 goto backup; 892 } 893 894 switch (*rp & 0377) 895 { 896 case MATCHCLASS: 897 /* match any phrase in a class */ 898 mlp->match_pattern = rvp; 899 mlp->match_first = avp; 900 extendclass: 901 ap = *avp; 902 if (ap == NULL) 903 goto backup; 904 mlp->match_last = avp++; 905 cataddr(mlp->match_first, mlp->match_last, 906 buf, sizeof buf, '\0'); 907 if (!wordinclass(buf, rp[1])) 908 { 909 if (tTd(21, 36)) 910 { 911 dprintf("EXTEND rp="); 912 xputs(rp); 913 dprintf(", ap="); 914 xputs(ap); 915 dprintf("\n"); 916 } 917 goto extendclass; 918 } 919 if (tTd(21, 36)) 920 dprintf("CLMATCH\n"); 921 mlp++; 922 break; 923 924 case MATCHNCLASS: 925 /* match any token not in a class */ 926 if (wordinclass(ap, rp[1])) 927 goto backup; 928 929 /* FALLTHROUGH */ 930 931 case MATCHONE: 932 case MATCHANY: 933 /* match exactly one token */ 934 mlp->match_pattern = rvp; 935 mlp->match_first = avp; 936 mlp->match_last = avp++; 937 mlp++; 938 break; 939 940 case MATCHZANY: 941 /* match zero or more tokens */ 942 mlp->match_pattern = rvp; 943 mlp->match_first = avp; 944 mlp->match_last = avp - 1; 945 mlp++; 946 break; 947 948 case MATCHZERO: 949 /* match zero tokens */ 950 break; 951 952 case MACRODEXPAND: 953 /* 954 ** Match against run-time macro. 955 ** This algorithm is broken for the 956 ** general case (no recursive macros, 957 ** improper tokenization) but should 958 ** work for the usual cases. 959 */ 960 961 ap = macvalue(rp[1], e); 962 mlp->match_first = avp; 963 if (tTd(21, 2)) 964 dprintf("rewrite: LHS $&%s => \"%s\"\n", 965 macname(rp[1]), 966 ap == NULL ? "(NULL)" : ap); 967 968 if (ap == NULL) 969 break; 970 while (*ap != '\0') 971 { 972 if (*avp == NULL || 973 strncasecmp(ap, *avp, strlen(*avp)) != 0) 974 { 975 /* no match */ 976 avp = mlp->match_first; 977 goto backup; 978 } 979 ap += strlen(*avp++); 980 } 981 982 /* match */ 983 break; 984 985 default: 986 /* must have exact match */ 987 if (sm_strcasecmp(rp, ap)) 988 goto backup; 989 avp++; 990 break; 991 } 992 993 /* successful match on this token */ 994 rvp++; 995 continue; 996 997 backup: 998 /* match failed -- back up */ 999 while (--mlp >= mlist) 1000 { 1001 rvp = mlp->match_pattern; 1002 rp = *rvp; 1003 avp = mlp->match_last + 1; 1004 ap = *avp; 1005 1006 if (tTd(21, 36)) 1007 { 1008 dprintf("BACKUP rp="); 1009 xputs(rp); 1010 dprintf(", ap="); 1011 xputs(ap); 1012 dprintf("\n"); 1013 } 1014 1015 if (ap == NULL) 1016 { 1017 /* run off the end -- back up again */ 1018 continue; 1019 } 1020 if ((*rp & 0377) == MATCHANY || 1021 (*rp & 0377) == MATCHZANY) 1022 { 1023 /* extend binding and continue */ 1024 mlp->match_last = avp++; 1025 rvp++; 1026 mlp++; 1027 break; 1028 } 1029 if ((*rp & 0377) == MATCHCLASS) 1030 { 1031 /* extend binding and try again */ 1032 mlp->match_last = avp; 1033 goto extendclass; 1034 } 1035 } 1036 1037 if (mlp < mlist) 1038 { 1039 /* total failure to match */ 1040 break; 1041 } 1042 } 1043 1044 /* 1045 ** See if we successfully matched 1046 */ 1047 1048 if (mlp < mlist || *rvp != NULL) 1049 { 1050 if (tTd(21, 10)) 1051 dprintf("----- rule fails\n"); 1052 rwr = rwr->r_next; 1053 ruleno++; 1054 loopcount = 0; 1055 continue; 1056 } 1057 1058 rvp = rwr->r_rhs; 1059 if (tTd(21, 12)) 1060 { 1061 dprintf("-----rule matches:"); 1062 printav(rvp); 1063 } 1064 1065 rp = *rvp; 1066 if (rp != NULL) 1067 { 1068 if ((*rp & 0377) == CANONUSER) 1069 { 1070 rvp++; 1071 rwr = rwr->r_next; 1072 ruleno++; 1073 loopcount = 0; 1074 } 1075 else if ((*rp & 0377) == CANONHOST) 1076 { 1077 rvp++; 1078 rwr = NULL; 1079 } 1080 } 1081 1082 /* substitute */ 1083 for (avp = npvp; *rvp != NULL; rvp++) 1084 { 1085 register struct match *m; 1086 register char **pp; 1087 1088 rp = *rvp; 1089 if ((*rp & 0377) == MATCHREPL) 1090 { 1091 /* substitute from LHS */ 1092 m = &mlist[rp[1] - '1']; 1093 if (m < mlist || m >= mlp) 1094 { 1095 syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 1096 rulename, rp[1]); 1097 return EX_CONFIG; 1098 } 1099 if (tTd(21, 15)) 1100 { 1101 dprintf("$%c:", rp[1]); 1102 pp = m->match_first; 1103 while (pp <= m->match_last) 1104 { 1105 dprintf(" %lx=\"", 1106 (u_long) *pp); 1107 (void) dflush(); 1108 dprintf("%s\"", *pp++); 1109 } 1110 dprintf("\n"); 1111 } 1112 pp = m->match_first; 1113 while (pp <= m->match_last) 1114 { 1115 if (avp >= &npvp[MAXATOM]) 1116 { 1117 syserr("554 5.3.0 rewrite: expansion too long"); 1118 return EX_DATAERR; 1119 } 1120 *avp++ = *pp++; 1121 } 1122 } 1123 else 1124 { 1125 /* some sort of replacement */ 1126 if (avp >= &npvp[MAXATOM]) 1127 { 1128 toolong: 1129 syserr("554 5.3.0 rewrite: expansion too long"); 1130 return EX_DATAERR; 1131 } 1132 if ((*rp & 0377) != MACRODEXPAND) 1133 { 1134 /* vanilla replacement */ 1135 *avp++ = rp; 1136 } 1137 else 1138 { 1139 /* $&x replacement */ 1140 char *mval = macvalue(rp[1], e); 1141 char **xpvp; 1142 int trsize = 0; 1143 static size_t pvpb1_size = 0; 1144 static char **pvpb1 = NULL; 1145 char pvpbuf[PSBUFSIZE]; 1146 1147 if (tTd(21, 2)) 1148 dprintf("rewrite: RHS $&%s => \"%s\"\n", 1149 macname(rp[1]), 1150 mval == NULL ? "(NULL)" : mval); 1151 if (mval == NULL || *mval == '\0') 1152 continue; 1153 1154 /* save the remainder of the input */ 1155 for (xpvp = pvp; *xpvp != NULL; xpvp++) 1156 trsize += sizeof *xpvp; 1157 if ((size_t) trsize > pvpb1_size) 1158 { 1159 if (pvpb1 != NULL) 1160 sm_free(pvpb1); 1161 pvpb1 = (char **)xalloc(trsize); 1162 pvpb1_size = trsize; 1163 } 1164 1165 memmove((char *) pvpb1, 1166 (char *) pvp, 1167 trsize); 1168 1169 /* scan the new replacement */ 1170 xpvp = prescan(mval, '\0', pvpbuf, 1171 sizeof pvpbuf, NULL, 1172 NULL); 1173 if (xpvp == NULL) 1174 { 1175 /* prescan pre-printed error */ 1176 return EX_DATAERR; 1177 } 1178 1179 /* insert it into the output stream */ 1180 while (*xpvp != NULL) 1181 { 1182 if (tTd(21, 19)) 1183 dprintf(" ... %s\n", 1184 *xpvp); 1185 *avp++ = newstr(*xpvp); 1186 if (avp >= &npvp[MAXATOM]) 1187 goto toolong; 1188 xpvp++; 1189 } 1190 if (tTd(21, 19)) 1191 dprintf(" ... DONE\n"); 1192 1193 /* restore the old trailing input */ 1194 memmove((char *) pvp, 1195 (char *) pvpb1, 1196 trsize); 1197 } 1198 } 1199 } 1200 *avp++ = NULL; 1201 1202 /* 1203 ** Check for any hostname/keyword lookups. 1204 */ 1205 1206 for (rvp = npvp; *rvp != NULL; rvp++) 1207 { 1208 char **hbrvp; 1209 char **xpvp; 1210 int trsize; 1211 char *replac; 1212 int endtoken; 1213 STAB *map; 1214 char *mapname; 1215 char **key_rvp; 1216 char **arg_rvp; 1217 char **default_rvp; 1218 char cbuf[MAXNAME + 1]; 1219 char *pvpb1[MAXATOM + 1]; 1220 char *argvect[10]; 1221 char pvpbuf[PSBUFSIZE]; 1222 char *nullpvp[1]; 1223 1224 if ((**rvp & 0377) != HOSTBEGIN && 1225 (**rvp & 0377) != LOOKUPBEGIN) 1226 continue; 1227 1228 /* 1229 ** Got a hostname/keyword lookup. 1230 ** 1231 ** This could be optimized fairly easily. 1232 */ 1233 1234 hbrvp = rvp; 1235 if ((**rvp & 0377) == HOSTBEGIN) 1236 { 1237 endtoken = HOSTEND; 1238 mapname = "host"; 1239 } 1240 else 1241 { 1242 endtoken = LOOKUPEND; 1243 mapname = *++rvp; 1244 } 1245 map = stab(mapname, ST_MAP, ST_FIND); 1246 if (map == NULL) 1247 syserr("554 5.3.0 rewrite: map %s not found", mapname); 1248 1249 /* extract the match part */ 1250 key_rvp = ++rvp; 1251 default_rvp = NULL; 1252 arg_rvp = argvect; 1253 xpvp = NULL; 1254 replac = pvpbuf; 1255 while (*rvp != NULL && (**rvp & 0377) != endtoken) 1256 { 1257 int nodetype = **rvp & 0377; 1258 1259 if (nodetype != CANONHOST && nodetype != CANONUSER) 1260 { 1261 rvp++; 1262 continue; 1263 } 1264 1265 *rvp++ = NULL; 1266 1267 if (xpvp != NULL) 1268 { 1269 cataddr(xpvp, NULL, replac, 1270 &pvpbuf[sizeof pvpbuf] - replac, 1271 '\0'); 1272 *++arg_rvp = replac; 1273 replac += strlen(replac) + 1; 1274 xpvp = NULL; 1275 } 1276 switch (nodetype) 1277 { 1278 case CANONHOST: 1279 xpvp = rvp; 1280 break; 1281 1282 case CANONUSER: 1283 default_rvp = rvp; 1284 break; 1285 } 1286 } 1287 if (*rvp != NULL) 1288 *rvp++ = NULL; 1289 if (xpvp != NULL) 1290 { 1291 cataddr(xpvp, NULL, replac, 1292 &pvpbuf[sizeof pvpbuf] - replac, 1293 '\0'); 1294 *++arg_rvp = replac; 1295 } 1296 *++arg_rvp = NULL; 1297 1298 /* save the remainder of the input string */ 1299 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1300 memmove((char *) pvpb1, (char *) rvp, trsize); 1301 1302 /* look it up */ 1303 cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 1304 map == NULL ? '\0' : map->s_map.map_spacesub); 1305 argvect[0] = cbuf; 1306 replac = map_lookup(map, cbuf, argvect, &rstat, e); 1307 1308 /* if no replacement, use default */ 1309 if (replac == NULL && default_rvp != NULL) 1310 { 1311 /* create the default */ 1312 cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0'); 1313 replac = cbuf; 1314 } 1315 1316 if (replac == NULL) 1317 { 1318 xpvp = key_rvp; 1319 } 1320 else if (*replac == '\0') 1321 { 1322 /* null replacement */ 1323 nullpvp[0] = NULL; 1324 xpvp = nullpvp; 1325 } 1326 else 1327 { 1328 /* scan the new replacement */ 1329 xpvp = prescan(replac, '\0', pvpbuf, 1330 sizeof pvpbuf, NULL, NULL); 1331 if (xpvp == NULL) 1332 { 1333 /* prescan already printed error */ 1334 return EX_DATAERR; 1335 } 1336 } 1337 1338 /* append it to the token list */ 1339 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1340 { 1341 *avp++ = newstr(*xpvp); 1342 if (avp >= &npvp[MAXATOM]) 1343 goto toolong; 1344 } 1345 1346 /* restore the old trailing information */ 1347 rvp = avp - 1; 1348 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1349 if (avp >= &npvp[MAXATOM]) 1350 goto toolong; 1351 } 1352 1353 /* 1354 ** Check for subroutine calls. 1355 */ 1356 1357 status = callsubr(npvp, reclevel, e); 1358 if (rstat == EX_OK || status == EX_TEMPFAIL) 1359 rstat = status; 1360 1361 /* copy vector back into original space. */ 1362 for (avp = npvp; *avp++ != NULL;) 1363 continue; 1364 memmove((char *) pvp, (char *) npvp, 1365 (int) (avp - npvp) * sizeof *avp); 1366 1367 if (tTd(21, 4)) 1368 { 1369 dprintf("rewritten as:"); 1370 printav(pvp); 1371 } 1372 } 1373 1374 if (OpMode == MD_TEST) 1375 { 1376 printf("%s%-16.16s returns:", prefix, rulename); 1377 printav(pvp); 1378 } 1379 else if (tTd(21, 1)) 1380 { 1381 dprintf("%s%-16.16s returns:", prefix, rulename); 1382 printav(pvp); 1383 } 1384 return rstat; 1385 } 1386 /* 1387 ** CALLSUBR -- call subroutines in rewrite vector 1388 ** 1389 ** Parameters: 1390 ** pvp -- pointer to token vector. 1391 ** reclevel -- the current recursion level. 1392 ** e -- the current envelope. 1393 ** 1394 ** Returns: 1395 ** The status from the subroutine call. 1396 ** 1397 ** Side Effects: 1398 ** pvp is modified. 1399 */ 1400 1401 static int 1402 callsubr(pvp, reclevel, e) 1403 char **pvp; 1404 int reclevel; 1405 ENVELOPE *e; 1406 { 1407 char **avp; 1408 char **rvp; 1409 register int i; 1410 int subr; 1411 int status; 1412 int rstat = EX_OK; 1413 char *tpvp[MAXATOM + 1]; 1414 1415 for (avp = pvp; *avp != NULL; avp++) 1416 { 1417 if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 1418 { 1419 stripquotes(avp[1]); 1420 subr = strtorwset(avp[1], NULL, ST_FIND); 1421 if (subr < 0) 1422 { 1423 syserr("Unknown ruleset %s", avp[1]); 1424 return EX_CONFIG; 1425 } 1426 1427 if (tTd(21, 3)) 1428 dprintf("-----callsubr %s (%d)\n", 1429 avp[1], subr); 1430 1431 /* 1432 ** Take care of possible inner calls first. 1433 ** use a full size temporary buffer to avoid 1434 ** overflows in rewrite, but strip off the 1435 ** subroutine call. 1436 */ 1437 1438 for (i = 2; avp[i] != NULL; i++) 1439 tpvp[i - 2] = avp[i]; 1440 tpvp[i - 2] = NULL; 1441 1442 status = callsubr(tpvp, reclevel, e); 1443 if (rstat == EX_OK || status == EX_TEMPFAIL) 1444 rstat = status; 1445 1446 /* 1447 ** Now we need to call the ruleset specified for 1448 ** the subroutine. we can do this with the 1449 ** temporary buffer that we set up earlier, 1450 ** since it has all the data we want to rewrite. 1451 */ 1452 1453 status = rewrite(tpvp, subr, reclevel, e); 1454 if (rstat == EX_OK || status == EX_TEMPFAIL) 1455 rstat = status; 1456 1457 /* 1458 ** Find length of tpvp and current offset into 1459 ** pvp, if the total is greater than MAXATOM, 1460 ** then it would overflow the buffer if we copied 1461 ** it back in to pvp, in which case we throw a 1462 ** fit. 1463 */ 1464 1465 for (rvp = tpvp; *rvp != NULL; rvp++) 1466 continue; 1467 if (((rvp - tpvp) + (avp - pvp)) > MAXATOM) 1468 { 1469 syserr("554 5.3.0 callsubr: expansion too long"); 1470 return EX_DATAERR; 1471 } 1472 1473 /* 1474 ** Now we can copy the rewritten code over 1475 ** the initial subroutine call in the buffer. 1476 */ 1477 1478 for (i = 0; tpvp[i] != NULL; i++) 1479 avp[i] = tpvp[i]; 1480 avp[i] = NULL; 1481 1482 /* 1483 ** If we got this far, we've processed the left 1484 ** most subroutine, and recursively called ourselves 1485 ** to handle any other subroutines. We're done. 1486 */ 1487 1488 break; 1489 } 1490 } 1491 return rstat; 1492 } 1493 /* 1494 ** MAP_LOOKUP -- do lookup in map 1495 ** 1496 ** Parameters: 1497 ** map -- the map to use for the lookup. 1498 ** key -- the key to look up. 1499 ** argvect -- arguments to pass to the map lookup. 1500 ** pstat -- a pointer to an integer in which to store the 1501 ** status from the lookup. 1502 ** e -- the current envelope. 1503 ** 1504 ** Returns: 1505 ** The result of the lookup. 1506 ** NULL -- if there was no data for the given key. 1507 */ 1508 1509 static char * 1510 map_lookup(smap, key, argvect, pstat, e) 1511 STAB *smap; 1512 char key[]; 1513 char **argvect; 1514 int *pstat; 1515 ENVELOPE *e; 1516 { 1517 auto int status = EX_OK; 1518 MAP *map; 1519 char *replac; 1520 1521 if (smap == NULL) 1522 return NULL; 1523 1524 map = &smap->s_map; 1525 DYNOPENMAP(map); 1526 1527 if (e->e_sendmode == SM_DEFER && 1528 bitset(MF_DEFER, map->map_mflags)) 1529 { 1530 /* don't do any map lookups */ 1531 if (tTd(60, 1)) 1532 dprintf("map_lookup(%s, %s) => DEFERRED\n", 1533 smap->s_name, key); 1534 *pstat = EX_TEMPFAIL; 1535 return NULL; 1536 } 1537 1538 if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1539 stripquotes(key); 1540 1541 if (tTd(60, 1)) 1542 { 1543 dprintf("map_lookup(%s, %s", smap->s_name, key); 1544 if (tTd(60, 5)) 1545 { 1546 int i; 1547 1548 for (i = 0; argvect[i] != NULL; i++) 1549 dprintf(", %%%d=%s", i, argvect[i]); 1550 } 1551 dprintf(") => "); 1552 } 1553 replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1554 if (tTd(60, 1)) 1555 dprintf("%s (%d)\n", 1556 replac != NULL ? replac : "NOT FOUND", 1557 status); 1558 1559 /* should recover if status == EX_TEMPFAIL */ 1560 if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1561 { 1562 *pstat = EX_TEMPFAIL; 1563 if (tTd(60, 1)) 1564 dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 1565 smap->s_name, key, errno); 1566 if (e->e_message == NULL) 1567 { 1568 char mbuf[320]; 1569 1570 snprintf(mbuf, sizeof mbuf, 1571 "%.80s map: lookup (%s): deferred", 1572 smap->s_name, 1573 shortenstring(key, MAXSHORTSTR)); 1574 e->e_message = newstr(mbuf); 1575 } 1576 } 1577 if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1578 { 1579 size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1580 static char *rwbuf = NULL; 1581 static size_t rwbuflen = 0; 1582 1583 if (i > rwbuflen) 1584 { 1585 if (rwbuf != NULL) 1586 sm_free(rwbuf); 1587 rwbuflen = i; 1588 rwbuf = (char *) xalloc(rwbuflen); 1589 } 1590 snprintf(rwbuf, rwbuflen, "%s%s", key, map->map_tapp); 1591 if (tTd(60, 4)) 1592 dprintf("map_lookup tempfail: returning \"%s\"\n", 1593 rwbuf); 1594 return rwbuf; 1595 } 1596 return replac; 1597 } 1598 /* 1599 ** INITERRMAILERS -- initialize error and discard mailers 1600 ** 1601 ** Parameters: 1602 ** none. 1603 ** 1604 ** Returns: 1605 ** none. 1606 ** 1607 ** Side Effects: 1608 ** initializes error and discard mailers. 1609 */ 1610 1611 static MAILER discardmailer; 1612 static MAILER errormailer; 1613 static char *discardargv[] = { "DISCARD", NULL }; 1614 static char *errorargv[] = { "ERROR", NULL }; 1615 1616 void 1617 initerrmailers() 1618 { 1619 if (discardmailer.m_name == NULL) 1620 { 1621 /* initialize the discard mailer */ 1622 discardmailer.m_name = "*discard*"; 1623 discardmailer.m_mailer = "DISCARD"; 1624 discardmailer.m_argv = discardargv; 1625 } 1626 if (errormailer.m_name == NULL) 1627 { 1628 /* initialize the bogus mailer */ 1629 errormailer.m_name = "*error*"; 1630 errormailer.m_mailer = "ERROR"; 1631 errormailer.m_argv = errorargv; 1632 } 1633 } 1634 /* 1635 ** BUILDADDR -- build address from token vector. 1636 ** 1637 ** Parameters: 1638 ** tv -- token vector. 1639 ** a -- pointer to address descriptor to fill. 1640 ** If NULL, one will be allocated. 1641 ** flags -- info regarding whether this is a sender or 1642 ** a recipient. 1643 ** e -- the current envelope. 1644 ** 1645 ** Returns: 1646 ** NULL if there was an error. 1647 ** 'a' otherwise. 1648 ** 1649 ** Side Effects: 1650 ** fills in 'a' 1651 */ 1652 1653 static struct errcodes 1654 { 1655 char *ec_name; /* name of error code */ 1656 int ec_code; /* numeric code */ 1657 } ErrorCodes[] = 1658 { 1659 { "usage", EX_USAGE }, 1660 { "nouser", EX_NOUSER }, 1661 { "nohost", EX_NOHOST }, 1662 { "unavailable", EX_UNAVAILABLE }, 1663 { "software", EX_SOFTWARE }, 1664 { "tempfail", EX_TEMPFAIL }, 1665 { "protocol", EX_PROTOCOL }, 1666 #ifdef EX_CONFIG 1667 { "config", EX_CONFIG }, 1668 #endif /* EX_CONFIG */ 1669 { NULL, EX_UNAVAILABLE } 1670 }; 1671 1672 1673 static ADDRESS * 1674 buildaddr(tv, a, flags, e) 1675 register char **tv; 1676 register ADDRESS *a; 1677 int flags; 1678 register ENVELOPE *e; 1679 { 1680 struct mailer **mp; 1681 register struct mailer *m; 1682 register char *p; 1683 char *mname; 1684 char **hostp; 1685 char hbuf[MAXNAME + 1]; 1686 static char ubuf[MAXNAME + 2]; 1687 1688 if (tTd(24, 5)) 1689 { 1690 dprintf("buildaddr, flags=%x, tv=", flags); 1691 printav(tv); 1692 } 1693 1694 if (a == NULL) 1695 a = (ADDRESS *) xalloc(sizeof *a); 1696 memset((char *) a, '\0', sizeof *a); 1697 hbuf[0] = '\0'; 1698 1699 /* set up default error return flags */ 1700 a->q_flags |= DefaultNotify; 1701 1702 /* figure out what net/mailer to use */ 1703 if (*tv == NULL || (**tv & 0377) != CANONNET) 1704 { 1705 syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 1706 badaddr: 1707 if (ExitStat == EX_TEMPFAIL) 1708 a->q_state = QS_QUEUEUP; 1709 else 1710 { 1711 a->q_state = QS_BADADDR; 1712 a->q_mailer = &errormailer; 1713 } 1714 return a; 1715 } 1716 mname = *++tv; 1717 1718 /* extract host and user portions */ 1719 if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1720 hostp = ++tv; 1721 else 1722 hostp = NULL; 1723 while (*tv != NULL && (**tv & 0377) != CANONUSER) 1724 tv++; 1725 if (*tv == NULL) 1726 { 1727 syserr("554 5.3.5 buildaddr: no user"); 1728 goto badaddr; 1729 } 1730 if (tv == hostp) 1731 hostp = NULL; 1732 else if (hostp != NULL) 1733 cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1734 cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1735 1736 /* save away the host name */ 1737 if (strcasecmp(mname, "error") == 0) 1738 { 1739 /* Set up triplet for use by -bv */ 1740 a->q_mailer = &errormailer; 1741 a->q_user = newstr(ubuf); 1742 1743 if (hostp != NULL) 1744 { 1745 register struct errcodes *ep; 1746 1747 a->q_host = newstr(hbuf); 1748 if (strchr(hbuf, '.') != NULL) 1749 { 1750 a->q_status = newstr(hbuf); 1751 setstat(dsntoexitstat(hbuf)); 1752 } 1753 else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 1754 { 1755 setstat(atoi(hbuf)); 1756 } 1757 else 1758 { 1759 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1760 if (strcasecmp(ep->ec_name, hbuf) == 0) 1761 break; 1762 setstat(ep->ec_code); 1763 } 1764 } 1765 else 1766 { 1767 a->q_host = NULL; 1768 setstat(EX_UNAVAILABLE); 1769 } 1770 stripquotes(ubuf); 1771 if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 1772 { 1773 char fmt[16]; 1774 int off; 1775 1776 if ((off = isenhsc(ubuf + 4, ' ')) > 0) 1777 { 1778 ubuf[off + 4] = '\0'; 1779 off += 5; 1780 } 1781 else 1782 { 1783 off = 4; 1784 ubuf[3] = '\0'; 1785 } 1786 (void) snprintf(fmt, sizeof fmt, "%s %%s", ubuf); 1787 if (off > 4) 1788 usrerr(fmt, ubuf + off); 1789 else if (isenhsc(hbuf, '\0') > 0) 1790 usrerrenh(hbuf, fmt, ubuf + off); 1791 else 1792 usrerr(fmt, ubuf + off); 1793 /* XXX ubuf[off - 1] = ' '; */ 1794 } 1795 else 1796 { 1797 usrerr("553 5.3.0 %s", ubuf); 1798 } 1799 goto badaddr; 1800 } 1801 1802 for (mp = Mailer; (m = *mp++) != NULL; ) 1803 { 1804 if (strcasecmp(m->m_name, mname) == 0) 1805 break; 1806 } 1807 if (m == NULL) 1808 { 1809 syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 1810 goto badaddr; 1811 } 1812 a->q_mailer = m; 1813 1814 /* figure out what host (if any) */ 1815 if (hostp == NULL) 1816 { 1817 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1818 { 1819 syserr("554 5.3.5 buildaddr: no host"); 1820 goto badaddr; 1821 } 1822 a->q_host = NULL; 1823 } 1824 else 1825 a->q_host = newstr(hbuf); 1826 1827 /* figure out the user */ 1828 p = ubuf; 1829 if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 1830 { 1831 p++; 1832 tv++; 1833 a->q_flags |= QNOTREMOTE; 1834 } 1835 1836 /* do special mapping for local mailer */ 1837 if (*p == '"') 1838 p++; 1839 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 1840 a->q_mailer = m = ProgMailer; 1841 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 1842 a->q_mailer = m = FileMailer; 1843 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 1844 { 1845 /* may be :include: */ 1846 stripquotes(ubuf); 1847 if (strncasecmp(ubuf, ":include:", 9) == 0) 1848 { 1849 /* if :include:, don't need further rewriting */ 1850 a->q_mailer = m = InclMailer; 1851 a->q_user = newstr(&ubuf[9]); 1852 return a; 1853 } 1854 } 1855 1856 /* rewrite according recipient mailer rewriting rules */ 1857 define('h', a->q_host, e); 1858 1859 #if _FFR_ADDR_TYPE 1860 /* 1861 ** Note, change the 9 to a 10 before removing #if FFR check 1862 ** in a future version. 1863 */ 1864 1865 if (ConfigLevel >= 9 || 1866 !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1867 #else /* _FFR_ADDR_TYPE */ 1868 if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1869 #endif /* _FFR_ADDR_TYPE */ 1870 { 1871 /* sender addresses done later */ 1872 (void) rewrite(tv, 2, 0, e); 1873 if (m->m_re_rwset > 0) 1874 (void) rewrite(tv, m->m_re_rwset, 0, e); 1875 } 1876 (void) rewrite(tv, 4, 0, e); 1877 1878 /* save the result for the command line/RCPT argument */ 1879 cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 1880 a->q_user = newstr(ubuf); 1881 1882 /* 1883 ** Do mapping to lower case as requested by mailer 1884 */ 1885 1886 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1887 makelower(a->q_host); 1888 if (!bitnset(M_USR_UPPER, m->m_flags)) 1889 makelower(a->q_user); 1890 1891 if (tTd(24, 6)) 1892 { 1893 dprintf("buildaddr => "); 1894 printaddr(a, FALSE); 1895 } 1896 return a; 1897 } 1898 /* 1899 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1900 ** 1901 ** Parameters: 1902 ** pvp -- parameter vector to rebuild. 1903 ** evp -- last parameter to include. Can be NULL to 1904 ** use entire pvp. 1905 ** buf -- buffer to build the string into. 1906 ** sz -- size of buf. 1907 ** spacesub -- the space separator character; if null, 1908 ** use SpaceSub. 1909 ** 1910 ** Returns: 1911 ** none. 1912 ** 1913 ** Side Effects: 1914 ** Destroys buf. 1915 */ 1916 1917 void 1918 cataddr(pvp, evp, buf, sz, spacesub) 1919 char **pvp; 1920 char **evp; 1921 char *buf; 1922 register int sz; 1923 int spacesub; 1924 { 1925 bool oatomtok = FALSE; 1926 bool natomtok = FALSE; 1927 register int i; 1928 register char *p; 1929 1930 if (sz <= 0) 1931 return; 1932 1933 if (spacesub == '\0') 1934 spacesub = SpaceSub; 1935 1936 if (pvp == NULL) 1937 { 1938 *buf = '\0'; 1939 return; 1940 } 1941 p = buf; 1942 sz -= 2; 1943 while (*pvp != NULL && (i = strlen(*pvp)) < sz - 1) 1944 { 1945 natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 1946 if (oatomtok && natomtok) 1947 { 1948 *p++ = spacesub; 1949 --sz; 1950 } 1951 (void) strlcpy(p, *pvp, sz); 1952 oatomtok = natomtok; 1953 p += i; 1954 sz -= i; 1955 if (pvp++ == evp) 1956 break; 1957 } 1958 *p = '\0'; 1959 } 1960 /* 1961 ** SAMEADDR -- Determine if two addresses are the same 1962 ** 1963 ** This is not just a straight comparison -- if the mailer doesn't 1964 ** care about the host we just ignore it, etc. 1965 ** 1966 ** Parameters: 1967 ** a, b -- pointers to the internal forms to compare. 1968 ** 1969 ** Returns: 1970 ** TRUE -- they represent the same mailbox. 1971 ** FALSE -- they don't. 1972 ** 1973 ** Side Effects: 1974 ** none. 1975 */ 1976 1977 bool 1978 sameaddr(a, b) 1979 register ADDRESS *a; 1980 register ADDRESS *b; 1981 { 1982 register ADDRESS *ca, *cb; 1983 1984 /* if they don't have the same mailer, forget it */ 1985 if (a->q_mailer != b->q_mailer) 1986 return FALSE; 1987 1988 /* if the user isn't the same, we can drop out */ 1989 if (strcmp(a->q_user, b->q_user) != 0) 1990 return FALSE; 1991 1992 /* if we have good uids for both but they differ, these are different */ 1993 if (a->q_mailer == ProgMailer) 1994 { 1995 ca = getctladdr(a); 1996 cb = getctladdr(b); 1997 if (ca != NULL && cb != NULL && 1998 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1999 ca->q_uid != cb->q_uid) 2000 return FALSE; 2001 } 2002 2003 /* otherwise compare hosts (but be careful for NULL ptrs) */ 2004 if (a->q_host == b->q_host) 2005 { 2006 /* probably both null pointers */ 2007 return TRUE; 2008 } 2009 if (a->q_host == NULL || b->q_host == NULL) 2010 { 2011 /* only one is a null pointer */ 2012 return FALSE; 2013 } 2014 if (strcmp(a->q_host, b->q_host) != 0) 2015 return FALSE; 2016 2017 return TRUE; 2018 } 2019 /* 2020 ** PRINTADDR -- print address (for debugging) 2021 ** 2022 ** Parameters: 2023 ** a -- the address to print 2024 ** follow -- follow the q_next chain. 2025 ** 2026 ** Returns: 2027 ** none. 2028 ** 2029 ** Side Effects: 2030 ** none. 2031 */ 2032 2033 struct qflags 2034 { 2035 char *qf_name; 2036 u_long qf_bit; 2037 }; 2038 2039 static struct qflags AddressFlags[] = 2040 { 2041 { "QGOODUID", QGOODUID }, 2042 { "QPRIMARY", QPRIMARY }, 2043 { "QNOTREMOTE", QNOTREMOTE }, 2044 { "QSELFREF", QSELFREF }, 2045 { "QBOGUSSHELL", QBOGUSSHELL }, 2046 { "QUNSAFEADDR", QUNSAFEADDR }, 2047 { "QPINGONSUCCESS", QPINGONSUCCESS }, 2048 { "QPINGONFAILURE", QPINGONFAILURE }, 2049 { "QPINGONDELAY", QPINGONDELAY }, 2050 { "QHASNOTIFY", QHASNOTIFY }, 2051 { "QRELAYED", QRELAYED }, 2052 { "QEXPANDED", QEXPANDED }, 2053 { "QDELIVERED", QDELIVERED }, 2054 { "QDELAYED", QDELAYED }, 2055 { "QTHISPASS", QTHISPASS }, 2056 { "QRCPTOK", QRCPTOK }, 2057 { NULL, 0 } 2058 }; 2059 2060 void 2061 printaddr(a, follow) 2062 register ADDRESS *a; 2063 bool follow; 2064 { 2065 register MAILER *m; 2066 MAILER pseudomailer; 2067 register struct qflags *qfp; 2068 bool firstone; 2069 2070 if (a == NULL) 2071 { 2072 printf("[NULL]\n"); 2073 return; 2074 } 2075 2076 while (a != NULL) 2077 { 2078 printf("%lx=", (u_long) a); 2079 (void) fflush(stdout); 2080 2081 /* find the mailer -- carefully */ 2082 m = a->q_mailer; 2083 if (m == NULL) 2084 { 2085 m = &pseudomailer; 2086 m->m_mno = -1; 2087 m->m_name = "NULL"; 2088 } 2089 2090 printf("%s:\n\tmailer %d (%s), host `%s'\n", 2091 a->q_paddr == NULL ? "<null>" : a->q_paddr, 2092 m->m_mno, m->m_name, 2093 a->q_host == NULL ? "<null>" : a->q_host); 2094 printf("\tuser `%s', ruser `%s'\n", 2095 a->q_user, 2096 a->q_ruser == NULL ? "<null>" : a->q_ruser); 2097 printf("\tstate="); 2098 switch (a->q_state) 2099 { 2100 case QS_OK: 2101 printf("OK"); 2102 break; 2103 2104 case QS_DONTSEND: 2105 printf("DONTSEND"); 2106 break; 2107 2108 case QS_BADADDR: 2109 printf("BADADDR"); 2110 break; 2111 2112 case QS_QUEUEUP: 2113 printf("QUEUEUP"); 2114 break; 2115 2116 case QS_SENT: 2117 printf("SENT"); 2118 break; 2119 2120 case QS_VERIFIED: 2121 printf("VERIFIED"); 2122 break; 2123 2124 case QS_EXPANDED: 2125 printf("EXPANDED"); 2126 break; 2127 2128 case QS_SENDER: 2129 printf("SENDER"); 2130 break; 2131 2132 case QS_CLONED: 2133 printf("CLONED"); 2134 break; 2135 2136 case QS_DISCARDED: 2137 printf("DISCARDED"); 2138 break; 2139 2140 case QS_REPLACED: 2141 printf("REPLACED"); 2142 break; 2143 2144 case QS_REMOVED: 2145 printf("REMOVED"); 2146 break; 2147 2148 case QS_DUPLICATE: 2149 printf("DUPLICATE"); 2150 break; 2151 2152 case QS_INCLUDED: 2153 printf("INCLUDED"); 2154 break; 2155 2156 default: 2157 printf("%d", a->q_state); 2158 break; 2159 } 2160 printf(", next=%lx, alias %lx, uid %d, gid %d\n", 2161 (u_long) a->q_next, (u_long) a->q_alias, 2162 (int) a->q_uid, (int) a->q_gid); 2163 printf("\tflags=%lx<", a->q_flags); 2164 firstone = TRUE; 2165 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2166 { 2167 if (!bitset(qfp->qf_bit, a->q_flags)) 2168 continue; 2169 if (!firstone) 2170 printf(","); 2171 firstone = FALSE; 2172 printf("%s", qfp->qf_name); 2173 } 2174 printf(">\n"); 2175 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2176 a->q_owner == NULL ? "(none)" : a->q_owner, 2177 a->q_home == NULL ? "(none)" : a->q_home, 2178 a->q_fullname == NULL ? "(none)" : a->q_fullname); 2179 printf("\torcpt=\"%s\", statmta=%s, status=%s\n", 2180 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2181 a->q_statmta == NULL ? "(none)" : a->q_statmta, 2182 a->q_status == NULL ? "(none)" : a->q_status); 2183 printf("\trstatus=\"%s\"\n", 2184 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2185 printf("\tspecificity=%d, statdate=%s\n", 2186 a->q_specificity, 2187 a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2188 2189 if (!follow) 2190 return; 2191 a = a->q_next; 2192 } 2193 } 2194 /* 2195 ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 2196 ** 2197 ** Parameters: 2198 ** a -- pointer to the address 2199 ** 2200 ** Returns: 2201 ** TRUE -- if this address is "empty" (i.e., no one should 2202 ** ever generate replies to it. 2203 ** FALSE -- if it is a "regular" (read: replyable) address. 2204 */ 2205 2206 bool 2207 emptyaddr(a) 2208 register ADDRESS *a; 2209 { 2210 return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2211 a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2212 } 2213 /* 2214 ** REMOTENAME -- return the name relative to the current mailer 2215 ** 2216 ** Parameters: 2217 ** name -- the name to translate. 2218 ** m -- the mailer that we want to do rewriting relative 2219 ** to. 2220 ** flags -- fine tune operations. 2221 ** pstat -- pointer to status word. 2222 ** e -- the current envelope. 2223 ** 2224 ** Returns: 2225 ** the text string representing this address relative to 2226 ** the receiving mailer. 2227 ** 2228 ** Side Effects: 2229 ** none. 2230 ** 2231 ** Warnings: 2232 ** The text string returned is tucked away locally; 2233 ** copy it if you intend to save it. 2234 */ 2235 2236 char * 2237 remotename(name, m, flags, pstat, e) 2238 char *name; 2239 struct mailer *m; 2240 int flags; 2241 int *pstat; 2242 register ENVELOPE *e; 2243 { 2244 register char **pvp; 2245 char *fancy; 2246 char *oldg = macvalue('g', e); 2247 int rwset; 2248 static char buf[MAXNAME + 1]; 2249 char lbuf[MAXNAME + 1]; 2250 char pvpbuf[PSBUFSIZE]; 2251 #if _FFR_ADDR_TYPE 2252 char addrtype[4]; 2253 #endif /* _FFR_ADDR_TYPE */ 2254 2255 if (tTd(12, 1)) 2256 dprintf("remotename(%s)\n", name); 2257 2258 /* don't do anything if we are tagging it as special */ 2259 if (bitset(RF_SENDERADDR, flags)) 2260 { 2261 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2262 : m->m_se_rwset; 2263 #if _FFR_ADDR_TYPE 2264 addrtype[2] = 's'; 2265 #endif /* _FFR_ADDR_TYPE */ 2266 } 2267 else 2268 { 2269 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2270 : m->m_re_rwset; 2271 #if _FFR_ADDR_TYPE 2272 addrtype[2] = 'r'; 2273 #endif /* _FFR_ADDR_TYPE */ 2274 } 2275 if (rwset < 0) 2276 return name; 2277 #if _FFR_ADDR_TYPE 2278 addrtype[1] = ' '; 2279 addrtype[3] = '\0'; 2280 addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 2281 define(macid("{addr_type}", NULL), addrtype, e); 2282 #endif /* _FFR_ADDR_TYPE */ 2283 2284 /* 2285 ** Do a heuristic crack of this name to extract any comment info. 2286 ** This will leave the name as a comment and a $g macro. 2287 */ 2288 2289 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2290 fancy = "\201g"; 2291 else 2292 fancy = crackaddr(name); 2293 2294 /* 2295 ** Turn the name into canonical form. 2296 ** Normally this will be RFC 822 style, i.e., "user@domain". 2297 ** If this only resolves to "user", and the "C" flag is 2298 ** specified in the sending mailer, then the sender's 2299 ** domain will be appended. 2300 */ 2301 2302 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 2303 if (pvp == NULL) 2304 return name; 2305 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2306 *pstat = EX_TEMPFAIL; 2307 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2308 { 2309 /* append from domain to this address */ 2310 register char **pxp = pvp; 2311 int l = MAXATOM; /* size of buffer for pvp */ 2312 2313 /* see if there is an "@domain" in the current name */ 2314 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 2315 { 2316 pxp++; 2317 --l; 2318 } 2319 if (*pxp == NULL) 2320 { 2321 /* no.... append the "@domain" from the sender */ 2322 register char **qxq = e->e_fromdomain; 2323 2324 while ((*pxp++ = *qxq++) != NULL) 2325 { 2326 if (--l <= 0) 2327 { 2328 *--pxp = NULL; 2329 usrerr("553 5.1.0 remotename: too many tokens"); 2330 *pstat = EX_UNAVAILABLE; 2331 break; 2332 } 2333 } 2334 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2335 *pstat = EX_TEMPFAIL; 2336 } 2337 } 2338 2339 /* 2340 ** Do more specific rewriting. 2341 ** Rewrite using ruleset 1 or 2 depending on whether this is 2342 ** a sender address or not. 2343 ** Then run it through any receiving-mailer-specific rulesets. 2344 */ 2345 2346 if (bitset(RF_SENDERADDR, flags)) 2347 { 2348 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 2349 *pstat = EX_TEMPFAIL; 2350 } 2351 else 2352 { 2353 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 2354 *pstat = EX_TEMPFAIL; 2355 } 2356 if (rwset > 0) 2357 { 2358 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 2359 *pstat = EX_TEMPFAIL; 2360 } 2361 2362 /* 2363 ** Do any final sanitation the address may require. 2364 ** This will normally be used to turn internal forms 2365 ** (e.g., user@host.LOCAL) into external form. This 2366 ** may be used as a default to the above rules. 2367 */ 2368 2369 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 2370 *pstat = EX_TEMPFAIL; 2371 2372 /* 2373 ** Now restore the comment information we had at the beginning. 2374 */ 2375 2376 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 2377 define('g', lbuf, e); 2378 2379 /* need to make sure route-addrs have <angle brackets> */ 2380 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2381 expand("<\201g>", buf, sizeof buf, e); 2382 else 2383 expand(fancy, buf, sizeof buf, e); 2384 2385 define('g', oldg, e); 2386 2387 if (tTd(12, 1)) 2388 dprintf("remotename => `%s'\n", buf); 2389 return buf; 2390 } 2391 /* 2392 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2393 ** 2394 ** Parameters: 2395 ** a -- the address to map (but just the user name part). 2396 ** sendq -- the sendq in which to install any replacement 2397 ** addresses. 2398 ** aliaslevel -- the alias nesting depth. 2399 ** e -- the envelope. 2400 ** 2401 ** Returns: 2402 ** none. 2403 */ 2404 2405 #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2406 Q_PINGFLAGS|QHASNOTIFY|\ 2407 QRELAYED|QEXPANDED|QDELIVERED|QDELAYED) 2408 2409 void 2410 maplocaluser(a, sendq, aliaslevel, e) 2411 register ADDRESS *a; 2412 ADDRESS **sendq; 2413 int aliaslevel; 2414 ENVELOPE *e; 2415 { 2416 register char **pvp; 2417 register ADDRESS *a1 = NULL; 2418 auto char *delimptr; 2419 char pvpbuf[PSBUFSIZE]; 2420 2421 if (tTd(29, 1)) 2422 { 2423 dprintf("maplocaluser: "); 2424 printaddr(a, FALSE); 2425 } 2426 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 2427 if (pvp == NULL) 2428 { 2429 if (tTd(29, 9)) 2430 dprintf("maplocaluser: cannot prescan %s\n", 2431 a->q_user); 2432 return; 2433 } 2434 2435 define('h', a->q_host, e); 2436 define('u', a->q_user, e); 2437 define('z', a->q_home, e); 2438 2439 #if _FFR_ADDR_TYPE 2440 define(macid("{addr_type}", NULL), "e r", e); 2441 #endif /* _FFR_ADDR_TYPE */ 2442 if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL) 2443 { 2444 if (tTd(29, 9)) 2445 dprintf("maplocaluser: rewrite tempfail\n"); 2446 a->q_state = QS_QUEUEUP; 2447 a->q_status = "4.4.3"; 2448 return; 2449 } 2450 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2451 { 2452 if (tTd(29, 9)) 2453 dprintf("maplocaluser: doesn't resolve\n"); 2454 return; 2455 } 2456 2457 /* if non-null, mailer destination specified -- has it changed? */ 2458 a1 = buildaddr(pvp, NULL, 0, e); 2459 if (a1 == NULL || sameaddr(a, a1)) 2460 { 2461 if (tTd(29, 9)) 2462 dprintf("maplocaluser: address unchanged\n"); 2463 if (a1 != NULL) 2464 sm_free(a1); 2465 return; 2466 } 2467 2468 /* make new address take on flags and print attributes of old */ 2469 a1->q_flags &= ~Q_COPYFLAGS; 2470 a1->q_flags |= a->q_flags & Q_COPYFLAGS; 2471 a1->q_paddr = newstr(a->q_paddr); 2472 a1->q_orcpt = a->q_orcpt; 2473 2474 /* mark old address as dead; insert new address */ 2475 a->q_state = QS_REPLACED; 2476 if (tTd(29, 5)) 2477 { 2478 dprintf("maplocaluser: QS_REPLACED "); 2479 printaddr(a, FALSE); 2480 } 2481 a1->q_alias = a; 2482 allocaddr(a1, RF_COPYALL, newstr(a->q_paddr)); 2483 (void) recipient(a1, sendq, aliaslevel, e); 2484 } 2485 /* 2486 ** DEQUOTE_INIT -- initialize dequote map 2487 ** 2488 ** This is a no-op. 2489 ** 2490 ** Parameters: 2491 ** map -- the internal map structure. 2492 ** args -- arguments. 2493 ** 2494 ** Returns: 2495 ** TRUE. 2496 */ 2497 2498 bool 2499 dequote_init(map, args) 2500 MAP *map; 2501 char *args; 2502 { 2503 register char *p = args; 2504 2505 /* there is no check whether there is really an argument */ 2506 map->map_mflags |= MF_KEEPQUOTES; 2507 for (;;) 2508 { 2509 while (isascii(*p) && isspace(*p)) 2510 p++; 2511 if (*p != '-') 2512 break; 2513 switch (*++p) 2514 { 2515 case 'a': 2516 map->map_app = ++p; 2517 break; 2518 2519 case 'D': 2520 map->map_mflags |= MF_DEFER; 2521 break; 2522 2523 case 'S': 2524 case 's': 2525 map->map_spacesub = *++p; 2526 break; 2527 } 2528 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2529 p++; 2530 if (*p != '\0') 2531 *p = '\0'; 2532 } 2533 if (map->map_app != NULL) 2534 map->map_app = newstr(map->map_app); 2535 2536 return TRUE; 2537 } 2538 /* 2539 ** DEQUOTE_MAP -- unquote an address 2540 ** 2541 ** Parameters: 2542 ** map -- the internal map structure (ignored). 2543 ** name -- the name to dequote. 2544 ** av -- arguments (ignored). 2545 ** statp -- pointer to status out-parameter. 2546 ** 2547 ** Returns: 2548 ** NULL -- if there were no quotes, or if the resulting 2549 ** unquoted buffer would not be acceptable to prescan. 2550 ** else -- The dequoted buffer. 2551 */ 2552 2553 /* ARGSUSED2 */ 2554 char * 2555 dequote_map(map, name, av, statp) 2556 MAP *map; 2557 char *name; 2558 char **av; 2559 int *statp; 2560 { 2561 register char *p; 2562 register char *q; 2563 register char c; 2564 int anglecnt = 0; 2565 int cmntcnt = 0; 2566 int quotecnt = 0; 2567 int spacecnt = 0; 2568 bool quotemode = FALSE; 2569 bool bslashmode = FALSE; 2570 char spacesub = map->map_spacesub; 2571 2572 for (p = q = name; (c = *p++) != '\0'; ) 2573 { 2574 if (bslashmode) 2575 { 2576 bslashmode = FALSE; 2577 *q++ = c; 2578 continue; 2579 } 2580 2581 if (c == ' ' && spacesub != '\0') 2582 c = spacesub; 2583 2584 switch (c) 2585 { 2586 case '\\': 2587 bslashmode = TRUE; 2588 break; 2589 2590 case '(': 2591 cmntcnt++; 2592 break; 2593 2594 case ')': 2595 if (cmntcnt-- <= 0) 2596 return NULL; 2597 break; 2598 2599 case ' ': 2600 case '\t': 2601 spacecnt++; 2602 break; 2603 } 2604 2605 if (cmntcnt > 0) 2606 { 2607 *q++ = c; 2608 continue; 2609 } 2610 2611 switch (c) 2612 { 2613 case '"': 2614 quotemode = !quotemode; 2615 quotecnt++; 2616 continue; 2617 2618 case '<': 2619 anglecnt++; 2620 break; 2621 2622 case '>': 2623 if (anglecnt-- <= 0) 2624 return NULL; 2625 break; 2626 } 2627 *q++ = c; 2628 } 2629 2630 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2631 quotemode || quotecnt <= 0 || spacecnt != 0) 2632 return NULL; 2633 *q++ = '\0'; 2634 return map_rewrite(map, name, strlen(name), NULL); 2635 } 2636 /* 2637 ** RSCHECK -- check string(s) for validity using rewriting sets 2638 ** 2639 ** Parameters: 2640 ** rwset -- the rewriting set to use. 2641 ** p1 -- the first string to check. 2642 ** p2 -- the second string to check -- may be null. 2643 ** e -- the current envelope. 2644 ** rmcomm -- remove comments? 2645 ** cnt -- count rejections (statistics)? 2646 ** logl -- logging level 2647 ** host -- NULL or relay host. 2648 ** 2649 ** Returns: 2650 ** EX_OK -- if the rwset doesn't resolve to $#error 2651 ** else -- the failure status (message printed) 2652 */ 2653 2654 int 2655 rscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host) 2656 char *rwset; 2657 char *p1; 2658 char *p2; 2659 ENVELOPE *e; 2660 bool rmcomm, cnt; 2661 int logl; 2662 char *host; 2663 { 2664 char *buf; 2665 int bufsize; 2666 int saveexitstat; 2667 int rstat = EX_OK; 2668 char **pvp; 2669 int rsno; 2670 bool discard = FALSE; 2671 auto ADDRESS a1; 2672 bool saveQuickAbort = QuickAbort; 2673 bool saveSuprErrs = SuprErrs; 2674 char buf0[MAXLINE]; 2675 char pvpbuf[PSBUFSIZE]; 2676 extern char MsgBuf[]; 2677 2678 if (tTd(48, 2)) 2679 dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 2680 p2 == NULL ? "(NULL)" : p2); 2681 2682 rsno = strtorwset(rwset, NULL, ST_FIND); 2683 if (rsno < 0) 2684 return EX_OK; 2685 2686 if (p2 != NULL) 2687 { 2688 bufsize = strlen(p1) + strlen(p2) + 2; 2689 if (bufsize > sizeof buf0) 2690 buf = xalloc(bufsize); 2691 else 2692 { 2693 buf = buf0; 2694 bufsize = sizeof buf0; 2695 } 2696 (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2697 } 2698 else 2699 { 2700 bufsize = strlen(p1) + 1; 2701 if (bufsize > sizeof buf0) 2702 buf = xalloc(bufsize); 2703 else 2704 { 2705 buf = buf0; 2706 bufsize = sizeof buf0; 2707 } 2708 (void) snprintf(buf, bufsize, "%s", p1); 2709 } 2710 SuprErrs = TRUE; 2711 QuickAbort = FALSE; 2712 pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 2713 rmcomm ? NULL : TokTypeNoC); 2714 SuprErrs = saveSuprErrs; 2715 if (pvp == NULL) 2716 { 2717 if (tTd(48, 2)) 2718 dprintf("rscheck: cannot prescan input\n"); 2719 /* 2720 syserr("rscheck: cannot prescan input: \"%s\"", 2721 shortenstring(buf, MAXSHORTSTR)); 2722 rstat = EX_DATAERR; 2723 */ 2724 goto finis; 2725 } 2726 2727 MapOpenErr = FALSE; 2728 (void) rewrite(pvp, rsno, 0, e); 2729 if (MapOpenErr) 2730 { 2731 usrerrenh("4.3.0", "451 Temporary failure"); 2732 rstat = EX_TEMPFAIL; 2733 goto finis; 2734 } 2735 2736 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 2737 pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 2738 strcmp(pvp[1], "discard") != 0)) 2739 { 2740 goto finis; 2741 } 2742 2743 if (strcmp(pvp[1], "discard") == 0) 2744 { 2745 if (tTd(48, 2)) 2746 dprintf("rscheck: discard mailer selected\n"); 2747 e->e_flags |= EF_DISCARD; 2748 discard = TRUE; 2749 } 2750 else 2751 { 2752 int savelogusrerrs = LogUsrErrs; 2753 static bool logged = FALSE; 2754 2755 /* got an error -- process it */ 2756 saveexitstat = ExitStat; 2757 LogUsrErrs = FALSE; 2758 (void) buildaddr(pvp, &a1, 0, e); 2759 LogUsrErrs = savelogusrerrs; 2760 rstat = ExitStat; 2761 ExitStat = saveexitstat; 2762 if (!logged) 2763 { 2764 if (cnt) 2765 markstats(e, &a1, TRUE); 2766 logged = TRUE; 2767 } 2768 } 2769 2770 if (LogLevel >= logl) 2771 { 2772 char *relay; 2773 char *p; 2774 char lbuf[MAXLINE]; 2775 2776 p = lbuf; 2777 if (p2 != NULL) 2778 { 2779 snprintf(p, SPACELEFT(lbuf, p), 2780 ", arg2=%s", 2781 p2); 2782 p += strlen(p); 2783 } 2784 2785 if (host != NULL) 2786 relay = host; 2787 else 2788 relay = macvalue('_', e); 2789 if (relay != NULL) 2790 { 2791 snprintf(p, SPACELEFT(lbuf, p), 2792 ", relay=%s", relay); 2793 p += strlen(p); 2794 } 2795 *p = '\0'; 2796 if (discard) 2797 sm_syslog(LOG_NOTICE, e->e_id, 2798 "ruleset=%s, arg1=%s%s, discard", 2799 rwset, p1, lbuf); 2800 else 2801 sm_syslog(LOG_NOTICE, e->e_id, 2802 "ruleset=%s, arg1=%s%s, reject=%s", 2803 rwset, p1, lbuf, MsgBuf); 2804 } 2805 2806 finis: 2807 /* clean up */ 2808 QuickAbort = saveQuickAbort; 2809 setstat(rstat); 2810 if (buf != buf0) 2811 sm_free(buf); 2812 2813 if (rstat != EX_OK && QuickAbort) 2814 longjmp(TopFrame, 2); 2815 return rstat; 2816 } 2817