parseaddr.c revision 71345
1103285Sikob/* 2113584Ssimokawa * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 3103285Sikob * All rights reserved. 4103285Sikob * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5103285Sikob * Copyright (c) 1988, 1993 6103285Sikob * The Regents of the University of California. All rights reserved. 7103285Sikob * 8103285Sikob * By using this file, you agree to the terms and conditions set 9103285Sikob * forth in the LICENSE file which can be found at the top level of 10103285Sikob * the sendmail distribution. 11103285Sikob * 12103285Sikob */ 13103285Sikob 14103285Sikob#ifndef lint 15103285Sikobstatic char id[] = "@(#)$Id: parseaddr.c,v 8.234.4.9 2000/10/09 03:14:48 gshapiro Exp $"; 16103285Sikob#endif /* ! lint */ 17106802Ssimokawa 18103285Sikob#include <sendmail.h> 19103285Sikob 20103285Sikobstatic void allocaddr __P((ADDRESS *, int, char *)); 21103285Sikobstatic int callsubr __P((char**, int, ENVELOPE *)); 22103285Sikobstatic char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 23103285Sikobstatic ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); 24103285Sikob 25103285Sikob/* 26103285Sikob** PARSEADDR -- Parse an address 27103285Sikob** 28103285Sikob** Parses an address and breaks it up into three parts: a 29103285Sikob** net to transmit the message on, the host to transmit it 30103285Sikob** to, and a user on that host. These are loaded into an 31103285Sikob** ADDRESS header with the values squirreled away if necessary. 32103285Sikob** The "user" part may not be a real user; the process may 33103285Sikob** just reoccur on that machine. For example, on a machine 34103285Sikob** with an arpanet connection, the address 35103285Sikob** csvax.bill@berkeley 36103285Sikob** will break up to a "user" of 'csvax.bill' and a host 37106802Ssimokawa** of 'berkeley' -- to be transmitted over the arpanet. 38103285Sikob** 39103285Sikob** Parameters: 40103285Sikob** addr -- the address to parse. 41103285Sikob** a -- a pointer to the address descriptor buffer. 42103285Sikob** If NULL, a header will be created. 43103285Sikob** flags -- describe detail for parsing. See RF_ definitions 44103285Sikob** in sendmail.h. 45103285Sikob** delim -- the character to terminate the address, passed 46103285Sikob** to prescan. 47103285Sikob** delimptr -- if non-NULL, set to the location of the 48103285Sikob** delim character that was found. 49103285Sikob** e -- the envelope that will contain this address. 50103285Sikob** 51103285Sikob** Returns: 52103285Sikob** A pointer to the address descriptor header (`a' if 53113584Ssimokawa** `a' is non-NULL). 54103285Sikob** NULL on error. 55103285Sikob** 56103285Sikob** Side Effects: 57127468Ssimokawa** none 58117067Ssimokawa*/ 59117067Ssimokawa 60117067Ssimokawa/* following delimiters are inherent to the internal algorithms */ 61127468Ssimokawa#define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 62127468Ssimokawa 63127468SsimokawaADDRESS * 64127468Ssimokawaparseaddr(addr, a, flags, delim, delimptr, e) 65127468Ssimokawa char *addr; 66127468Ssimokawa register ADDRESS *a; 67127468Ssimokawa int flags; 68127468Ssimokawa int delim; 69103285Sikob char **delimptr; 70103285Sikob register ENVELOPE *e; 71113584Ssimokawa{ 72103285Sikob register char **pvp; 73103285Sikob auto char *delimptrbuf; 74103285Sikob bool qup; 75127468Ssimokawa char pvpbuf[PSBUFSIZE]; 76103285Sikob 77103285Sikob /* 78106802Ssimokawa ** Initialize and prescan address. 79103285Sikob */ 80103285Sikob 81113584Ssimokawa e->e_to = addr; 82103285Sikob if (tTd(20, 1)) 83103285Sikob dprintf("\n--parseaddr(%s)\n", addr); 84113584Ssimokawa 85103285Sikob if (delimptr == NULL) 86103285Sikob delimptr = &delimptrbuf; 87103285Sikob 88103285Sikob pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); 89103285Sikob if (pvp == NULL) 90103285Sikob { 91103285Sikob if (tTd(20, 1)) 92103285Sikob dprintf("parseaddr-->NULL\n"); 93103285Sikob return NULL; 94113584Ssimokawa } 95116376Ssimokawa 96124378Ssimokawa if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 97129585Sdfr { 98103285Sikob if (tTd(20, 1)) 99103285Sikob dprintf("parseaddr-->bad address\n"); 100103285Sikob return NULL; 101103285Sikob } 102103285Sikob 103103285Sikob /* 104103285Sikob ** Save addr if we are going to have to. 105103285Sikob ** 106103285Sikob ** We have to do this early because there is a chance that 107103285Sikob ** the map lookups in the rewriting rules could clobber 108103285Sikob ** static memory somewhere. 109103285Sikob */ 110103285Sikob 111103285Sikob if (bitset(RF_COPYPADDR, flags) && addr != NULL) 112103285Sikob { 113103285Sikob char savec = **delimptr; 114103285Sikob 115103285Sikob if (savec != '\0') 116103285Sikob **delimptr = '\0'; 117103285Sikob e->e_to = addr = newstr(addr); 118103285Sikob if (savec != '\0') 119103285Sikob **delimptr = savec; 120103285Sikob } 121103285Sikob 122103285Sikob /* 123103285Sikob ** Apply rewriting rules. 124103285Sikob ** Ruleset 0 does basic parsing. It must resolve. 125124169Ssimokawa */ 126124169Ssimokawa 127124169Ssimokawa qup = FALSE; 128124169Ssimokawa if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 129124169Ssimokawa qup = TRUE; 130124169Ssimokawa if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) 131124169Ssimokawa qup = TRUE; 132124169Ssimokawa 133129585Sdfr 134129585Sdfr /* 135124169Ssimokawa ** Build canonical address from pvp. 136124169Ssimokawa */ 137124169Ssimokawa 138124169Ssimokawa a = buildaddr(pvp, a, flags, e); 139113584Ssimokawa 140129585Sdfr /* 141113584Ssimokawa ** Make local copies of the host & user and then 142124169Ssimokawa ** transport them out. 143124169Ssimokawa */ 144124169Ssimokawa 145124169Ssimokawa allocaddr(a, flags, addr); 146113584Ssimokawa if (QS_IS_BADADDR(a->q_state)) 147124169Ssimokawa return a; 148124169Ssimokawa 149129585Sdfr /* 150129585Sdfr ** If there was a parsing failure, mark it for queueing. 151129585Sdfr */ 152129585Sdfr 153124169Ssimokawa if (qup && OpMode != MD_INITALIAS) 154124169Ssimokawa { 155124169Ssimokawa char *msg = "Transient parse error -- message queued for future delivery"; 156113584Ssimokawa 157113584Ssimokawa if (e->e_sendmode == SM_DEFER) 158113584Ssimokawa msg = "Deferring message until queue run"; 159103285Sikob if (tTd(20, 1)) 160103285Sikob dprintf("parseaddr: queuing message\n"); 161103285Sikob message(msg); 162103285Sikob if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 163103285Sikob e->e_message = newstr(msg); 164103285Sikob a->q_state = QS_QUEUEUP; 165103285Sikob a->q_status = "4.4.3"; 166103285Sikob } 167103285Sikob 168112523Ssimokawa /* 169103285Sikob ** Compute return value. 170103285Sikob */ 171103285Sikob 172103285Sikob if (tTd(20, 1)) 173103285Sikob { 174103285Sikob dprintf("parseaddr-->"); 175103285Sikob printaddr(a, FALSE); 176103285Sikob } 177103285Sikob 178103285Sikob return a; 179103285Sikob} 180103285Sikob/* 181103285Sikob** INVALIDADDR -- check for address containing meta-characters 182103285Sikob** 183103285Sikob** Parameters: 184103285Sikob** addr -- the address to check. 185103285Sikob** 186103285Sikob** Returns: 187103285Sikob** TRUE -- if the address has any "wierd" characters 188103285Sikob** FALSE -- otherwise. 189103285Sikob*/ 190103285Sikob 191103285Sikobbool 192103285Sikobinvalidaddr(addr, delimptr) 193103285Sikob register char *addr; 194103285Sikob char *delimptr; 195103285Sikob{ 196103285Sikob char savedelim = '\0'; 197113584Ssimokawa 198103285Sikob if (delimptr != NULL) 199103285Sikob { 200103285Sikob savedelim = *delimptr; 201103285Sikob if (savedelim != '\0') 202103285Sikob *delimptr = '\0'; 203103285Sikob } 204103285Sikob if (strlen(addr) > MAXNAME - 1) 205103285Sikob { 206103285Sikob usrerr("553 5.1.1 Address too long (%d bytes max)", 207103285Sikob MAXNAME - 1); 208103285Sikob goto failure; 209103285Sikob } 210103285Sikob for (; *addr != '\0'; addr++) 211103285Sikob { 212103285Sikob if ((*addr & 0340) == 0200) 213103285Sikob break; 214103285Sikob } 215103285Sikob if (*addr == '\0') 216103285Sikob { 217103285Sikob if (delimptr != NULL && savedelim != '\0') 218103285Sikob *delimptr = savedelim; 219103285Sikob return FALSE; 220103285Sikob } 221103285Sikob setstat(EX_USAGE); 222103285Sikob usrerr("553 5.1.1 Address contained invalid control characters"); 223103285Sikobfailure: 224103285Sikob if (delimptr != NULL && savedelim != '\0') 225103285Sikob *delimptr = savedelim; 226103285Sikob return TRUE; 227103285Sikob} 228103285Sikob/* 229103285Sikob** ALLOCADDR -- do local allocations of address on demand. 230103285Sikob** 231103285Sikob** Also lowercases the host name if requested. 232103285Sikob** 233103285Sikob** Parameters: 234103285Sikob** a -- the address to reallocate. 235103285Sikob** flags -- the copy flag (see RF_ definitions in sendmail.h 236103285Sikob** for a description). 237103285Sikob** paddr -- the printname of the address. 238103285Sikob** 239103285Sikob** Returns: 240103285Sikob** none. 241103285Sikob** 242103285Sikob** Side Effects: 243103285Sikob** Copies portions of a into local buffers as requested. 244103285Sikob*/ 245103285Sikob 246103285Sikobstatic void 247103285Sikoballocaddr(a, flags, paddr) 248103285Sikob register ADDRESS *a; 249103285Sikob int flags; 250103285Sikob char *paddr; 251103285Sikob{ 252103285Sikob if (tTd(24, 4)) 253103285Sikob dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 254103285Sikob 255103285Sikob a->q_paddr = paddr; 256103285Sikob 257103285Sikob if (a->q_user == NULL) 258103285Sikob a->q_user = newstr(""); 259103285Sikob if (a->q_host == NULL) 260103285Sikob a->q_host = newstr(""); 261129585Sdfr 262129585Sdfr if (bitset(RF_COPYPARSE, flags)) 263103285Sikob { 264129585Sdfr a->q_host = newstr(a->q_host); 265103285Sikob if (a->q_user != a->q_paddr) 266103285Sikob a->q_user = newstr(a->q_user); 267103285Sikob } 268103285Sikob 269103285Sikob if (a->q_paddr == NULL) 270103285Sikob a->q_paddr = newstr(a->q_user); 271103285Sikob} 272103285Sikob/* 273103285Sikob** PRESCAN -- Prescan name and make it canonical 274103285Sikob** 275103285Sikob** Scans a name and turns it into a set of tokens. This process 276129585Sdfr** deletes blanks and comments (in parentheses) (if the token type 277103285Sikob** for left paren is SPC). 278103285Sikob** 279103285Sikob** This routine knows about quoted strings and angle brackets. 280103285Sikob** 281129585Sdfr** There are certain subtleties to this routine. The one that 282103285Sikob** comes to mind now is that backslashes on the ends of names 283103285Sikob** are silently stripped off; this is intentional. The problem 284103285Sikob** is that some versions of sndmsg (like at LBL) set the kill 285103285Sikob** character to something other than @ when reading addresses; 286103285Sikob** so people type "csvax.eric\@berkeley" -- which screws up the 287103285Sikob** berknet mailer. 288103285Sikob** 289103285Sikob** Parameters: 290103285Sikob** addr -- the name to chomp. 291103285Sikob** delim -- the delimiter for the address, normally 292109280Ssimokawa** '\0' or ','; \0 is accepted in any case. 293103285Sikob** If '\t' then we are reading the .cf file. 294107653Ssimokawa** pvpbuf -- place to put the saved text -- note that 295103285Sikob** the pointers are static. 296107653Ssimokawa** pvpbsize -- size of pvpbuf. 297107653Ssimokawa** delimptr -- if non-NULL, set to the location of the 298107653Ssimokawa** terminating delimiter. 299103285Sikob** toktab -- if set, a token table to use for parsing. 300103285Sikob** If NULL, use the default table. 301103285Sikob** 302103285Sikob** Returns: 303129585Sdfr** A pointer to a vector of tokens. 304106790Ssimokawa** NULL on error. 305103285Sikob*/ 306129585Sdfr 307108500Ssimokawa/* states and character types */ 308103285Sikob#define OPR 0 /* operator */ 309103285Sikob#define ATM 1 /* atom */ 310108500Ssimokawa#define QST 2 /* in quoted string */ 311108500Ssimokawa#define SPC 3 /* chewing up spaces */ 312108500Ssimokawa#define ONE 4 /* pick up one character */ 313103285Sikob#define ILL 5 /* illegal character */ 314103285Sikob 315108500Ssimokawa#define NSTATES 6 /* number of states */ 316103285Sikob#define TYPE 017 /* mask to select state type */ 317103285Sikob 318103285Sikob/* meta bits for table */ 319109280Ssimokawa#define M 020 /* meta character; don't pass through */ 320103285Sikob#define B 040 /* cause a break */ 321108500Ssimokawa#define MB M|B /* meta-break */ 322109280Ssimokawa 323109280Ssimokawastatic short StateTab[NSTATES][NSTATES] = 324108527Ssimokawa{ 325109280Ssimokawa /* oldst chtype> OPR ATM QST SPC ONE ILL */ 326108527Ssimokawa /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 327108527Ssimokawa /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 328108500Ssimokawa /*QST*/ { QST, QST, OPR, QST, QST, QST }, 329108500Ssimokawa /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 330108500Ssimokawa /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 331108500Ssimokawa /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 332108500Ssimokawa}; 333109280Ssimokawa 334109280Ssimokawa/* token type table -- it gets modified with $o characters */ 335108500Ssimokawastatic u_char TokTypeTab[256] = 336109280Ssimokawa{ 337108500Ssimokawa /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 338108500Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 339108500Ssimokawa /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 340108500Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 341108500Ssimokawa /* sp ! " # $ % & ' ( ) * + , - . / */ 342119118Ssimokawa SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 343108500Ssimokawa /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 344103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 345103285Sikob /* @ A B C D E F G H I J K L M N O */ 346103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 347103285Sikob /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 348130585Sphk ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 349103285Sikob /* ` a b c d e f g h i j k l m n o */ 350103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 351103285Sikob /* p q r s t u v w x y z { | } ~ del */ 352103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 353103285Sikob 354103285Sikob /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 355129585Sdfr OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 356103285Sikob /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 357103285Sikob OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 358103285Sikob /* sp ! " # $ % & ' ( ) * + , - . / */ 359103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 360103285Sikob /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 361103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 362103285Sikob /* @ A B C D E F G H I J K L M N O */ 363103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 364103285Sikob /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 365103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 366103285Sikob /* ` a b c d e f g h i j k l m n o */ 367103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 368103285Sikob /* p q r s t u v w x y z { | } ~ del */ 369103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 370103285Sikob}; 371103285Sikob 372103285Sikob/* token type table for MIME parsing */ 373103285Sikobu_char MimeTokenTab[256] = 374103285Sikob{ 375103285Sikob /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 376103285Sikob ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 377103285Sikob /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 378103285Sikob ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 379103285Sikob /* sp ! " # $ % & ' ( ) * + , - . / */ 380103285Sikob SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 381103285Sikob /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 382103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 383103285Sikob /* @ A B C D E F G H I J K L M N O */ 384103285Sikob OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 385103285Sikob /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 386103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 387103285Sikob /* ` a b c d e f g h i j k l m n o */ 388103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 389103285Sikob /* p q r s t u v w x y z { | } ~ del */ 390103285Sikob ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 391103285Sikob 392119118Ssimokawa /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 393119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 394119118Ssimokawa /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 395119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 396119118Ssimokawa /* sp ! " # $ % & ' ( ) * + , - . / */ 397119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 398119118Ssimokawa /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 399119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 400119118Ssimokawa /* @ A B C D E F G H I J K L M N O */ 401119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 402119118Ssimokawa /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 403119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 404119118Ssimokawa /* ` a b c d e f g h i j k l m n o */ 405119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 406103285Sikob /* p q r s t u v w x y z { | } ~ del */ 407119118Ssimokawa ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 408103285Sikob}; 409103285Sikob 410103285Sikob/* token type table: don't strip comments */ 411103285Sikobu_char TokTypeNoC[256] = 412106790Ssimokawa{ 413108530Ssimokawa /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 414108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 415103285Sikob /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 416129585Sdfr ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 417108530Ssimokawa /* sp ! " # $ % & ' ( ) * + , - . / */ 418108530Ssimokawa SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 419108530Ssimokawa /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 420108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 421108530Ssimokawa /* @ A B C D E F G H I J K L M N O */ 422108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 423108530Ssimokawa /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 424108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 425108530Ssimokawa /* ` a b c d e f g h i j k l m n o */ 426108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 427108530Ssimokawa /* p q r s t u v w x y z { | } ~ del */ 428108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 429108530Ssimokawa 430108530Ssimokawa /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 431108530Ssimokawa OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 432108530Ssimokawa /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 433108530Ssimokawa OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 434108530Ssimokawa /* sp ! " # $ % & ' ( ) * + , - . / */ 435108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 436108530Ssimokawa /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 437108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 438108701Ssimokawa /* @ A B C D E F G H I J K L M N O */ 439108701Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 440108530Ssimokawa /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 441108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 442108530Ssimokawa /* ` a b c d e f g h i j k l m n o */ 443108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 444108530Ssimokawa /* p q r s t u v w x y z { | } ~ del */ 445108530Ssimokawa ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 446108530Ssimokawa}; 447108530Ssimokawa 448108530Ssimokawa 449108530Ssimokawa#define NOCHAR -1 /* signal nothing in lookahead token */ 450108530Ssimokawa 451108701Ssimokawachar ** 452108701Ssimokawaprescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) 453108530Ssimokawa char *addr; 454108530Ssimokawa int delim; 455108530Ssimokawa char pvpbuf[]; 456108530Ssimokawa int pvpbsize; 457108530Ssimokawa char **delimptr; 458108530Ssimokawa u_char *toktab; 459108530Ssimokawa{ 460108530Ssimokawa register char *p; 461108530Ssimokawa register char *q; 462108530Ssimokawa register int c; 463108530Ssimokawa char **avp; 464108530Ssimokawa bool bslashmode; 465108530Ssimokawa bool route_syntax; 466108530Ssimokawa int cmntcnt; 467108530Ssimokawa int anglecnt; 468108530Ssimokawa char *tok; 469108530Ssimokawa int state; 470108530Ssimokawa int newstate; 471108530Ssimokawa char *saveto = CurEnv->e_to; 472108530Ssimokawa static char *av[MAXATOM + 1]; 473108530Ssimokawa static char firsttime = TRUE; 474108530Ssimokawa extern int errno; 475108530Ssimokawa 476108530Ssimokawa if (firsttime) 477108530Ssimokawa { 478108530Ssimokawa /* initialize the token type table */ 479108530Ssimokawa char obuf[50]; 480108530Ssimokawa 481108530Ssimokawa firsttime = FALSE; 482108530Ssimokawa if (OperatorChars == NULL) 483108530Ssimokawa { 484108530Ssimokawa if (ConfigLevel < 7) 485108530Ssimokawa OperatorChars = macvalue('o', CurEnv); 486108530Ssimokawa if (OperatorChars == NULL) 487108530Ssimokawa OperatorChars = ".:@[]"; 488108530Ssimokawa } 489108530Ssimokawa expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, 490108701Ssimokawa CurEnv); 491129585Sdfr (void) strlcat(obuf, DELIMCHARS, sizeof obuf); 492103285Sikob for (p = obuf; *p != '\0'; p++) 493103285Sikob { 494129541Sdfr if (TokTypeTab[*p & 0xff] == ATM) 495108530Ssimokawa TokTypeTab[*p & 0xff] = OPR; 496108530Ssimokawa if (TokTypeNoC[*p & 0xff] == ATM) 497129541Sdfr TokTypeNoC[*p & 0xff] = OPR; 498108530Ssimokawa } 499108530Ssimokawa } 500108530Ssimokawa if (toktab == NULL) 501108530Ssimokawa toktab = TokTypeTab; 502108530Ssimokawa 503108530Ssimokawa /* make sure error messages don't have garbage on them */ 504108530Ssimokawa errno = 0; 505108530Ssimokawa 506108530Ssimokawa q = pvpbuf; 507108530Ssimokawa bslashmode = FALSE; 508108530Ssimokawa route_syntax = FALSE; 509108701Ssimokawa cmntcnt = 0; 510108530Ssimokawa anglecnt = 0; 511108530Ssimokawa avp = av; 512108530Ssimokawa state = ATM; 513108530Ssimokawa c = NOCHAR; 514108530Ssimokawa p = addr; 515108530Ssimokawa CurEnv->e_to = p; 516108530Ssimokawa if (tTd(22, 11)) 517108530Ssimokawa { 518108530Ssimokawa dprintf("prescan: "); 519108530Ssimokawa xputs(p); 520108530Ssimokawa dprintf("\n"); 521108701Ssimokawa } 522108701Ssimokawa 523108701Ssimokawa do 524108701Ssimokawa { 525108530Ssimokawa /* read a token */ 526108530Ssimokawa tok = q; 527108701Ssimokawa for (;;) 528108701Ssimokawa { 529108701Ssimokawa /* store away any old lookahead character */ 530108701Ssimokawa if (c != NOCHAR && !bslashmode) 531108701Ssimokawa { 532108701Ssimokawa /* see if there is room */ 533108701Ssimokawa if (q >= &pvpbuf[pvpbsize - 5]) 534108701Ssimokawa { 535108701Ssimokawa usrerr("553 5.1.1 Address too long"); 536108701Ssimokawa if (strlen(addr) > (SIZE_T) MAXNAME) 537108701Ssimokawa addr[MAXNAME] = '\0'; 538108530Ssimokawa returnnull: 539108530Ssimokawa if (delimptr != NULL) 540108530Ssimokawa *delimptr = p; 541108530Ssimokawa CurEnv->e_to = saveto; 542108701Ssimokawa return NULL; 543108530Ssimokawa } 544113584Ssimokawa 545108530Ssimokawa /* squirrel it away */ 546108530Ssimokawa *q++ = c; 547113584Ssimokawa } 548108530Ssimokawa 549108530Ssimokawa /* read a new input character */ 550108701Ssimokawa c = *p++; 551108530Ssimokawa if (c == '\0') 552108642Ssimokawa { 553108701Ssimokawa /* diagnose and patch up bad syntax */ 554108642Ssimokawa if (state == QST) 555108642Ssimokawa { 556108530Ssimokawa usrerr("653 Unbalanced '\"'"); 557108530Ssimokawa c = '"'; 558108530Ssimokawa } 559108701Ssimokawa else if (cmntcnt > 0) 560108701Ssimokawa { 561108701Ssimokawa usrerr("653 Unbalanced '('"); 562116978Ssimokawa c = ')'; 563108701Ssimokawa } 564108701Ssimokawa else if (anglecnt > 0) 565108701Ssimokawa { 566108701Ssimokawa c = '>'; 567116978Ssimokawa usrerr("653 Unbalanced '<'"); 568116978Ssimokawa } 569116978Ssimokawa else 570116978Ssimokawa break; 571116978Ssimokawa 572116978Ssimokawa p--; 573108530Ssimokawa } 574108530Ssimokawa else if (c == delim && cmntcnt <= 0 && state != QST) 575108530Ssimokawa { 576108530Ssimokawa if (anglecnt <= 0) 577108530Ssimokawa break; 578108530Ssimokawa 579108530Ssimokawa /* special case for better error management */ 580108530Ssimokawa if (delim == ',' && !route_syntax) 581108530Ssimokawa { 582108701Ssimokawa usrerr("653 Unbalanced '<'"); 583129541Sdfr c = '>'; 584108530Ssimokawa p--; 585108530Ssimokawa } 586108530Ssimokawa } 587108530Ssimokawa 588108530Ssimokawa if (tTd(22, 101)) 589108530Ssimokawa dprintf("c=%c, s=%d; ", c, state); 590108530Ssimokawa 591108530Ssimokawa /* chew up special characters */ 592108530Ssimokawa *q = '\0'; 593108530Ssimokawa if (bslashmode) 594108530Ssimokawa { 595108530Ssimokawa bslashmode = FALSE; 596121781Ssimokawa 597129585Sdfr /* kludge \! for naive users */ 598129585Sdfr if (cmntcnt > 0) 599108530Ssimokawa { 600113584Ssimokawa c = NOCHAR; 601113584Ssimokawa continue; 602113584Ssimokawa } 603113584Ssimokawa else if (c != '!' || state == QST) 604121781Ssimokawa { 605103285Sikob *q++ = '\\'; 606121781Ssimokawa continue; 607103285Sikob } 608121781Ssimokawa } 609121781Ssimokawa 610118416Ssimokawa if (c == '\\') 611118416Ssimokawa { 612118416Ssimokawa bslashmode = TRUE; 613118416Ssimokawa } 614129541Sdfr else if (state == QST) 615110045Ssimokawa { 616110045Ssimokawa /* EMPTY */ 617110045Ssimokawa /* do nothing, just avoid next clauses */ 618110045Ssimokawa } 619110045Ssimokawa else if (c == '(' && toktab['('] == SPC) 620110045Ssimokawa { 621110045Ssimokawa cmntcnt++; 622110045Ssimokawa c = NOCHAR; 623103285Sikob } 624129541Sdfr else if (c == ')' && toktab['('] == SPC) 625118820Ssimokawa { 626118820Ssimokawa if (cmntcnt <= 0) 627103285Sikob { 628103285Sikob usrerr("653 Unbalanced ')'"); 629103285Sikob c = NOCHAR; 630103285Sikob } 631103285Sikob else 632103285Sikob cmntcnt--; 633113584Ssimokawa } 634113584Ssimokawa else if (cmntcnt > 0) 635113584Ssimokawa { 636113584Ssimokawa c = NOCHAR; 637113584Ssimokawa } 638103285Sikob else if (c == '<') 639103285Sikob { 640103285Sikob char *ptr = p; 641103285Sikob 642103285Sikob anglecnt++; 643113584Ssimokawa while (isascii(*ptr) && isspace(*ptr)) 644113584Ssimokawa ptr++; 645113584Ssimokawa if (*ptr == '@') 646113584Ssimokawa route_syntax = TRUE; 647103285Sikob } 648118293Ssimokawa else if (c == '>') 649118293Ssimokawa { 650118293Ssimokawa if (anglecnt <= 0) 651118293Ssimokawa { 652118293Ssimokawa usrerr("653 Unbalanced '>'"); 653103285Sikob c = NOCHAR; 654103285Sikob } 655110593Ssimokawa else 656110593Ssimokawa anglecnt--; 657103285Sikob route_syntax = FALSE; 658103285Sikob } 659103285Sikob else if (delim == ' ' && isascii(c) && isspace(c)) 660103285Sikob c = ' '; 661103285Sikob 662103285Sikob if (c == NOCHAR) 663103285Sikob continue; 664103285Sikob 665103285Sikob /* see if this is end of input */ 666118293Ssimokawa if (c == delim && anglecnt <= 0 && state != QST) 667118293Ssimokawa break; 668103285Sikob 669103285Sikob newstate = StateTab[state][toktab[c & 0xff]]; 670103285Sikob if (tTd(22, 101)) 671103285Sikob dprintf("ns=%02o\n", newstate); 672103285Sikob state = newstate & TYPE; 673113584Ssimokawa if (state == ILL) 674103285Sikob { 675113584Ssimokawa if (isascii(c) && isprint(c)) 676113584Ssimokawa usrerr("653 Illegal character %c", c); 677113584Ssimokawa else 678113584Ssimokawa usrerr("653 Illegal character 0x%02x", c); 679103285Sikob } 680103285Sikob if (bitset(M, newstate)) 681103285Sikob c = NOCHAR; 682116376Ssimokawa if (bitset(B, newstate)) 683116376Ssimokawa break; 684103285Sikob } 685103285Sikob 686103285Sikob /* new token */ 687103285Sikob if (tok != q) 688103285Sikob { 689103285Sikob *q++ = '\0'; 690103285Sikob if (tTd(22, 36)) 691103285Sikob { 692113584Ssimokawa dprintf("tok="); 693103285Sikob xputs(tok); 694103285Sikob dprintf("\n"); 695129541Sdfr } 696103285Sikob if (avp >= &av[MAXATOM]) 697113584Ssimokawa { 698113584Ssimokawa usrerr("553 5.1.0 prescan: too many tokens"); 699113584Ssimokawa goto returnnull; 700113584Ssimokawa } 701108527Ssimokawa if (q - tok > MAXNAME) 702108527Ssimokawa { 703113584Ssimokawa usrerr("553 5.1.0 prescan: token too long"); 704129585Sdfr goto returnnull; 705113584Ssimokawa } 706113584Ssimokawa *avp++ = tok; 707113584Ssimokawa } 708113584Ssimokawa } while (c != '\0' && (c != delim || anglecnt > 0)); 709109736Ssimokawa *avp = NULL; 710109736Ssimokawa p--; 711113584Ssimokawa if (delimptr != NULL) 712113584Ssimokawa *delimptr = p; 713108527Ssimokawa if (tTd(22, 12)) 714108527Ssimokawa { 715108527Ssimokawa dprintf("prescan==>"); 716113584Ssimokawa printav(av); 717108527Ssimokawa } 718108527Ssimokawa CurEnv->e_to = saveto; 719103285Sikob if (av[0] == NULL) 720113584Ssimokawa { 721108527Ssimokawa if (tTd(22, 1)) 722108527Ssimokawa dprintf("prescan: null leading token\n"); 723108527Ssimokawa return NULL; 724113584Ssimokawa } 725108527Ssimokawa return av; 726108527Ssimokawa} 727103285Sikob/* 728109814Ssimokawa** REWRITE -- apply rewrite rules to token vector. 729109814Ssimokawa** 730109814Ssimokawa** This routine is an ordered production system. Each rewrite 731109814Ssimokawa** rule has a LHS (called the pattern) and a RHS (called the 732103285Sikob** rewrite); 'rwr' points the the current rewrite rule. 733109814Ssimokawa** 734109814Ssimokawa** For each rewrite rule, 'avp' points the address vector we 735103285Sikob** are trying to match against, and 'pvp' points to the pattern. 736103285Sikob** If pvp points to a special match value (MATCHZANY, MATCHANY, 737103285Sikob** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 738103285Sikob** matched is saved away in the match vector (pointed to by 'mvp'). 739103285Sikob** 740103285Sikob** When a match between avp & pvp does not match, we try to 741103285Sikob** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 742103285Sikob** we must also back out the match in mvp. If we reach a 743103285Sikob** MATCHANY or MATCHZANY we just extend the match and start 744113584Ssimokawa** over again. 745103285Sikob** 746113584Ssimokawa** When we finally match, we rewrite the address vector 747113584Ssimokawa** and try over again. 748113584Ssimokawa** 749103285Sikob** Parameters: 750103285Sikob** pvp -- pointer to token vector. 751103285Sikob** ruleset -- the ruleset to use for rewriting. 752103285Sikob** reclevel -- recursion level (to catch loops). 753106790Ssimokawa** e -- the current envelope. 754113584Ssimokawa** 755113584Ssimokawa** Returns: 756108530Ssimokawa** A status code. If EX_TEMPFAIL, higher level code should 757108530Ssimokawa** attempt recovery. 758103285Sikob** 759108530Ssimokawa** Side Effects: 760103285Sikob** pvp is modified. 761106790Ssimokawa*/ 762106790Ssimokawa 763106790Ssimokawastruct match 764103285Sikob{ 765103285Sikob char **match_first; /* first token matched */ 766103285Sikob char **match_last; /* last token matched */ 767103285Sikob char **match_pattern; /* pointer to pattern */ 768103285Sikob}; 769106790Ssimokawa 770129585Sdfr#define MAXMATCH 9 /* max params per rewrite */ 771106790Ssimokawa 772103285Sikob 773103285Sikobint 774103285Sikobrewrite(pvp, ruleset, reclevel, e) 775103285Sikob char **pvp; 776103285Sikob int ruleset; 777108527Ssimokawa int reclevel; 778108527Ssimokawa register ENVELOPE *e; 779108527Ssimokawa{ 780108527Ssimokawa register char *ap; /* address pointer */ 781108527Ssimokawa register char *rp; /* rewrite pointer */ 782113584Ssimokawa register char *rulename; /* ruleset name */ 783113584Ssimokawa register char *prefix; 784113584Ssimokawa register char **avp; /* address vector pointer */ 785113584Ssimokawa register char **rvp; /* rewrite vector pointer */ 786108527Ssimokawa register struct match *mlp; /* cur ptr into mlist */ 787108527Ssimokawa register struct rewrite *rwr; /* pointer to current rewrite rule */ 788108527Ssimokawa int ruleno; /* current rule number */ 789108527Ssimokawa int rstat = EX_OK; /* return status */ 790108527Ssimokawa int loopcount; 791108527Ssimokawa struct match mlist[MAXMATCH]; /* stores match on LHS */ 792108527Ssimokawa char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 793108527Ssimokawa char buf[MAXLINE]; 794108527Ssimokawa char name[6]; 795108527Ssimokawa 796108527Ssimokawa if (ruleset < 0 || ruleset >= MAXRWSETS) 797108527Ssimokawa { 798108527Ssimokawa syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 799108527Ssimokawa return EX_CONFIG; 800108527Ssimokawa } 801108655Ssimokawa rulename = RuleSetNames[ruleset]; 802108655Ssimokawa if (rulename == NULL) 803108655Ssimokawa { 804108655Ssimokawa snprintf(name, sizeof name, "%d", ruleset); 805108655Ssimokawa rulename = name; 806108655Ssimokawa } 807106790Ssimokawa if (OpMode == MD_TEST) 808113584Ssimokawa prefix = ""; 809113584Ssimokawa else 810113584Ssimokawa prefix = "rewrite: ruleset "; 811120660Ssimokawa if (OpMode == MD_TEST) 812113584Ssimokawa { 813113584Ssimokawa printf("%s%-16.16s input:", prefix, rulename); 814113584Ssimokawa printav(pvp); 815113584Ssimokawa } 816113584Ssimokawa else if (tTd(21, 1)) 817113584Ssimokawa { 818113584Ssimokawa dprintf("%s%-16.16s input:", prefix, rulename); 819113584Ssimokawa printav(pvp); 820113584Ssimokawa } 821113584Ssimokawa if (reclevel++ > MaxRuleRecursion) 822113584Ssimokawa { 823113584Ssimokawa syserr("rewrite: excessive recursion (max %d), ruleset %s", 824113584Ssimokawa MaxRuleRecursion, rulename); 825113584Ssimokawa return EX_CONFIG; 826113584Ssimokawa } 827113584Ssimokawa if (pvp == NULL) 828113584Ssimokawa return EX_USAGE; 829113584Ssimokawa 830113584Ssimokawa /* 831113584Ssimokawa ** Run through the list of rewrite rules, applying 832113584Ssimokawa ** any that match. 833113584Ssimokawa */ 834113584Ssimokawa 835113584Ssimokawa ruleno = 1; 836113584Ssimokawa loopcount = 0; 837113584Ssimokawa for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 838113584Ssimokawa { 839113584Ssimokawa int status; 840106790Ssimokawa 841103285Sikob /* if already canonical, quit now */ 842103285Sikob if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 843120660Ssimokawa break; 844103285Sikob 845129585Sdfr if (tTd(21, 12)) 846103285Sikob { 847103285Sikob if (tTd(21, 15)) 848120660Ssimokawa dprintf("-----trying rule (line %d):", 849103285Sikob rwr->r_line); 850120660Ssimokawa else 851129585Sdfr dprintf("-----trying rule:"); 852103285Sikob printav(rwr->r_lhs); 853108655Ssimokawa } 854103285Sikob 855103285Sikob /* try to match on this rule */ 856103285Sikob mlp = mlist; 857103285Sikob rvp = rwr->r_lhs; 858103285Sikob avp = pvp; 859103285Sikob if (++loopcount > 100) 860103285Sikob { 861103285Sikob syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 862103285Sikob rulename, ruleno); 863103285Sikob if (tTd(21, 1)) 864103285Sikob { 865103285Sikob dprintf("workspace: "); 866103285Sikob printav(pvp); 867103285Sikob } 868103285Sikob break; 869103285Sikob } 870103285Sikob 871103285Sikob while ((ap = *avp) != NULL || *rvp != NULL) 872103285Sikob { 873103285Sikob rp = *rvp; 874103285Sikob if (tTd(21, 35)) 875103285Sikob { 876103285Sikob dprintf("ADVANCE rp="); 877103285Sikob xputs(rp); 878103285Sikob dprintf(", ap="); 879103285Sikob xputs(ap); 880120660Ssimokawa dprintf("\n"); 881103285Sikob } 882103285Sikob if (rp == NULL) 883120660Ssimokawa { 884103285Sikob /* end-of-pattern before end-of-address */ 885113584Ssimokawa goto backup; 886119155Ssimokawa } 887119155Ssimokawa if (ap == NULL && (*rp & 0377) != MATCHZANY && 888119155Ssimokawa (*rp & 0377) != MATCHZERO) 889119155Ssimokawa { 890119155Ssimokawa /* end-of-input with patterns left */ 891119155Ssimokawa goto backup; 892120660Ssimokawa } 893103285Sikob 894103285Sikob switch (*rp & 0377) 895113584Ssimokawa { 896103285Sikob case MATCHCLASS: 897103285Sikob /* match any phrase in a class */ 898119155Ssimokawa mlp->match_pattern = rvp; 899119155Ssimokawa mlp->match_first = avp; 900103285Sikob extendclass: 901103285Sikob ap = *avp; 902103285Sikob if (ap == NULL) 903113584Ssimokawa goto backup; 904103285Sikob mlp->match_last = avp++; 905103285Sikob cataddr(mlp->match_first, mlp->match_last, 906103285Sikob buf, sizeof buf, '\0'); 907103285Sikob if (!wordinclass(buf, rp[1])) 908113584Ssimokawa { 909113584Ssimokawa if (tTd(21, 36)) 910119155Ssimokawa { 911113584Ssimokawa dprintf("EXTEND rp="); 912103285Sikob xputs(rp); 913103285Sikob dprintf(", ap="); 914113584Ssimokawa xputs(ap); 915113584Ssimokawa dprintf("\n"); 916103285Sikob } 917113584Ssimokawa goto extendclass; 918113584Ssimokawa } 919113584Ssimokawa if (tTd(21, 36)) 920113584Ssimokawa dprintf("CLMATCH\n"); 921119155Ssimokawa mlp++; 922113584Ssimokawa break; 923103285Sikob 924111942Ssimokawa case MATCHNCLASS: 925103285Sikob /* match any token not in a class */ 926103285Sikob if (wordinclass(ap, rp[1])) 927120660Ssimokawa goto backup; 928113584Ssimokawa 929113584Ssimokawa /* FALLTHROUGH */ 930103285Sikob 931113584Ssimokawa case MATCHONE: 932120660Ssimokawa case MATCHANY: 933113584Ssimokawa /* match exactly one token */ 934113584Ssimokawa mlp->match_pattern = rvp; 935103285Sikob mlp->match_first = avp; 936111942Ssimokawa mlp->match_last = avp++; 937113584Ssimokawa mlp++; 938113584Ssimokawa break; 939113584Ssimokawa 940113584Ssimokawa case MATCHZANY: 941113584Ssimokawa /* match zero or more tokens */ 942113584Ssimokawa mlp->match_pattern = rvp; 943113584Ssimokawa mlp->match_first = avp; 944113584Ssimokawa mlp->match_last = avp - 1; 945113584Ssimokawa mlp++; 946113584Ssimokawa break; 947113584Ssimokawa 948111942Ssimokawa case MATCHZERO: 949111942Ssimokawa /* match zero tokens */ 950113584Ssimokawa break; 951113584Ssimokawa 952111942Ssimokawa case MACRODEXPAND: 953111942Ssimokawa /* 954113584Ssimokawa ** Match against run-time macro. 955111942Ssimokawa ** This algorithm is broken for the 956111942Ssimokawa ** general case (no recursive macros, 957111942Ssimokawa ** improper tokenization) but should 958111942Ssimokawa ** work for the usual cases. 959103285Sikob */ 960113584Ssimokawa 961113584Ssimokawa ap = macvalue(rp[1], e); 962113584Ssimokawa mlp->match_first = avp; 963113584Ssimokawa if (tTd(21, 2)) 964113584Ssimokawa dprintf("rewrite: LHS $&%s => \"%s\"\n", 965113584Ssimokawa macname(rp[1]), 966113584Ssimokawa ap == NULL ? "(NULL)" : ap); 967113584Ssimokawa 968113584Ssimokawa if (ap == NULL) 969103285Sikob break; 970108655Ssimokawa while (*ap != '\0') 971108655Ssimokawa { 972108655Ssimokawa if (*avp == NULL || 973108655Ssimokawa strncasecmp(ap, *avp, strlen(*avp)) != 0) 974108655Ssimokawa { 975103285Sikob /* no match */ 976103285Sikob avp = mlp->match_first; 977113584Ssimokawa goto backup; 978113584Ssimokawa } 979113584Ssimokawa ap += strlen(*avp++); 980113584Ssimokawa } 981103285Sikob 982103285Sikob /* match */ 983103285Sikob break; 984103285Sikob 985103285Sikob default: 986113584Ssimokawa /* must have exact match */ 987103285Sikob if (sm_strcasecmp(rp, ap)) 988103285Sikob goto backup; 989103285Sikob avp++; 990103285Sikob break; 991103285Sikob } 992103285Sikob 993107653Ssimokawa /* successful match on this token */ 994103285Sikob rvp++; 995103285Sikob continue; 996103285Sikob 997103285Sikob backup: 998113584Ssimokawa /* match failed -- back up */ 999113584Ssimokawa while (--mlp >= mlist) 1000103285Sikob { 1001103285Sikob rvp = mlp->match_pattern; 1002103285Sikob rp = *rvp; 1003103285Sikob avp = mlp->match_last + 1; 1004107653Ssimokawa ap = *avp; 1005107653Ssimokawa 1006103285Sikob if (tTd(21, 36)) 1007113584Ssimokawa { 1008103285Sikob dprintf("BACKUP rp="); 1009103285Sikob xputs(rp); 1010103285Sikob dprintf(", ap="); 1011106790Ssimokawa xputs(ap); 1012103285Sikob dprintf("\n"); 1013103285Sikob } 1014103285Sikob 1015103285Sikob if (ap == NULL) 1016106790Ssimokawa { 1017106790Ssimokawa /* run off the end -- back up again */ 1018106790Ssimokawa continue; 1019103285Sikob } 1020103285Sikob if ((*rp & 0377) == MATCHANY || 1021103285Sikob (*rp & 0377) == MATCHZANY) 1022103285Sikob { 1023103285Sikob /* extend binding and continue */ 1024106790Ssimokawa mlp->match_last = avp++; 1025106790Ssimokawa rvp++; 1026106790Ssimokawa mlp++; 1027103285Sikob break; 1028103285Sikob } 1029103285Sikob if ((*rp & 0377) == MATCHCLASS) 1030103285Sikob { 1031103285Sikob /* extend binding and try again */ 1032106790Ssimokawa mlp->match_last = avp; 1033106790Ssimokawa goto extendclass; 1034106790Ssimokawa } 1035103285Sikob } 1036113584Ssimokawa 1037103285Sikob if (mlp < mlist) 1038120660Ssimokawa { 1039103285Sikob /* total failure to match */ 1040129585Sdfr break; 1041113584Ssimokawa } 1042103285Sikob } 1043103285Sikob 1044113584Ssimokawa /* 1045103285Sikob ** See if we successfully matched 1046103285Sikob */ 1047113584Ssimokawa 1048103285Sikob if (mlp < mlist || *rvp != NULL) 1049103285Sikob { 1050113584Ssimokawa if (tTd(21, 10)) 1051103285Sikob dprintf("----- rule fails\n"); 1052103285Sikob rwr = rwr->r_next; 1053103285Sikob ruleno++; 1054103285Sikob loopcount = 0; 1055103285Sikob continue; 1056103285Sikob } 1057113584Ssimokawa 1058113584Ssimokawa rvp = rwr->r_rhs; 1059103285Sikob if (tTd(21, 12)) 1060103285Sikob { 1061113584Ssimokawa dprintf("-----rule matches:"); 1062113584Ssimokawa printav(rvp); 1063103285Sikob } 1064103285Sikob 1065103285Sikob rp = *rvp; 1066103285Sikob if (rp != NULL) 1067113584Ssimokawa { 1068113584Ssimokawa if ((*rp & 0377) == CANONUSER) 1069113584Ssimokawa { 1070119155Ssimokawa rvp++; 1071119155Ssimokawa rwr = rwr->r_next; 1072119155Ssimokawa ruleno++; 1073103285Sikob loopcount = 0; 1074113584Ssimokawa } 1075113584Ssimokawa else if ((*rp & 0377) == CANONHOST) 1076103285Sikob { 1077103285Sikob rvp++; 1078103285Sikob rwr = NULL; 1079103285Sikob } 1080103285Sikob } 1081103285Sikob 1082113584Ssimokawa /* substitute */ 1083103285Sikob for (avp = npvp; *rvp != NULL; rvp++) 1084110577Ssimokawa { 1085103285Sikob register struct match *m; 1086103285Sikob register char **pp; 1087103285Sikob 1088103285Sikob rp = *rvp; 1089103285Sikob if ((*rp & 0377) == MATCHREPL) 1090110577Ssimokawa { 1091103285Sikob /* substitute from LHS */ 1092103285Sikob m = &mlist[rp[1] - '1']; 1093103285Sikob if (m < mlist || m >= mlp) 1094103285Sikob { 1095103285Sikob syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 1096103285Sikob rulename, rp[1]); 1097103285Sikob return EX_CONFIG; 1098103285Sikob } 1099103285Sikob if (tTd(21, 15)) 1100103285Sikob { 1101103285Sikob dprintf("$%c:", rp[1]); 1102103285Sikob pp = m->match_first; 1103103285Sikob while (pp <= m->match_last) 1104103285Sikob { 1105103285Sikob dprintf(" %lx=\"", 1106103285Sikob (u_long) *pp); 1107103285Sikob (void) dflush(); 1108103285Sikob dprintf("%s\"", *pp++); 1109103285Sikob } 1110103285Sikob dprintf("\n"); 1111103285Sikob } 1112103285Sikob pp = m->match_first; 1113103285Sikob while (pp <= m->match_last) 1114103285Sikob { 1115110577Ssimokawa if (avp >= &npvp[MAXATOM]) 1116103285Sikob { 1117113584Ssimokawa syserr("554 5.3.0 rewrite: expansion too long"); 1118119289Ssimokawa return EX_DATAERR; 1119113584Ssimokawa } 1120113584Ssimokawa *avp++ = *pp++; 1121119289Ssimokawa } 1122113584Ssimokawa } 1123113584Ssimokawa else 1124114218Ssimokawa { 1125114218Ssimokawa /* some sort of replacement */ 1126114218Ssimokawa if (avp >= &npvp[MAXATOM]) 1127114218Ssimokawa { 1128114218Ssimokawa toolong: 1129114218Ssimokawa syserr("554 5.3.0 rewrite: expansion too long"); 1130114224Ssimokawa return EX_DATAERR; 1131120660Ssimokawa } 1132114218Ssimokawa if ((*rp & 0377) != MACRODEXPAND) 1133114224Ssimokawa { 1134114218Ssimokawa /* vanilla replacement */ 1135114218Ssimokawa *avp++ = rp; 1136114218Ssimokawa } 1137114218Ssimokawa else 1138120660Ssimokawa { 1139113584Ssimokawa /* $&x replacement */ 1140114218Ssimokawa char *mval = macvalue(rp[1], e); 1141103285Sikob char **xpvp; 1142110577Ssimokawa int trsize = 0; 1143110577Ssimokawa static size_t pvpb1_size = 0; 1144110577Ssimokawa static char **pvpb1 = NULL; 1145110577Ssimokawa char pvpbuf[PSBUFSIZE]; 1146113584Ssimokawa 1147113584Ssimokawa if (tTd(21, 2)) 1148103285Sikob dprintf("rewrite: RHS $&%s => \"%s\"\n", 1149110269Ssimokawa macname(rp[1]), 1150103285Sikob mval == NULL ? "(NULL)" : mval); 1151103285Sikob if (mval == NULL || *mval == '\0') 1152103285Sikob continue; 1153103285Sikob 1154103285Sikob /* save the remainder of the input */ 1155111956Ssimokawa for (xpvp = pvp; *xpvp != NULL; xpvp++) 1156111956Ssimokawa trsize += sizeof *xpvp; 1157111956Ssimokawa if ((size_t) trsize > pvpb1_size) 1158111956Ssimokawa { 1159111956Ssimokawa if (pvpb1 != NULL) 1160111956Ssimokawa free(pvpb1); 1161103285Sikob pvpb1 = (char **)xalloc(trsize); 1162103285Sikob pvpb1_size = trsize; 1163103285Sikob } 1164103285Sikob 1165103285Sikob memmove((char *) pvpb1, 1166103285Sikob (char *) pvp, 1167103285Sikob trsize); 1168103285Sikob 1169103285Sikob /* scan the new replacement */ 1170106790Ssimokawa xpvp = prescan(mval, '\0', pvpbuf, 1171106790Ssimokawa sizeof pvpbuf, NULL, 1172106790Ssimokawa NULL); 1173103285Sikob if (xpvp == NULL) 1174103285Sikob { 1175113584Ssimokawa /* prescan pre-printed error */ 1176103285Sikob return EX_DATAERR; 1177108527Ssimokawa } 1178108527Ssimokawa 1179108527Ssimokawa /* insert it into the output stream */ 1180113584Ssimokawa while (*xpvp != NULL) 1181103285Sikob { 1182113584Ssimokawa if (tTd(21, 19)) 1183113584Ssimokawa dprintf(" ... %s\n", 1184113584Ssimokawa *xpvp); 1185113584Ssimokawa *avp++ = newstr(*xpvp); 1186113584Ssimokawa if (avp >= &npvp[MAXATOM]) 1187113584Ssimokawa goto toolong; 1188113584Ssimokawa xpvp++; 1189103285Sikob } 1190103285Sikob if (tTd(21, 19)) 1191103285Sikob dprintf(" ... DONE\n"); 1192113584Ssimokawa 1193110195Ssimokawa /* restore the old trailing input */ 1194103285Sikob memmove((char *) pvp, 1195108527Ssimokawa (char *) pvpb1, 1196103285Sikob trsize); 1197106790Ssimokawa } 1198106790Ssimokawa } 1199113584Ssimokawa } 1200103285Sikob *avp++ = NULL; 1201103285Sikob 1202103285Sikob /* 1203108642Ssimokawa ** Check for any hostname/keyword lookups. 1204108642Ssimokawa */ 1205108642Ssimokawa 1206108642Ssimokawa for (rvp = npvp; *rvp != NULL; rvp++) 1207113584Ssimokawa { 1208113584Ssimokawa char **hbrvp; 1209113584Ssimokawa char **xpvp; 1210113584Ssimokawa int trsize; 1211113584Ssimokawa char *replac; 1212113584Ssimokawa int endtoken; 1213113584Ssimokawa STAB *map; 1214113584Ssimokawa char *mapname; 1215113584Ssimokawa char **key_rvp; 1216113584Ssimokawa char **arg_rvp; 1217117126Sscottl char **default_rvp; 1218127468Ssimokawa char cbuf[MAXNAME + 1]; 1219117126Sscottl char *pvpb1[MAXATOM + 1]; 1220117228Ssimokawa char *argvect[10]; 1221117228Ssimokawa char pvpbuf[PSBUFSIZE]; 1222117228Ssimokawa char *nullpvp[1]; 1223113584Ssimokawa 1224113584Ssimokawa if ((**rvp & 0377) != HOSTBEGIN && 1225103285Sikob (**rvp & 0377) != LOOKUPBEGIN) 1226103285Sikob continue; 1227103285Sikob 1228103285Sikob /* 1229103285Sikob ** Got a hostname/keyword lookup. 1230113584Ssimokawa ** 1231103285Sikob ** This could be optimized fairly easily. 1232109379Ssimokawa */ 1233103285Sikob 1234103285Sikob hbrvp = rvp; 1235109379Ssimokawa if ((**rvp & 0377) == HOSTBEGIN) 1236113584Ssimokawa { 1237113584Ssimokawa endtoken = HOSTEND; 1238113584Ssimokawa mapname = "host"; 1239113584Ssimokawa } 1240113584Ssimokawa else 1241124836Ssimokawa { 1242103285Sikob endtoken = LOOKUPEND; 1243103285Sikob mapname = *++rvp; 1244103285Sikob } 1245103285Sikob map = stab(mapname, ST_MAP, ST_FIND); 1246103285Sikob if (map == NULL) 1247113584Ssimokawa syserr("554 5.3.0 rewrite: map %s not found", mapname); 1248113584Ssimokawa 1249113584Ssimokawa /* extract the match part */ 1250113584Ssimokawa key_rvp = ++rvp; 1251113584Ssimokawa default_rvp = NULL; 1252113584Ssimokawa arg_rvp = argvect; 1253113584Ssimokawa xpvp = NULL; 1254113584Ssimokawa replac = pvpbuf; 1255113584Ssimokawa while (*rvp != NULL && (**rvp & 0377) != endtoken) 1256113584Ssimokawa { 1257113584Ssimokawa int nodetype = **rvp & 0377; 1258103285Sikob 1259113584Ssimokawa if (nodetype != CANONHOST && nodetype != CANONUSER) 1260108530Ssimokawa { 1261108530Ssimokawa rvp++; 1262108530Ssimokawa continue; 1263108530Ssimokawa } 1264108530Ssimokawa 1265108530Ssimokawa *rvp++ = NULL; 1266103285Sikob 1267103285Sikob if (xpvp != NULL) 1268103285Sikob { 1269103285Sikob cataddr(xpvp, NULL, replac, 1270103285Sikob &pvpbuf[sizeof pvpbuf] - replac, 1271108642Ssimokawa '\0'); 1272108642Ssimokawa *++arg_rvp = replac; 1273108642Ssimokawa replac += strlen(replac) + 1; 1274103285Sikob xpvp = NULL; 1275103285Sikob } 1276108527Ssimokawa switch (nodetype) 1277103285Sikob { 1278106790Ssimokawa case CANONHOST: 1279106790Ssimokawa xpvp = rvp; 1280106790Ssimokawa break; 1281103285Sikob 1282103285Sikob case CANONUSER: 1283113584Ssimokawa default_rvp = rvp; 1284109890Ssimokawa break; 1285113584Ssimokawa } 1286113584Ssimokawa } 1287103285Sikob if (*rvp != NULL) 1288103285Sikob *rvp++ = NULL; 1289109890Ssimokawa if (xpvp != NULL) 1290113584Ssimokawa { 1291103285Sikob cataddr(xpvp, NULL, replac, 1292103285Sikob &pvpbuf[sizeof pvpbuf] - replac, 1293103285Sikob '\0'); 1294103285Sikob *++arg_rvp = replac; 1295106790Ssimokawa } 1296106790Ssimokawa *++arg_rvp = NULL; 1297106790Ssimokawa 1298103285Sikob /* save the remainder of the input string */ 1299103285Sikob trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1300113584Ssimokawa memmove((char *) pvpb1, (char *) rvp, trsize); 1301103285Sikob 1302103285Sikob /* look it up */ 1303103285Sikob cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 1304103285Sikob map == NULL ? '\0' : map->s_map.map_spacesub); 1305109890Ssimokawa argvect[0] = cbuf; 1306113584Ssimokawa replac = map_lookup(map, cbuf, argvect, &rstat, e); 1307103285Sikob 1308103285Sikob /* if no replacement, use default */ 1309103285Sikob if (replac == NULL && default_rvp != NULL) 1310103285Sikob { 1311106790Ssimokawa /* create the default */ 1312113584Ssimokawa cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0'); 1313106790Ssimokawa replac = cbuf; 1314129585Sdfr } 1315103285Sikob 1316113584Ssimokawa if (replac == NULL) 1317103285Sikob { 1318103285Sikob xpvp = key_rvp; 1319103285Sikob } 1320103285Sikob else if (*replac == '\0') 1321106790Ssimokawa { 1322106790Ssimokawa /* null replacement */ 1323103285Sikob nullpvp[0] = NULL; 1324103285Sikob xpvp = nullpvp; 1325113584Ssimokawa } 1326129585Sdfr else 1327103285Sikob { 1328120660Ssimokawa /* scan the new replacement */ 1329103285Sikob xpvp = prescan(replac, '\0', pvpbuf, 1330103285Sikob sizeof pvpbuf, NULL, NULL); 1331103285Sikob if (xpvp == NULL) 1332103285Sikob { 1333103285Sikob /* prescan already printed error */ 1334103285Sikob return EX_DATAERR; 1335103285Sikob } 1336103285Sikob } 1337103285Sikob 1338103285Sikob /* append it to the token list */ 1339103285Sikob for (avp = hbrvp; *xpvp != NULL; xpvp++) 1340103285Sikob { 1341123740Speter *avp++ = newstr(*xpvp); 1342103285Sikob if (avp >= &npvp[MAXATOM]) 1343103285Sikob goto toolong; 1344103285Sikob } 1345103285Sikob 1346103285Sikob /* restore the old trailing information */ 1347103285Sikob rvp = avp - 1; 1348103285Sikob for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1349103285Sikob if (avp >= &npvp[MAXATOM]) 1350103285Sikob goto toolong; 1351103285Sikob } 1352113584Ssimokawa 1353113584Ssimokawa /* 1354103285Sikob ** Check for subroutine calls. 1355103285Sikob */ 1356103285Sikob 1357109892Ssimokawa status = callsubr(npvp, reclevel, e); 1358113584Ssimokawa if (rstat == EX_OK || status == EX_TEMPFAIL) 1359113584Ssimokawa rstat = status; 1360113584Ssimokawa 1361113584Ssimokawa /* copy vector back into original space. */ 1362103285Sikob for (avp = npvp; *avp++ != NULL;) 1363103285Sikob continue; 1364113584Ssimokawa memmove((char *) pvp, (char *) npvp, 1365113584Ssimokawa (int) (avp - npvp) * sizeof *avp); 1366113584Ssimokawa 1367109280Ssimokawa if (tTd(21, 4)) 1368113584Ssimokawa { 1369113584Ssimokawa dprintf("rewritten as:"); 1370113584Ssimokawa printav(pvp); 1371103285Sikob } 1372103285Sikob } 1373103285Sikob 1374103285Sikob if (OpMode == MD_TEST) 1375113584Ssimokawa { 1376113584Ssimokawa printf("%s%-16.16s returns:", prefix, rulename); 1377103285Sikob printav(pvp); 1378103285Sikob } 1379106790Ssimokawa else if (tTd(21, 1)) 1380106790Ssimokawa { 1381106790Ssimokawa dprintf("%s%-16.16s returns:", prefix, rulename); 1382103285Sikob printav(pvp); 1383103285Sikob } 1384109892Ssimokawa return rstat; 1385129585Sdfr} 1386103285Sikob/* 1387120660Ssimokawa** CALLSUBR -- call subroutines in rewrite vector 1388103285Sikob** 1389103285Sikob** Parameters: 1390103285Sikob** pvp -- pointer to token vector. 1391103285Sikob** reclevel -- the current recursion level. 1392103285Sikob** e -- the current envelope. 1393103285Sikob** 1394103285Sikob** Returns: 1395103285Sikob** The status from the subroutine call. 1396103285Sikob** 1397103285Sikob** Side Effects: 1398103285Sikob** pvp is modified. 1399103285Sikob*/ 1400103285Sikob 1401103285Sikobstatic int 1402123740Spetercallsubr(pvp, reclevel, e) 1403103285Sikob char **pvp; 1404103285Sikob int reclevel; 1405103285Sikob ENVELOPE *e; 1406103285Sikob{ 1407103285Sikob char **avp; 1408103285Sikob char **rvp; 1409103285Sikob register int i; 1410103285Sikob int subr; 1411103285Sikob int status; 1412103285Sikob int rstat = EX_OK; 1413103285Sikob char *tpvp[MAXATOM + 1]; 1414103285Sikob 1415103285Sikob for (avp = pvp; *avp != NULL; avp++) 1416108642Ssimokawa { 1417103285Sikob if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 1418103285Sikob { 1419103285Sikob stripquotes(avp[1]); 1420103285Sikob subr = strtorwset(avp[1], NULL, ST_FIND); 1421113584Ssimokawa if (subr < 0) 1422113584Ssimokawa { 1423113584Ssimokawa syserr("Unknown ruleset %s", avp[1]); 1424103285Sikob return EX_CONFIG; 1425109892Ssimokawa } 1426109892Ssimokawa 1427113584Ssimokawa if (tTd(21, 3)) 1428113584Ssimokawa dprintf("-----callsubr %s (%d)\n", 1429103285Sikob avp[1], subr); 1430103285Sikob 1431113584Ssimokawa /* 1432113584Ssimokawa ** Take care of possible inner calls first. 1433113584Ssimokawa ** use a full size temporary buffer to avoid 1434113584Ssimokawa ** overflows in rewrite, but strip off the 1435113584Ssimokawa ** subroutine call. 1436113584Ssimokawa */ 1437103285Sikob 1438103285Sikob for (i = 2; avp[i] != NULL; i++) 1439103285Sikob tpvp[i - 2] = avp[i]; 1440103285Sikob tpvp[i - 2] = NULL; 1441113584Ssimokawa 1442113584Ssimokawa status = callsubr(tpvp, reclevel, e); 1443103285Sikob if (rstat == EX_OK || status == EX_TEMPFAIL) 1444113584Ssimokawa rstat = status; 1445113584Ssimokawa 1446103285Sikob /* 1447103285Sikob ** Now we need to call the ruleset specified for 1448103285Sikob ** the subroutine. we can do this with the 1449113584Ssimokawa ** temporary buffer that we set up earlier, 1450103285Sikob ** since it has all the data we want to rewrite. 1451103285Sikob */ 1452103285Sikob 1453103285Sikob status = rewrite(tpvp, subr, reclevel, e); 1454106790Ssimokawa if (rstat == EX_OK || status == EX_TEMPFAIL) 1455106790Ssimokawa rstat = status; 1456113584Ssimokawa 1457109890Ssimokawa /* 1458109890Ssimokawa ** Find length of tpvp and current offset into 1459109890Ssimokawa ** pvp, if the total is greater than MAXATOM, 1460109890Ssimokawa ** then it would overflow the buffer if we copied 1461109890Ssimokawa ** it back in to pvp, in which case we throw a 1462109890Ssimokawa ** fit. 1463113584Ssimokawa */ 1464109890Ssimokawa 1465113584Ssimokawa for (rvp = tpvp; *rvp != NULL; rvp++) 1466113584Ssimokawa continue; 1467113584Ssimokawa if (((rvp - tpvp) + (avp - pvp)) > MAXATOM) 1468109890Ssimokawa { 1469109890Ssimokawa syserr("554 5.3.0 callsubr: expansion too long"); 1470109890Ssimokawa return EX_DATAERR; 1471109890Ssimokawa } 1472109890Ssimokawa 1473113584Ssimokawa /* 1474109890Ssimokawa ** Now we can copy the rewritten code over 1475109890Ssimokawa ** the initial subroutine call in the buffer. 1476109890Ssimokawa */ 1477109890Ssimokawa 1478109890Ssimokawa for (i = 0; tpvp[i] != NULL; i++) 1479109890Ssimokawa avp[i] = tpvp[i]; 1480109890Ssimokawa avp[i] = NULL; 1481109890Ssimokawa 1482109890Ssimokawa /* 1483109890Ssimokawa ** If we got this far, we've processed the left 1484109890Ssimokawa ** most subroutine, and recursively called ourselves 1485109890Ssimokawa ** to handle any other subroutines. We're done. 1486109890Ssimokawa */ 1487106790Ssimokawa 1488103285Sikob break; 1489103285Sikob } 1490103285Sikob } 1491103285Sikob return rstat; 1492103285Sikob} 1493109890Ssimokawa/* 1494129585Sdfr** MAP_LOOKUP -- do lookup in map 1495109890Ssimokawa** 1496109890Ssimokawa** Parameters: 1497103285Sikob** map -- the map to use for the lookup. 1498103285Sikob** key -- the key to look up. 1499109890Ssimokawa** argvect -- arguments to pass to the map lookup. 1500109890Ssimokawa** pstat -- a pointer to an integer in which to store the 1501109890Ssimokawa** status from the lookup. 1502109890Ssimokawa** e -- the current envelope. 1503109179Ssimokawa** 1504109890Ssimokawa** Returns: 1505103285Sikob** The result of the lookup. 1506113584Ssimokawa** NULL -- if there was no data for the given key. 1507109179Ssimokawa*/ 1508109179Ssimokawa 1509103285Sikobstatic char * 1510103285Sikobmap_lookup(smap, key, argvect, pstat, e) 1511103285Sikob STAB *smap; 1512103285Sikob char key[]; 1513109890Ssimokawa char **argvect; 1514109892Ssimokawa int *pstat; 1515109890Ssimokawa ENVELOPE *e; 1516109890Ssimokawa{ 1517109890Ssimokawa auto int status = EX_OK; 1518120660Ssimokawa MAP *map; 1519109890Ssimokawa char *replac; 1520113584Ssimokawa 1521113584Ssimokawa if (smap == NULL) 1522109890Ssimokawa return NULL; 1523109890Ssimokawa 1524109890Ssimokawa map = &smap->s_map; 1525113584Ssimokawa DYNOPENMAP(map); 1526113584Ssimokawa 1527113584Ssimokawa if (e->e_sendmode == SM_DEFER && 1528113584Ssimokawa bitset(MF_DEFER, map->map_mflags)) 1529109892Ssimokawa { 1530109890Ssimokawa /* don't do any map lookups */ 1531113584Ssimokawa if (tTd(60, 1)) 1532113584Ssimokawa dprintf("map_lookup(%s, %s) => DEFERRED\n", 1533109892Ssimokawa smap->s_name, key); 1534113584Ssimokawa *pstat = EX_TEMPFAIL; 1535113584Ssimokawa return NULL; 1536109892Ssimokawa } 1537103285Sikob 1538109890Ssimokawa if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1539109890Ssimokawa stripquotes(key); 1540109890Ssimokawa 1541109403Ssimokawa if (tTd(60, 1)) 1542113584Ssimokawa { 1543113584Ssimokawa dprintf("map_lookup(%s, %s", smap->s_name, key); 1544109890Ssimokawa if (tTd(60, 5)) 1545109890Ssimokawa { 1546113584Ssimokawa int i; 1547113584Ssimokawa 1548113584Ssimokawa for (i = 0; argvect[i] != NULL; i++) 1549109890Ssimokawa dprintf(", %%%d=%s", i, argvect[i]); 1550109890Ssimokawa } 1551109890Ssimokawa dprintf(") => "); 1552113584Ssimokawa } 1553109890Ssimokawa replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1554113584Ssimokawa if (tTd(60, 1)) 1555109403Ssimokawa dprintf("%s (%d)\n", 1556109403Ssimokawa replac != NULL ? replac : "NOT FOUND", 1557109403Ssimokawa status); 1558113584Ssimokawa 1559109890Ssimokawa /* should recover if status == EX_TEMPFAIL */ 1560109890Ssimokawa if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1561113584Ssimokawa { 1562113584Ssimokawa *pstat = EX_TEMPFAIL; 1563113584Ssimokawa if (tTd(60, 1)) 1564109890Ssimokawa dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 1565113584Ssimokawa smap->s_name, key, errno); 1566113584Ssimokawa if (e->e_message == NULL) 1567113584Ssimokawa { 1568113584Ssimokawa char mbuf[320]; 1569109403Ssimokawa 1570109890Ssimokawa snprintf(mbuf, sizeof mbuf, 1571109890Ssimokawa "%.80s map: lookup (%s): deferred", 1572109890Ssimokawa smap->s_name, 1573109890Ssimokawa shortenstring(key, MAXSHORTSTR)); 1574109890Ssimokawa e->e_message = newstr(mbuf); 1575113584Ssimokawa } 1576109890Ssimokawa } 1577109890Ssimokawa if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1578109890Ssimokawa { 1579109356Ssimokawa size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1580109356Ssimokawa static char *rwbuf = NULL; 1581113584Ssimokawa static size_t rwbuflen = 0; 1582109890Ssimokawa 1583109356Ssimokawa if (i > rwbuflen) 1584109356Ssimokawa { 1585109356Ssimokawa if (rwbuf != NULL) 1586113584Ssimokawa free(rwbuf); 1587113584Ssimokawa rwbuflen = i; 1588113584Ssimokawa rwbuf = (char *) xalloc(rwbuflen); 1589113584Ssimokawa } 1590109403Ssimokawa snprintf(rwbuf, rwbuflen, "%s%s", key, map->map_tapp); 1591109403Ssimokawa if (tTd(60, 4)) 1592113584Ssimokawa dprintf("map_lookup tempfail: returning \"%s\"\n", 1593113584Ssimokawa rwbuf); 1594113584Ssimokawa return rwbuf; 1595109403Ssimokawa } 1596109890Ssimokawa return replac; 1597109890Ssimokawa} 1598113584Ssimokawa/* 1599103285Sikob** INITERRMAILERS -- initialize error and discard mailers 1600109890Ssimokawa** 1601103285Sikob** Parameters: 1602103285Sikob** none. 1603106790Ssimokawa** 1604106790Ssimokawa** Returns: 1605113584Ssimokawa** none. 1606103285Sikob** 1607103285Sikob** Side Effects: 1608109890Ssimokawa** initializes error and discard mailers. 1609103285Sikob*/ 1610129585Sdfr 1611109890Ssimokawastatic MAILER discardmailer; 1612113584Ssimokawastatic MAILER errormailer; 1613109890Ssimokawastatic char *discardargv[] = { "DISCARD", NULL }; 1614109890Ssimokawastatic char *errorargv[] = { "ERROR", NULL }; 1615103285Sikob 1616109890Ssimokawavoid 1617109890Ssimokawainiterrmailers() 1618109890Ssimokawa{ 1619109890Ssimokawa if (discardmailer.m_name == NULL) 1620109890Ssimokawa { 1621109890Ssimokawa /* initialize the discard mailer */ 1622108995Ssimokawa discardmailer.m_name = "*discard*"; 1623108995Ssimokawa discardmailer.m_mailer = "DISCARD"; 1624109890Ssimokawa discardmailer.m_argv = discardargv; 1625109890Ssimokawa } 1626109890Ssimokawa if (errormailer.m_name == NULL) 1627113584Ssimokawa { 1628109890Ssimokawa /* initialize the bogus mailer */ 1629109179Ssimokawa errormailer.m_name = "*error*"; 1630109890Ssimokawa errormailer.m_mailer = "ERROR"; 1631103285Sikob errormailer.m_argv = errorargv; 1632103285Sikob } 1633103285Sikob} 1634103285Sikob/* 1635109890Ssimokawa** BUILDADDR -- build address from token vector. 1636109890Ssimokawa** 1637109890Ssimokawa** Parameters: 1638109890Ssimokawa** tv -- token vector. 1639109890Ssimokawa** a -- pointer to address descriptor to fill. 1640109890Ssimokawa** If NULL, one will be allocated. 1641111892Ssimokawa** flags -- info regarding whether this is a sender or 1642111892Ssimokawa** a recipient. 1643109890Ssimokawa** e -- the current envelope. 1644109890Ssimokawa** 1645120660Ssimokawa** Returns: 1646109890Ssimokawa** NULL if there was an error. 1647111942Ssimokawa** 'a' otherwise. 1648113584Ssimokawa** 1649113584Ssimokawa** Side Effects: 1650113584Ssimokawa** fills in 'a' 1651113584Ssimokawa*/ 1652113584Ssimokawa 1653113584Ssimokawastatic struct errcodes 1654113584Ssimokawa{ 1655113584Ssimokawa char *ec_name; /* name of error code */ 1656113584Ssimokawa int ec_code; /* numeric code */ 1657113584Ssimokawa} ErrorCodes[] = 1658111942Ssimokawa{ 1659109890Ssimokawa { "usage", EX_USAGE }, 1660113584Ssimokawa { "nouser", EX_NOUSER }, 1661113584Ssimokawa { "nohost", EX_NOHOST }, 1662109890Ssimokawa { "unavailable", EX_UNAVAILABLE }, 1663109890Ssimokawa { "software", EX_SOFTWARE }, 1664113584Ssimokawa { "tempfail", EX_TEMPFAIL }, 1665103285Sikob { "protocol", EX_PROTOCOL }, 1666109890Ssimokawa#ifdef EX_CONFIG 1667109890Ssimokawa { "config", EX_CONFIG }, 1668109890Ssimokawa#endif /* EX_CONFIG */ 1669103285Sikob { NULL, EX_UNAVAILABLE } 1670113584Ssimokawa}; 1671113584Ssimokawa 1672109890Ssimokawa 1673109890Ssimokawastatic ADDRESS * 1674109890Ssimokawabuildaddr(tv, a, flags, e) 1675109890Ssimokawa register char **tv; 1676109890Ssimokawa register ADDRESS *a; 1677109890Ssimokawa int flags; 1678109890Ssimokawa register ENVELOPE *e; 1679109890Ssimokawa{ 1680109890Ssimokawa struct mailer **mp; 1681113584Ssimokawa register struct mailer *m; 1682113584Ssimokawa register char *p; 1683109890Ssimokawa char *mname; 1684109890Ssimokawa char **hostp; 1685109890Ssimokawa char hbuf[MAXNAME + 1]; 1686109890Ssimokawa static char ubuf[MAXNAME + 2]; 1687109890Ssimokawa 1688109890Ssimokawa if (tTd(24, 5)) 1689113584Ssimokawa { 1690109890Ssimokawa dprintf("buildaddr, flags=%x, tv=", flags); 1691109890Ssimokawa printav(tv); 1692109890Ssimokawa } 1693113584Ssimokawa 1694113584Ssimokawa if (a == NULL) 1695113584Ssimokawa a = (ADDRESS *) xalloc(sizeof *a); 1696103285Sikob memset((char *) a, '\0', sizeof *a); 1697103285Sikob hbuf[0] = '\0'; 1698106790Ssimokawa 1699106790Ssimokawa /* set up default error return flags */ 1700110145Ssimokawa a->q_flags |= DefaultNotify; 1701103285Sikob 1702103285Sikob /* figure out what net/mailer to use */ 1703103285Sikob if (*tv == NULL || (**tv & 0377) != CANONNET) 1704103285Sikob { 1705103285Sikob syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 1706103285Sikobbadaddr: 1707103285Sikob if (ExitStat == EX_TEMPFAIL) 1708103285Sikob a->q_state = QS_QUEUEUP; 1709103285Sikob else 1710103285Sikob { 1711103285Sikob a->q_state = QS_BADADDR; 1712103285Sikob a->q_mailer = &errormailer; 1713103285Sikob } 1714103285Sikob return a; 1715103285Sikob } 1716103285Sikob mname = *++tv; 1717103285Sikob 1718103285Sikob /* extract host and user portions */ 1719103285Sikob if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1720103285Sikob hostp = ++tv; 1721103285Sikob else 1722103285Sikob hostp = NULL; 1723103285Sikob while (*tv != NULL && (**tv & 0377) != CANONUSER) 1724103285Sikob tv++; 1725103285Sikob if (*tv == NULL) 1726116978Ssimokawa { 1727118416Ssimokawa syserr("554 5.3.5 buildaddr: no user"); 1728118416Ssimokawa goto badaddr; 1729116978Ssimokawa } 1730108642Ssimokawa if (tv == hostp) 1731103285Sikob hostp = NULL; 1732103285Sikob else if (hostp != NULL) 1733103285Sikob cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1734108642Ssimokawa cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1735108642Ssimokawa 1736108642Ssimokawa /* save away the host name */ 1737108642Ssimokawa if (strcasecmp(mname, "error") == 0) 1738116978Ssimokawa { 1739116978Ssimokawa /* Set up triplet for use by -bv */ 1740108642Ssimokawa a->q_mailer = &errormailer; 1741108642Ssimokawa a->q_user = newstr(ubuf); 1742129541Sdfr 1743108642Ssimokawa if (hostp != NULL) 1744116978Ssimokawa { 1745116978Ssimokawa register struct errcodes *ep; 1746108642Ssimokawa 1747108642Ssimokawa a->q_host = newstr(hbuf); 1748116978Ssimokawa if (strchr(hbuf, '.') != NULL) 1749116978Ssimokawa { 1750116978Ssimokawa a->q_status = newstr(hbuf); 1751116978Ssimokawa setstat(dsntoexitstat(hbuf)); 1752116978Ssimokawa } 1753116978Ssimokawa else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 1754108642Ssimokawa { 1755108642Ssimokawa setstat(atoi(hbuf)); 1756108642Ssimokawa } 1757108642Ssimokawa else 1758108642Ssimokawa { 1759108642Ssimokawa for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1760108642Ssimokawa if (strcasecmp(ep->ec_name, hbuf) == 0) 1761108642Ssimokawa break; 1762108642Ssimokawa setstat(ep->ec_code); 1763103285Sikob } 1764103285Sikob } 1765129585Sdfr else 1766103285Sikob { 1767129585Sdfr a->q_host = NULL; 1768103285Sikob setstat(EX_UNAVAILABLE); 1769103285Sikob } 1770103285Sikob stripquotes(ubuf); 1771103285Sikob if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 1772103285Sikob { 1773103285Sikob char fmt[16]; 1774103285Sikob int off; 1775103285Sikob 1776103285Sikob if ((off = isenhsc(ubuf + 4, ' ')) > 0) 1777103285Sikob { 1778103285Sikob ubuf[off + 4] = '\0'; 1779103285Sikob off += 5; 1780103285Sikob } 1781103285Sikob else 1782103285Sikob { 1783103285Sikob off = 4; 1784103285Sikob ubuf[3] = '\0'; 1785103285Sikob } 1786103285Sikob (void) snprintf(fmt, sizeof fmt, "%s %%s", ubuf); 1787103285Sikob if (off > 4) 1788103285Sikob usrerr(fmt, ubuf + off); 1789103285Sikob else if (isenhsc(hbuf, '\0') > 0) 1790103285Sikob usrerrenh(hbuf, fmt, ubuf + off); 1791103285Sikob else 1792103285Sikob usrerr(fmt, ubuf + off); 1793103285Sikob /* XXX ubuf[off - 1] = ' '; */ 1794103285Sikob } 1795103285Sikob else 1796103285Sikob { 1797103285Sikob usrerr("553 5.3.0 %s", ubuf); 1798103285Sikob } 1799103285Sikob goto badaddr; 1800111074Ssimokawa } 1801111074Ssimokawa 1802111074Ssimokawa for (mp = Mailer; (m = *mp++) != NULL; ) 1803111074Ssimokawa { 1804111074Ssimokawa if (strcasecmp(m->m_name, mname) == 0) 1805103285Sikob break; 1806103285Sikob } 1807103285Sikob if (m == NULL) 1808103285Sikob { 1809103285Sikob syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 1810103285Sikob goto badaddr; 1811103285Sikob } 1812103285Sikob a->q_mailer = m; 1813103285Sikob 1814103285Sikob /* figure out what host (if any) */ 1815103285Sikob if (hostp == NULL) 1816103285Sikob { 1817110798Ssimokawa if (!bitnset(M_LOCALMAILER, m->m_flags)) 1818116376Ssimokawa { 1819116376Ssimokawa syserr("554 5.3.5 buildaddr: no host"); 1820103285Sikob goto badaddr; 1821111074Ssimokawa } 1822103285Sikob a->q_host = NULL; 1823103285Sikob } 1824103285Sikob else 1825103285Sikob a->q_host = newstr(hbuf); 1826127468Ssimokawa 1827113584Ssimokawa /* figure out the user */ 1828113584Ssimokawa p = ubuf; 1829127468Ssimokawa if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 1830127468Ssimokawa { 1831113584Ssimokawa p++; 1832103285Sikob tv++; 1833109644Ssimokawa a->q_flags |= QNOTREMOTE; 1834109644Ssimokawa } 1835103285Sikob 1836109644Ssimokawa /* do special mapping for local mailer */ 1837109644Ssimokawa if (*p == '"') 1838109644Ssimokawa p++; 1839109644Ssimokawa if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 1840109644Ssimokawa a->q_mailer = m = ProgMailer; 1841109644Ssimokawa else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 1842113584Ssimokawa a->q_mailer = m = FileMailer; 1843103285Sikob else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 1844103285Sikob { 1845103285Sikob /* may be :include: */ 1846103285Sikob stripquotes(ubuf); 1847103285Sikob if (strncasecmp(ubuf, ":include:", 9) == 0) 1848103285Sikob { 1849103285Sikob /* if :include:, don't need further rewriting */ 1850127468Ssimokawa a->q_mailer = m = InclMailer; 1851113584Ssimokawa a->q_user = newstr(&ubuf[9]); 1852113584Ssimokawa return a; 1853127468Ssimokawa } 1854127468Ssimokawa } 1855113584Ssimokawa 1856103285Sikob /* rewrite according recipient mailer rewriting rules */ 1857103285Sikob define('h', a->q_host, e); 1858103285Sikob 1859103285Sikob#if _FFR_ADDR_TYPE 1860103285Sikob /* 1861103285Sikob ** Note, change the 9 to a 10 before removing #if FFR check 1862103285Sikob ** in a future version. 1863103285Sikob */ 1864103285Sikob 1865103285Sikob if (ConfigLevel >= 9 || 1866103285Sikob !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1867103285Sikob#else /* _FFR_ADDR_TYPE */ 1868103285Sikob if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1869103285Sikob#endif /* _FFR_ADDR_TYPE */ 1870106789Ssimokawa { 1871103285Sikob /* sender addresses done later */ 1872103285Sikob (void) rewrite(tv, 2, 0, e); 1873103285Sikob if (m->m_re_rwset > 0) 1874103285Sikob (void) rewrite(tv, m->m_re_rwset, 0, e); 1875103285Sikob } 1876103285Sikob (void) rewrite(tv, 4, 0, e); 1877103285Sikob 1878103285Sikob /* save the result for the command line/RCPT argument */ 1879103285Sikob cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 1880106789Ssimokawa a->q_user = newstr(ubuf); 1881103285Sikob 1882103285Sikob /* 1883129585Sdfr ** Do mapping to lower case as requested by mailer 1884103285Sikob */ 1885103285Sikob 1886103285Sikob if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1887103285Sikob makelower(a->q_host); 1888103285Sikob if (!bitnset(M_USR_UPPER, m->m_flags)) 1889111074Ssimokawa makelower(a->q_user); 1890111074Ssimokawa 1891111787Ssimokawa if (tTd(24, 6)) 1892111787Ssimokawa { 1893111787Ssimokawa dprintf("buildaddr => "); 1894111787Ssimokawa printaddr(a, FALSE); 1895111787Ssimokawa } 1896111787Ssimokawa return a; 1897112523Ssimokawa} 1898112523Ssimokawa/* 1899103285Sikob** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1900103285Sikob** 1901103285Sikob** Parameters: 1902103285Sikob** pvp -- parameter vector to rebuild. 1903113584Ssimokawa** evp -- last parameter to include. Can be NULL to 1904113584Ssimokawa** use entire pvp. 1905113584Ssimokawa** buf -- buffer to build the string into. 1906113584Ssimokawa** sz -- size of buf. 1907113584Ssimokawa** spacesub -- the space separator character; if null, 1908113584Ssimokawa** use SpaceSub. 1909103285Sikob** 1910103285Sikob** Returns: 1911103285Sikob** none. 1912113584Ssimokawa** 1913103285Sikob** Side Effects: 1914103285Sikob** Destroys buf. 1915103285Sikob*/ 1916113584Ssimokawa 1917103285Sikobvoid 1918103285Sikobcataddr(pvp, evp, buf, sz, spacesub) 1919103285Sikob char **pvp; 1920103285Sikob char **evp; 1921113584Ssimokawa char *buf; 1922103285Sikob register int sz; 1923113584Ssimokawa int spacesub; 1924113584Ssimokawa{ 1925113584Ssimokawa bool oatomtok = FALSE; 1926113584Ssimokawa bool natomtok = FALSE; 1927113584Ssimokawa register int i; 1928109736Ssimokawa register char *p; 1929109736Ssimokawa 1930109736Ssimokawa if (sz <= 0) 1931109736Ssimokawa return; 1932103285Sikob 1933129585Sdfr if (spacesub == '\0') 1934113584Ssimokawa spacesub = SpaceSub; 1935113584Ssimokawa 1936113584Ssimokawa if (pvp == NULL) 1937113584Ssimokawa { 1938113584Ssimokawa *buf = '\0'; 1939113584Ssimokawa return; 1940127468Ssimokawa } 1941110269Ssimokawa p = buf; 1942110269Ssimokawa sz -= 2; 1943110269Ssimokawa while (*pvp != NULL && (i = strlen(*pvp)) < sz - 1) 1944110269Ssimokawa { 1945110269Ssimokawa natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 1946110798Ssimokawa if (oatomtok && natomtok) 1947110269Ssimokawa { 1948113584Ssimokawa *p++ = spacesub; 1949113584Ssimokawa --sz; 1950103285Sikob } 1951103285Sikob (void) strlcpy(p, *pvp, sz); 1952103285Sikob oatomtok = natomtok; 1953103285Sikob p += i; 1954103285Sikob sz -= i; 1955103285Sikob if (pvp++ == evp) 1956103285Sikob break; 1957103285Sikob } 1958103285Sikob *p = '\0'; 1959103285Sikob} 1960103285Sikob/* 1961103285Sikob** SAMEADDR -- Determine if two addresses are the same 1962103285Sikob** 1963103285Sikob** This is not just a straight comparison -- if the mailer doesn't 1964103285Sikob** care about the host we just ignore it, etc. 1965103285Sikob** 1966103285Sikob** Parameters: 1967103285Sikob** a, b -- pointers to the internal forms to compare. 1968103285Sikob** 1969103285Sikob** Returns: 1970103285Sikob** TRUE -- they represent the same mailbox. 1971103285Sikob** FALSE -- they don't. 1972103285Sikob** 1973103285Sikob** Side Effects: 1974103285Sikob** none. 1975103285Sikob*/ 1976103285Sikob 1977103285Sikobbool 1978103285Sikobsameaddr(a, b) 1979103285Sikob register ADDRESS *a; 1980103285Sikob register ADDRESS *b; 1981103285Sikob{ 1982103285Sikob register ADDRESS *ca, *cb; 1983103285Sikob 1984103285Sikob /* if they don't have the same mailer, forget it */ 1985103285Sikob if (a->q_mailer != b->q_mailer) 1986113584Ssimokawa return FALSE; 1987113584Ssimokawa 1988113584Ssimokawa /* if the user isn't the same, we can drop out */ 1989113584Ssimokawa if (strcmp(a->q_user, b->q_user) != 0) 1990113584Ssimokawa return FALSE; 1991129585Sdfr 1992113584Ssimokawa /* if we have good uids for both but they differ, these are different */ 1993113584Ssimokawa if (a->q_mailer == ProgMailer) 1994113584Ssimokawa { 1995113584Ssimokawa ca = getctladdr(a); 1996113584Ssimokawa cb = getctladdr(b); 1997113584Ssimokawa if (ca != NULL && cb != NULL && 1998113584Ssimokawa bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1999113584Ssimokawa ca->q_uid != cb->q_uid) 2000113584Ssimokawa return FALSE; 2001113584Ssimokawa } 2002113584Ssimokawa 2003129585Sdfr /* otherwise compare hosts (but be careful for NULL ptrs) */ 2004113584Ssimokawa if (a->q_host == b->q_host) 2005113584Ssimokawa { 2006129585Sdfr /* probably both null pointers */ 2007113584Ssimokawa return TRUE; 2008113584Ssimokawa } 2009113584Ssimokawa if (a->q_host == NULL || b->q_host == NULL) 2010113584Ssimokawa { 2011113584Ssimokawa /* only one is a null pointer */ 2012113584Ssimokawa return FALSE; 2013113584Ssimokawa } 2014113584Ssimokawa if (strcmp(a->q_host, b->q_host) != 0) 2015113584Ssimokawa return FALSE; 2016113584Ssimokawa 2017113584Ssimokawa return TRUE; 2018113584Ssimokawa} 2019113584Ssimokawa/* 2020113584Ssimokawa** PRINTADDR -- print address (for debugging) 2021113584Ssimokawa** 2022113584Ssimokawa** Parameters: 2023113584Ssimokawa** a -- the address to print 2024113584Ssimokawa** follow -- follow the q_next chain. 2025113584Ssimokawa** 2026113584Ssimokawa** Returns: 2027113584Ssimokawa** none. 2028113584Ssimokawa** 2029113584Ssimokawa** Side Effects: 2030113584Ssimokawa** none. 2031103285Sikob*/ 2032103285Sikob 2033103285Sikobstruct qflags 2034103285Sikob{ 2035129585Sdfr char *qf_name; 2036113584Ssimokawa u_long qf_bit; 2037129585Sdfr}; 2038113584Ssimokawa 2039103285Sikobstatic struct qflags AddressFlags[] = 2040103285Sikob{ 2041103285Sikob { "QGOODUID", QGOODUID }, 2042103285Sikob { "QPRIMARY", QPRIMARY }, 2043103285Sikob { "QNOTREMOTE", QNOTREMOTE }, 2044103285Sikob { "QSELFREF", QSELFREF }, 2045113584Ssimokawa { "QBOGUSSHELL", QBOGUSSHELL }, 2046113584Ssimokawa { "QUNSAFEADDR", QUNSAFEADDR }, 2047103285Sikob { "QPINGONSUCCESS", QPINGONSUCCESS }, 2048113584Ssimokawa { "QPINGONFAILURE", QPINGONFAILURE }, 2049113584Ssimokawa { "QPINGONDELAY", QPINGONDELAY }, 2050113584Ssimokawa { "QHASNOTIFY", QHASNOTIFY }, 2051113584Ssimokawa { "QRELAYED", QRELAYED }, 2052113584Ssimokawa { "QEXPANDED", QEXPANDED }, 2053113584Ssimokawa { "QDELIVERED", QDELIVERED }, 2054113584Ssimokawa { "QDELAYED", QDELAYED }, 2055113584Ssimokawa { "QTHISPASS", QTHISPASS }, 2056113584Ssimokawa { "QRCPTOK", QRCPTOK }, 2057113584Ssimokawa { NULL, 0 } 2058113584Ssimokawa}; 2059113584Ssimokawa 2060113584Ssimokawavoid 2061113584Ssimokawaprintaddr(a, follow) 2062113584Ssimokawa register ADDRESS *a; 2063113584Ssimokawa bool follow; 2064103285Sikob{ 2065103285Sikob register MAILER *m; 2066116897Ssimokawa MAILER pseudomailer; 2067103285Sikob register struct qflags *qfp; 2068103285Sikob bool firstone; 2069103285Sikob 2070129585Sdfr if (a == NULL) 2071103285Sikob { 2072103285Sikob printf("[NULL]\n"); 2073103285Sikob return; 2074103285Sikob } 2075103285Sikob 2076103285Sikob while (a != NULL) 2077103285Sikob { 2078103285Sikob printf("%lx=", (u_long) a); 2079103285Sikob (void) fflush(stdout); 2080103285Sikob 2081103285Sikob /* find the mailer -- carefully */ 2082103285Sikob m = a->q_mailer; 2083113584Ssimokawa if (m == NULL) 2084113584Ssimokawa { 2085103285Sikob m = &pseudomailer; 2086103285Sikob m->m_mno = -1; 2087103285Sikob m->m_name = "NULL"; 2088106789Ssimokawa } 2089103285Sikob 2090103285Sikob printf("%s:\n\tmailer %d (%s), host `%s'\n", 2091103285Sikob a->q_paddr == NULL ? "<null>" : a->q_paddr, 2092103285Sikob m->m_mno, m->m_name, 2093103285Sikob a->q_host == NULL ? "<null>" : a->q_host); 2094103285Sikob printf("\tuser `%s', ruser `%s'\n", 2095103285Sikob a->q_user, 2096103285Sikob a->q_ruser == NULL ? "<null>" : a->q_ruser); 2097103285Sikob printf("\tstate="); 2098107653Ssimokawa switch (a->q_state) 2099108642Ssimokawa { 2100103285Sikob case QS_OK: 2101103285Sikob printf("OK"); 2102103285Sikob break; 2103103285Sikob 2104103285Sikob case QS_DONTSEND: 2105103285Sikob printf("DONTSEND"); 2106103285Sikob break; 2107103285Sikob 2108103285Sikob case QS_BADADDR: 2109106790Ssimokawa printf("BADADDR"); 2110106790Ssimokawa break; 2111103285Sikob 2112103285Sikob case QS_QUEUEUP: 2113120660Ssimokawa printf("QUEUEUP"); 2114109890Ssimokawa break; 2115109890Ssimokawa 2116129585Sdfr case QS_SENT: 2117113584Ssimokawa printf("SENT"); 2118103285Sikob break; 2119109890Ssimokawa 2120113584Ssimokawa case QS_VERIFIED: 2121109890Ssimokawa printf("VERIFIED"); 2122113584Ssimokawa break; 2123119155Ssimokawa 2124119155Ssimokawa case QS_EXPANDED: 2125109890Ssimokawa printf("EXPANDED"); 2126109890Ssimokawa break; 2127113584Ssimokawa 2128113584Ssimokawa case QS_SENDER: 2129109890Ssimokawa printf("SENDER"); 2130119155Ssimokawa break; 2131113584Ssimokawa 2132113584Ssimokawa case QS_CLONED: 2133109890Ssimokawa printf("CLONED"); 2134109890Ssimokawa break; 2135109890Ssimokawa 2136109890Ssimokawa case QS_DISCARDED: 2137109890Ssimokawa printf("DISCARDED"); 2138109890Ssimokawa break; 2139109890Ssimokawa 2140109179Ssimokawa case QS_REPLACED: 2141109890Ssimokawa printf("REPLACED"); 2142109890Ssimokawa break; 2143109423Ssimokawa 2144113584Ssimokawa case QS_REMOVED: 2145113584Ssimokawa printf("REMOVED"); 2146109890Ssimokawa break; 2147109890Ssimokawa 2148109890Ssimokawa case QS_DUPLICATE: 2149109403Ssimokawa printf("DUPLICATE"); 2150109890Ssimokawa break; 2151109890Ssimokawa 2152109890Ssimokawa case QS_INCLUDED: 2153103285Sikob printf("INCLUDED"); 2154106790Ssimokawa break; 2155106790Ssimokawa 2156106790Ssimokawa default: 2157103285Sikob printf("%d", a->q_state); 2158109179Ssimokawa break; 2159120660Ssimokawa } 2160109890Ssimokawa printf(", next=%lx, alias %lx, uid %d, gid %d\n", 2161109890Ssimokawa (u_long) a->q_next, (u_long) a->q_alias, 2162129585Sdfr (int) a->q_uid, (int) a->q_gid); 2163113584Ssimokawa printf("\tflags=%lx<", a->q_flags); 2164109179Ssimokawa firstone = TRUE; 2165109890Ssimokawa for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2166113584Ssimokawa { 2167113584Ssimokawa if (!bitset(qfp->qf_bit, a->q_flags)) 2168113584Ssimokawa continue; 2169113584Ssimokawa if (!firstone) 2170109890Ssimokawa printf(","); 2171113584Ssimokawa firstone = FALSE; 2172109890Ssimokawa printf("%s", qfp->qf_name); 2173113584Ssimokawa } 2174113584Ssimokawa printf(">\n"); 2175113584Ssimokawa printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2176109890Ssimokawa a->q_owner == NULL ? "(none)" : a->q_owner, 2177109890Ssimokawa a->q_home == NULL ? "(none)" : a->q_home, 2178113584Ssimokawa a->q_fullname == NULL ? "(none)" : a->q_fullname); 2179113584Ssimokawa printf("\torcpt=\"%s\", statmta=%s, status=%s\n", 2180113584Ssimokawa a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2181113584Ssimokawa a->q_statmta == NULL ? "(none)" : a->q_statmta, 2182113584Ssimokawa a->q_status == NULL ? "(none)" : a->q_status); 2183113584Ssimokawa printf("\trstatus=\"%s\"\n", 2184113584Ssimokawa a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2185113584Ssimokawa printf("\tspecificity=%d, statdate=%s\n", 2186113584Ssimokawa a->q_specificity, 2187113584Ssimokawa a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2188113584Ssimokawa 2189113584Ssimokawa if (!follow) 2190113584Ssimokawa return; 2191109890Ssimokawa a = a->q_next; 2192109890Ssimokawa } 2193109890Ssimokawa} 2194109890Ssimokawa/* 2195111942Ssimokawa** EMPTYADDR -- return TRUE if this address is empty (``<>'') 2196109890Ssimokawa** 2197109890Ssimokawa** Parameters: 2198111942Ssimokawa** a -- pointer to the address 2199109890Ssimokawa** 2200113584Ssimokawa** Returns: 2201113584Ssimokawa** TRUE -- if this address is "empty" (i.e., no one should 2202109890Ssimokawa** ever generate replies to it. 2203109890Ssimokawa** FALSE -- if it is a "regular" (read: replyable) address. 2204103285Sikob*/ 2205109890Ssimokawa 2206111942Ssimokawabool 2207111942Ssimokawaemptyaddr(a) 2208111942Ssimokawa register ADDRESS *a; 2209111942Ssimokawa{ 2210111942Ssimokawa return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2211111942Ssimokawa a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2212103285Sikob} 2213106790Ssimokawa/* 2214106790Ssimokawa** REMOTENAME -- return the name relative to the current mailer 2215129585Sdfr** 2216106790Ssimokawa** Parameters: 2217129585Sdfr** name -- the name to translate. 2218103285Sikob** m -- the mailer that we want to do rewriting relative 2219103285Sikob** to. 2220103285Sikob** flags -- fine tune operations. 2221103285Sikob** pstat -- pointer to status word. 2222103285Sikob** e -- the current envelope. 2223103285Sikob** 2224103285Sikob** Returns: 2225103285Sikob** the text string representing this address relative to 2226103285Sikob** the receiving mailer. 2227103285Sikob** 2228103285Sikob** Side Effects: 2229103285Sikob** none. 2230103285Sikob** 2231103285Sikob** Warnings: 2232103285Sikob** The text string returned is tucked away locally; 2233103285Sikob** copy it if you intend to save it. 2234103285Sikob*/ 2235103285Sikob 2236113584Ssimokawachar * 2237103285Sikobremotename(name, m, flags, pstat, e) 2238103285Sikob char *name; 2239103285Sikob struct mailer *m; 2240103285Sikob int flags; 2241103285Sikob int *pstat; 2242113584Ssimokawa register ENVELOPE *e; 2243103285Sikob{ 2244103285Sikob register char **pvp; 2245103285Sikob char *fancy; 2246103285Sikob char *oldg = macvalue('g', e); 2247103285Sikob int rwset; 2248103285Sikob static char buf[MAXNAME + 1]; 2249103285Sikob char lbuf[MAXNAME + 1]; 2250103285Sikob char pvpbuf[PSBUFSIZE]; 2251103285Sikob#if _FFR_ADDR_TYPE 2252103285Sikob char addrtype[4]; 2253103285Sikob#endif /* _FFR_ADDR_TYPE */ 2254103285Sikob 2255103285Sikob if (tTd(12, 1)) 2256103285Sikob dprintf("remotename(%s)\n", name); 2257103285Sikob 2258106790Ssimokawa /* don't do anything if we are tagging it as special */ 2259106790Ssimokawa if (bitset(RF_SENDERADDR, flags)) 2260129585Sdfr { 2261106790Ssimokawa rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2262103285Sikob : m->m_se_rwset; 2263113584Ssimokawa#if _FFR_ADDR_TYPE 2264120660Ssimokawa addrtype[2] = 's'; 2265103285Sikob#endif /* _FFR_ADDR_TYPE */ 2266129585Sdfr } 2267103285Sikob else 2268103285Sikob { 2269103285Sikob rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2270103285Sikob : m->m_re_rwset; 2271103285Sikob#if _FFR_ADDR_TYPE 2272103285Sikob addrtype[2] = 'r'; 2273103285Sikob#endif /* _FFR_ADDR_TYPE */ 2274103285Sikob } 2275103285Sikob if (rwset < 0) 2276103285Sikob return name; 2277103285Sikob#if _FFR_ADDR_TYPE 2278103285Sikob addrtype[1] = ' '; 2279103285Sikob addrtype[3] = '\0'; 2280103285Sikob addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 2281103285Sikob define(macid("{addr_type}", NULL), addrtype, e); 2282103285Sikob#endif /* _FFR_ADDR_TYPE */ 2283103285Sikob 2284103285Sikob /* 2285103285Sikob ** Do a heuristic crack of this name to extract any comment info. 2286103285Sikob ** This will leave the name as a comment and a $g macro. 2287103285Sikob */ 2288103285Sikob 2289103285Sikob if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2290103285Sikob fancy = "\201g"; 2291103285Sikob else 2292103285Sikob fancy = crackaddr(name); 2293103285Sikob 2294103285Sikob /* 2295103285Sikob ** Turn the name into canonical form. 2296103285Sikob ** Normally this will be RFC 822 style, i.e., "user@domain". 2297103285Sikob ** If this only resolves to "user", and the "C" flag is 2298103285Sikob ** specified in the sending mailer, then the sender's 2299103285Sikob ** domain will be appended. 2300103285Sikob */ 2301103285Sikob 2302103285Sikob pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 2303103285Sikob if (pvp == NULL) 2304103285Sikob return name; 2305103285Sikob if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2306113584Ssimokawa *pstat = EX_TEMPFAIL; 2307103285Sikob if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2308103285Sikob { 2309103285Sikob /* append from domain to this address */ 2310103285Sikob register char **pxp = pvp; 2311103285Sikob int l = MAXATOM; /* size of buffer for pvp */ 2312103285Sikob 2313103285Sikob /* see if there is an "@domain" in the current name */ 2314103285Sikob while (*pxp != NULL && strcmp(*pxp, "@") != 0) 2315103285Sikob { 2316103285Sikob pxp++; 2317103285Sikob --l; 2318103285Sikob } 2319103285Sikob if (*pxp == NULL) 2320103285Sikob { 2321113584Ssimokawa /* no.... append the "@domain" from the sender */ 2322103285Sikob register char **qxq = e->e_fromdomain; 2323113584Ssimokawa 2324113584Ssimokawa while ((*pxp++ = *qxq++) != NULL) 2325103285Sikob { 2326113584Ssimokawa if (--l <= 0) 2327113584Ssimokawa { 2328103285Sikob *--pxp = NULL; 2329113584Ssimokawa usrerr("553 5.1.0 remotename: too many tokens"); 2330113584Ssimokawa *pstat = EX_UNAVAILABLE; 2331103285Sikob break; 2332103285Sikob } 2333103285Sikob } 2334103285Sikob if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2335103285Sikob *pstat = EX_TEMPFAIL; 2336106790Ssimokawa } 2337106790Ssimokawa } 2338120660Ssimokawa 2339129585Sdfr /* 2340106790Ssimokawa ** Do more specific rewriting. 2341103285Sikob ** Rewrite using ruleset 1 or 2 depending on whether this is 2342103285Sikob ** a sender address or not. 2343129585Sdfr ** Then run it through any receiving-mailer-specific rulesets. 2344103285Sikob */ 2345103285Sikob 2346103285Sikob if (bitset(RF_SENDERADDR, flags)) 2347103285Sikob { 2348103285Sikob if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 2349103285Sikob *pstat = EX_TEMPFAIL; 2350103285Sikob } 2351103285Sikob else 2352103285Sikob { 2353103285Sikob if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 2354103285Sikob *pstat = EX_TEMPFAIL; 2355103285Sikob } 2356103285Sikob if (rwset > 0) 2357103285Sikob { 2358103285Sikob if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 2359103285Sikob *pstat = EX_TEMPFAIL; 2360103285Sikob } 2361103285Sikob 2362103285Sikob /* 2363113584Ssimokawa ** Do any final sanitation the address may require. 2364113584Ssimokawa ** This will normally be used to turn internal forms 2365113584Ssimokawa ** (e.g., user@host.LOCAL) into external form. This 2366113584Ssimokawa ** may be used as a default to the above rules. 2367127468Ssimokawa */ 2368127468Ssimokawa 2369127468Ssimokawa if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 2370127468Ssimokawa *pstat = EX_TEMPFAIL; 2371113972Ssimokawa 2372114142Ssimokawa /* 2373108712Ssimokawa ** Now restore the comment information we had at the beginning. 2374113584Ssimokawa */ 2375113584Ssimokawa 2376113584Ssimokawa cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 2377113584Ssimokawa define('g', lbuf, e); 2378113584Ssimokawa 2379113584Ssimokawa /* need to make sure route-addrs have <angle brackets> */ 2380113584Ssimokawa if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2381113584Ssimokawa expand("<\201g>", buf, sizeof buf, e); 2382113584Ssimokawa else 2383103285Sikob expand(fancy, buf, sizeof buf, e); 2384103285Sikob 2385103285Sikob define('g', oldg, e); 2386103285Sikob 2387103285Sikob if (tTd(12, 1)) 2388103285Sikob dprintf("remotename => `%s'\n", buf); 2389103285Sikob return buf; 2390103285Sikob} 2391103285Sikob/* 2392103285Sikob** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2393103285Sikob** 2394103285Sikob** Parameters: 2395103285Sikob** a -- the address to map (but just the user name part). 2396103285Sikob** sendq -- the sendq in which to install any replacement 2397103285Sikob** addresses. 2398103285Sikob** aliaslevel -- the alias nesting depth. 2399113584Ssimokawa** e -- the envelope. 2400113584Ssimokawa** 2401113584Ssimokawa** Returns: 2402113584Ssimokawa** none. 2403103285Sikob*/ 2404103285Sikob 2405103285Sikob#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2406103285Sikob Q_PINGFLAGS|QHASNOTIFY|\ 2407113584Ssimokawa QRELAYED|QEXPANDED|QDELIVERED|QDELAYED) 2408103285Sikob 2409103285Sikobvoid 2410103285Sikobmaplocaluser(a, sendq, aliaslevel, e) 2411113584Ssimokawa register ADDRESS *a; 2412103285Sikob ADDRESS **sendq; 2413103285Sikob int aliaslevel; 2414103285Sikob ENVELOPE *e; 2415113584Ssimokawa{ 2416103285Sikob register char **pvp; 2417103285Sikob register ADDRESS *a1 = NULL; 2418103285Sikob auto char *delimptr; 2419103285Sikob char pvpbuf[PSBUFSIZE]; 2420103285Sikob 2421103285Sikob if (tTd(29, 1)) 2422103285Sikob { 2423103285Sikob dprintf("maplocaluser: "); 2424103285Sikob printaddr(a, FALSE); 2425106790Ssimokawa } 2426106790Ssimokawa pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 2427106790Ssimokawa if (pvp == NULL) 2428103285Sikob { 2429103285Sikob if (tTd(29, 9)) 2430129585Sdfr dprintf("maplocaluser: cannot prescan %s\n", 2431103285Sikob a->q_user); 2432110577Ssimokawa return; 2433103285Sikob } 2434108276Ssimokawa 2435108276Ssimokawa define('h', a->q_host, e); 2436129611Sdfr define('u', a->q_user, e); 2437129611Sdfr define('z', a->q_home, e); 2438129611Sdfr 2439129611Sdfr#if _FFR_ADDR_TYPE 2440129611Sdfr define(macid("{addr_type}", NULL), "e r", e); 2441129611Sdfr#endif /* _FFR_ADDR_TYPE */ 2442129611Sdfr if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL) 2443108276Ssimokawa { 2444108276Ssimokawa if (tTd(29, 9)) 2445108276Ssimokawa dprintf("maplocaluser: rewrite tempfail\n"); 2446103285Sikob a->q_state = QS_QUEUEUP; 2447103285Sikob a->q_status = "4.4.3"; 2448109280Ssimokawa return; 2449103285Sikob } 2450109280Ssimokawa if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2451103285Sikob { 2452109280Ssimokawa if (tTd(29, 9)) 2453103285Sikob dprintf("maplocaluser: doesn't resolve\n"); 2454103285Sikob return; 2455103285Sikob } 2456106790Ssimokawa 2457106790Ssimokawa /* if non-null, mailer destination specified -- has it changed? */ 2458106790Ssimokawa a1 = buildaddr(pvp, NULL, 0, e); 2459103285Sikob if (a1 == NULL || sameaddr(a, a1)) 2460103285Sikob { 2461103285Sikob if (tTd(29, 9)) 2462120660Ssimokawa dprintf("maplocaluser: address unchanged\n"); 2463103285Sikob if (a1 != NULL) 2464120660Ssimokawa free(a1); 2465103285Sikob return; 2466103285Sikob } 2467103285Sikob 2468103285Sikob /* make new address take on flags and print attributes of old */ 2469103285Sikob a1->q_flags &= ~Q_COPYFLAGS; 2470103285Sikob a1->q_flags |= a->q_flags & Q_COPYFLAGS; 2471103285Sikob a1->q_paddr = newstr(a->q_paddr); 2472103285Sikob a1->q_orcpt = a->q_orcpt; 2473103285Sikob 2474113584Ssimokawa /* mark old address as dead; insert new address */ 2475103285Sikob a->q_state = QS_REPLACED; 2476113584Ssimokawa if (tTd(29, 5)) 2477109892Ssimokawa { 2478103285Sikob dprintf("maplocaluser: QS_REPLACED "); 2479120660Ssimokawa printaddr(a, FALSE); 2480113584Ssimokawa } 2481119155Ssimokawa a1->q_alias = a; 2482113584Ssimokawa allocaddr(a1, RF_COPYALL, newstr(a->q_paddr)); 2483103285Sikob (void) recipient(a1, sendq, aliaslevel, e); 2484103285Sikob} 2485113584Ssimokawa/* 2486113584Ssimokawa** DEQUOTE_INIT -- initialize dequote map 2487113584Ssimokawa** 2488113584Ssimokawa** This is a no-op. 2489103285Sikob** 2490113584Ssimokawa** Parameters: 2491113584Ssimokawa** map -- the internal map structure. 2492113584Ssimokawa** args -- arguments. 2493109892Ssimokawa** 2494113584Ssimokawa** Returns: 2495103285Sikob** TRUE. 2496109892Ssimokawa*/ 2497109892Ssimokawa 2498109892Ssimokawabool 2499113584Ssimokawadequote_init(map, args) 2500109892Ssimokawa MAP *map; 2501113584Ssimokawa char *args; 2502113584Ssimokawa{ 2503109892Ssimokawa register char *p = args; 2504103285Sikob 2505103285Sikob /* there is no check whether there is really an argument */ 2506103285Sikob map->map_mflags |= MF_KEEPQUOTES; 2507109892Ssimokawa for (;;) 2508113584Ssimokawa { 2509113584Ssimokawa while (isascii(*p) && isspace(*p)) 2510109892Ssimokawa p++; 2511109892Ssimokawa if (*p != '-') 2512109280Ssimokawa break; 2513109892Ssimokawa switch (*++p) 2514109892Ssimokawa { 2515109892Ssimokawa case 'a': 2516103285Sikob map->map_app = ++p; 2517103285Sikob break; 2518113584Ssimokawa 2519103285Sikob case 'D': 2520103285Sikob map->map_mflags |= MF_DEFER; 2521103285Sikob break; 2522106790Ssimokawa 2523106790Ssimokawa case 'S': 2524113584Ssimokawa case 's': 2525113584Ssimokawa map->map_spacesub = *++p; 2526103285Sikob break; 2527120660Ssimokawa } 2528113584Ssimokawa while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2529103285Sikob p++; 2530113584Ssimokawa if (*p != '\0') 2531113584Ssimokawa *p = '\0'; 2532113584Ssimokawa } 2533103285Sikob if (map->map_app != NULL) 2534103285Sikob map->map_app = newstr(map->map_app); 2535103285Sikob 2536113584Ssimokawa return TRUE; 2537103285Sikob} 2538103285Sikob/* 2539113584Ssimokawa** DEQUOTE_MAP -- unquote an address 2540113584Ssimokawa** 2541119155Ssimokawa** Parameters: 2542120660Ssimokawa** map -- the internal map structure (ignored). 2543113584Ssimokawa** name -- the name to dequote. 2544129585Sdfr** av -- arguments (ignored). 2545113584Ssimokawa** statp -- pointer to status out-parameter. 2546113584Ssimokawa** 2547113584Ssimokawa** Returns: 2548109892Ssimokawa** NULL -- if there were no quotes, or if the resulting 2549113584Ssimokawa** unquoted buffer would not be acceptable to prescan. 2550113584Ssimokawa** else -- The dequoted buffer. 2551109892Ssimokawa*/ 2552113584Ssimokawa 2553103285Sikob/* ARGSUSED2 */ 2554106790Ssimokawachar * 2555106790Ssimokawadequote_map(map, name, av, statp) 2556113584Ssimokawa MAP *map; 2557113584Ssimokawa char *name; 2558103285Sikob char **av; 2559120660Ssimokawa int *statp; 2560113584Ssimokawa{ 2561113584Ssimokawa register char *p; 2562113584Ssimokawa register char *q; 2563103285Sikob register char c; 2564103285Sikob int anglecnt = 0; 2565113584Ssimokawa int cmntcnt = 0; 2566113584Ssimokawa int quotecnt = 0; 2567113584Ssimokawa int spacecnt = 0; 2568113584Ssimokawa bool quotemode = FALSE; 2569113584Ssimokawa bool bslashmode = FALSE; 2570113584Ssimokawa char spacesub = map->map_spacesub; 2571103285Sikob 2572113584Ssimokawa for (p = q = name; (c = *p++) != '\0'; ) 2573113584Ssimokawa { 2574113584Ssimokawa if (bslashmode) 2575113584Ssimokawa { 2576113584Ssimokawa bslashmode = FALSE; 2577113584Ssimokawa *q++ = c; 2578129585Sdfr continue; 2579113584Ssimokawa } 2580113584Ssimokawa 2581113584Ssimokawa if (c == ' ' && spacesub != '\0') 2582113584Ssimokawa c = spacesub; 2583113584Ssimokawa 2584113584Ssimokawa switch (c) 2585113584Ssimokawa { 2586113584Ssimokawa case '\\': 2587103285Sikob bslashmode = TRUE; 2588103285Sikob break; 2589113584Ssimokawa 2590113584Ssimokawa case '(': 2591113584Ssimokawa cmntcnt++; 2592113584Ssimokawa break; 2593103285Sikob 2594113584Ssimokawa case ')': 2595103285Sikob if (cmntcnt-- <= 0) 2596113584Ssimokawa return NULL; 2597113584Ssimokawa break; 2598113584Ssimokawa 2599103285Sikob case ' ': 2600113584Ssimokawa case '\t': 2601113584Ssimokawa spacecnt++; 2602103285Sikob break; 2603106790Ssimokawa } 2604113584Ssimokawa 2605113584Ssimokawa if (cmntcnt > 0) 2606113584Ssimokawa { 2607103285Sikob *q++ = c; 2608113584Ssimokawa continue; 2609129585Sdfr } 2610120660Ssimokawa 2611113584Ssimokawa switch (c) 2612113584Ssimokawa { 2613113584Ssimokawa case '"': 2614103285Sikob quotemode = !quotemode; 2615113584Ssimokawa quotecnt++; 2616113584Ssimokawa continue; 2617113584Ssimokawa 2618113584Ssimokawa case '<': 2619113584Ssimokawa anglecnt++; 2620120660Ssimokawa break; 2621113584Ssimokawa 2622113584Ssimokawa case '>': 2623113584Ssimokawa if (anglecnt-- <= 0) 2624113584Ssimokawa return NULL; 2625113584Ssimokawa break; 2626113584Ssimokawa } 2627113584Ssimokawa *q++ = c; 2628113584Ssimokawa } 2629113584Ssimokawa 2630113584Ssimokawa if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2631113584Ssimokawa quotemode || quotecnt <= 0 || spacecnt != 0) 2632113584Ssimokawa return NULL; 2633113584Ssimokawa *q++ = '\0'; 2634113584Ssimokawa return map_rewrite(map, name, strlen(name), NULL); 2635113584Ssimokawa} 2636113584Ssimokawa/* 2637113584Ssimokawa** RSCHECK -- check string(s) for validity using rewriting sets 2638113584Ssimokawa** 2639103285Sikob** Parameters: 2640120660Ssimokawa** rwset -- the rewriting set to use. 2641120660Ssimokawa** p1 -- the first string to check. 2642113584Ssimokawa** p2 -- the second string to check -- may be null. 2643113584Ssimokawa** e -- the current envelope. 2644120660Ssimokawa** rmcomm -- remove comments? 2645103285Sikob** cnt -- count rejections (statistics)? 2646113584Ssimokawa** logl -- logging level 2647113584Ssimokawa** host -- NULL or relay host. 2648113584Ssimokawa** 2649113584Ssimokawa** Returns: 2650120660Ssimokawa** EX_OK -- if the rwset doesn't resolve to $#error 2651103285Sikob** else -- the failure status (message printed) 2652103285Sikob*/ 2653103285Sikob 2654113584Ssimokawaint 2655103285Sikobrscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host) 2656120660Ssimokawa char *rwset; 2657113584Ssimokawa char *p1; 2658103285Sikob char *p2; 2659120660Ssimokawa ENVELOPE *e; 2660129585Sdfr bool rmcomm, cnt; 2661120660Ssimokawa int logl; 2662129585Sdfr char *host; 2663120660Ssimokawa{ 2664129585Sdfr char *buf; 2665120660Ssimokawa int bufsize; 2666110798Ssimokawa int saveexitstat; 2667110798Ssimokawa int rstat = EX_OK; 2668120660Ssimokawa char **pvp; 2669110798Ssimokawa int rsno; 2670110798Ssimokawa bool discard = FALSE; 2671110798Ssimokawa auto ADDRESS a1; 2672110798Ssimokawa bool saveQuickAbort = QuickAbort; 2673120660Ssimokawa bool saveSuprErrs = SuprErrs; 2674110798Ssimokawa char buf0[MAXLINE]; 2675103285Sikob char pvpbuf[PSBUFSIZE]; 2676103285Sikob extern char MsgBuf[]; 2677106790Ssimokawa 2678113584Ssimokawa if (tTd(48, 2)) 2679113584Ssimokawa dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 2680120660Ssimokawa p2 == NULL ? "(NULL)" : p2); 2681113584Ssimokawa 2682113584Ssimokawa rsno = strtorwset(rwset, NULL, ST_FIND); 2683113584Ssimokawa if (rsno < 0) 2684113584Ssimokawa return EX_OK; 2685113584Ssimokawa 2686113584Ssimokawa if (p2 != NULL) 2687113584Ssimokawa { 2688113584Ssimokawa bufsize = strlen(p1) + strlen(p2) + 2; 2689113584Ssimokawa if (bufsize > sizeof buf0) 2690106790Ssimokawa buf = xalloc(bufsize); 2691103285Sikob else 2692103285Sikob { 2693113584Ssimokawa buf = buf0; 2694113584Ssimokawa bufsize = sizeof buf0; 2695113584Ssimokawa } 2696103285Sikob (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2697129585Sdfr } 2698129585Sdfr else 2699103285Sikob { 2700113584Ssimokawa bufsize = strlen(p1) + 1; 2701103285Sikob if (bufsize > sizeof buf0) 2702103285Sikob buf = xalloc(bufsize); 2703103285Sikob else 2704103285Sikob { 2705103285Sikob buf = buf0; 2706103285Sikob bufsize = sizeof buf0; 2707103285Sikob } 2708103285Sikob (void) snprintf(buf, bufsize, "%s", p1); 2709103285Sikob } 2710103285Sikob SuprErrs = TRUE; 2711103285Sikob QuickAbort = FALSE; 2712103285Sikob pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 2713103285Sikob rmcomm ? NULL : TokTypeNoC); 2714103285Sikob SuprErrs = saveSuprErrs; 2715103285Sikob if (pvp == NULL) 2716103285Sikob { 2717113584Ssimokawa if (tTd(48, 2)) 2718113584Ssimokawa dprintf("rscheck: cannot prescan input\n"); 2719113584Ssimokawa/* 2720113584Ssimokawa syserr("rscheck: cannot prescan input: \"%s\"", 2721113584Ssimokawa shortenstring(buf, MAXSHORTSTR)); 2722113584Ssimokawa rstat = EX_DATAERR; 2723113584Ssimokawa*/ 2724113584Ssimokawa goto finis; 2725113584Ssimokawa } 2726129585Sdfr 2727113584Ssimokawa MapOpenErr = FALSE; 2728113584Ssimokawa (void) rewrite(pvp, rsno, 0, e); 2729113584Ssimokawa if (MapOpenErr) 2730113584Ssimokawa usrerrenh("4.3.0", "451 Temporary failure"); 2731113584Ssimokawa 2732113584Ssimokawa if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 2733113584Ssimokawa pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 2734103285Sikob strcmp(pvp[1], "discard") != 0)) 2735106789Ssimokawa { 2736106789Ssimokawa goto finis; 2737113584Ssimokawa } 2738113584Ssimokawa 2739113584Ssimokawa if (strcmp(pvp[1], "discard") == 0) 2740103285Sikob { 2741113584Ssimokawa if (tTd(48, 2)) 2742113584Ssimokawa dprintf("rscheck: discard mailer selected\n"); 2743113584Ssimokawa e->e_flags |= EF_DISCARD; 2744113584Ssimokawa discard = TRUE; 2745113584Ssimokawa } 2746113584Ssimokawa else 2747113584Ssimokawa { 2748113584Ssimokawa int savelogusrerrs = LogUsrErrs; 2749113584Ssimokawa static bool logged = FALSE; 2750113584Ssimokawa 2751113584Ssimokawa /* got an error -- process it */ 2752113584Ssimokawa saveexitstat = ExitStat; 2753113584Ssimokawa LogUsrErrs = FALSE; 2754113584Ssimokawa (void) buildaddr(pvp, &a1, 0, e); 2755113584Ssimokawa LogUsrErrs = savelogusrerrs; 2756113584Ssimokawa rstat = ExitStat; 2757113584Ssimokawa ExitStat = saveexitstat; 2758113584Ssimokawa if (!logged) 2759113584Ssimokawa { 2760113584Ssimokawa if (cnt) 2761103285Sikob markstats(e, &a1, TRUE); 2762103285Sikob logged = TRUE; 2763113584Ssimokawa } 2764113584Ssimokawa } 2765113584Ssimokawa 2766113584Ssimokawa if (LogLevel >= logl) 2767113584Ssimokawa { 2768113584Ssimokawa char *relay; 2769113584Ssimokawa char *p; 2770113584Ssimokawa char lbuf[MAXLINE]; 2771113584Ssimokawa 2772113584Ssimokawa p = lbuf; 2773113584Ssimokawa if (p2 != NULL) 2774113584Ssimokawa { 2775103285Sikob snprintf(p, SPACELEFT(lbuf, p), 2776113584Ssimokawa ", arg2=%s", 2777113584Ssimokawa p2); 2778113584Ssimokawa p += strlen(p); 2779113584Ssimokawa } 2780103285Sikob 2781113584Ssimokawa if (host != NULL) 2782113584Ssimokawa relay = host; 2783113584Ssimokawa else 2784103285Sikob relay = macvalue('_', e); 2785113584Ssimokawa if (relay != NULL) 2786113584Ssimokawa { 2787113584Ssimokawa snprintf(p, SPACELEFT(lbuf, p), 2788113584Ssimokawa ", relay=%s", relay); 2789113584Ssimokawa p += strlen(p); 2790124145Ssimokawa } 2791124145Ssimokawa *p = '\0'; 2792124145Ssimokawa if (discard) 2793113584Ssimokawa sm_syslog(LOG_NOTICE, e->e_id, 2794103285Sikob "ruleset=%s, arg1=%s%s, discard", 2795113584Ssimokawa rwset, p1, lbuf); 2796113584Ssimokawa else 2797113584Ssimokawa sm_syslog(LOG_NOTICE, e->e_id, 2798113584Ssimokawa "ruleset=%s, arg1=%s%s, reject=%s", 2799113584Ssimokawa rwset, p1, lbuf, MsgBuf); 2800113584Ssimokawa } 2801113584Ssimokawa 2802120660Ssimokawa finis: 2803120660Ssimokawa /* clean up */ 2804124145Ssimokawa QuickAbort = saveQuickAbort; 2805113584Ssimokawa setstat(rstat); 2806113584Ssimokawa if (buf != buf0) 2807113584Ssimokawa free(buf); 2808113584Ssimokawa 2809113584Ssimokawa if (rstat != EX_OK && QuickAbort) 2810113584Ssimokawa longjmp(TopFrame, 2); 2811113584Ssimokawa return rstat; 2812113584Ssimokawa} 2813113584Ssimokawa