122712Sdist /* 222712Sdist ** Sendmail 322712Sdist ** Copyright (c) 1983 Eric P. Allman 422712Sdist ** Berkeley, California 522712Sdist ** 622712Sdist ** Copyright (c) 1983 Regents of the University of California. 722712Sdist ** All rights reserved. The Berkeley software License Agreement 822712Sdist ** specifies the terms and conditions for redistribution. 922712Sdist */ 1022712Sdist 1122712Sdist 129339Seric # include <errno.h> 134549Seric # include "sendmail.h" 1411728Seric # include <signal.h> 154549Seric 165181Seric # ifndef SMTP 1723122Seric # ifndef lint 18*24955Seric static char SccsId[] = "@(#)srvrsmtp.c 5.9 (Berkeley) 09/19/85 (no SMTP)"; 1923122Seric # endif not lint 205181Seric # else SMTP 214556Seric 2223122Seric # ifndef lint 23*24955Seric static char SccsId[] = "@(#)srvrsmtp.c 5.9 (Berkeley) 09/19/85"; 2423122Seric # endif not lint 255181Seric 264549Seric /* 274549Seric ** SMTP -- run the SMTP protocol. 284549Seric ** 294549Seric ** Parameters: 304549Seric ** none. 314549Seric ** 324549Seric ** Returns: 334549Seric ** never. 344549Seric ** 354549Seric ** Side Effects: 364549Seric ** Reads commands from the input channel and processes 374549Seric ** them. 384549Seric */ 394549Seric 404549Seric struct cmd 414549Seric { 424549Seric char *cmdname; /* command name */ 434549Seric int cmdcode; /* internal code, see below */ 444549Seric }; 454549Seric 464549Seric /* values for cmdcode */ 474549Seric # define CMDERROR 0 /* bad command */ 484549Seric # define CMDMAIL 1 /* mail -- designate sender */ 494976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 504549Seric # define CMDDATA 3 /* data -- send message text */ 519339Seric # define CMDRSET 4 /* rset -- reset state */ 529339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 539339Seric # define CMDHELP 6 /* help -- give usage info */ 549339Seric # define CMDNOOP 7 /* noop -- do nothing */ 559339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 569339Seric # define CMDHELO 9 /* helo -- be polite */ 579339Seric # define CMDDBGQSHOW 10 /* showq -- show send queue (DEBUG) */ 589339Seric # define CMDDBGDEBUG 11 /* debug -- set debug mode */ 599339Seric # define CMDVERB 12 /* verb -- go into verbose mode */ 609339Seric # define CMDDBGKILL 13 /* kill -- kill sendmail */ 619339Seric # define CMDDBGWIZ 14 /* wiz -- become a wizard */ 629339Seric # define CMDONEX 15 /* onex -- sending one transaction only */ 634549Seric 644549Seric static struct cmd CmdTab[] = 654549Seric { 664549Seric "mail", CMDMAIL, 674976Seric "rcpt", CMDRCPT, 684549Seric "data", CMDDATA, 694549Seric "rset", CMDRSET, 704549Seric "vrfy", CMDVRFY, 717762Seric "expn", CMDVRFY, 724549Seric "help", CMDHELP, 734549Seric "noop", CMDNOOP, 744549Seric "quit", CMDQUIT, 754976Seric "helo", CMDHELO, 768544Seric "verb", CMDVERB, 779314Seric "onex", CMDONEX, 785003Seric # ifdef DEBUG 799339Seric "showq", CMDDBGQSHOW, 808544Seric "debug", CMDDBGDEBUG, 8124945Seric # endif DEBUG 8224945Seric # ifdef WIZ 838544Seric "kill", CMDDBGKILL, 8424945Seric # endif WIZ 858544Seric "wiz", CMDDBGWIZ, 864549Seric NULL, CMDERROR, 874549Seric }; 884549Seric 89*24955Seric # ifdef WIZ 908544Seric bool IsWiz = FALSE; /* set if we are a wizard */ 91*24955Seric # endif WIZ 9215596Seric char *WizWord; /* the wizard word to compare against */ 939339Seric bool InChild = FALSE; /* true if running in a subprocess */ 949378Seric bool OneXact = FALSE; /* one xaction only this run */ 9511146Seric 969339Seric #define EX_QUIT 22 /* special code for QUIT command */ 978544Seric 984549Seric smtp() 994549Seric { 1004549Seric register char *p; 1018544Seric register struct cmd *c; 1024549Seric char *cmd; 1034549Seric extern char *skipword(); 1044549Seric extern bool sameword(); 1054549Seric bool hasmail; /* mail command received */ 1065003Seric auto ADDRESS *vrfyqueue; 10712612Seric ADDRESS *a; 1088544Seric char inp[MAXLINE]; 1097124Seric extern char Version[]; 1107356Seric extern tick(); 1118544Seric extern bool iswiz(); 1129349Seric extern char *arpadate(); 11311151Seric extern char *macvalue(); 11412612Seric extern ADDRESS *recipient(); 11524943Seric extern ENVELOPE BlankEnvelope; 11624943Seric extern ENVELOPE *newenvelope(); 1174549Seric 1185003Seric hasmail = FALSE; 1197363Seric if (OutChannel != stdout) 1207363Seric { 1217363Seric /* arrange for debugging output to go to remote host */ 1227363Seric (void) close(1); 1237363Seric (void) dup(fileno(OutChannel)); 1247363Seric } 12511931Seric settime(); 12616153Seric expand("\001e", inp, &inp[sizeof inp], CurEnv); 12710708Seric message("220", inp); 12824943Seric SmtpPhase = "startup"; 1294549Seric for (;;) 1304549Seric { 13112612Seric /* arrange for backout */ 13212612Seric if (setjmp(TopFrame) > 0 && InChild) 13312612Seric finis(); 13412612Seric QuickAbort = FALSE; 13512612Seric HoldErrs = FALSE; 13612612Seric 1377356Seric /* setup for the read */ 1386907Seric CurEnv->e_to = NULL; 1394577Seric Errors = 0; 1407275Seric (void) fflush(stdout); 1417356Seric 1427356Seric /* read the input line */ 1437685Seric p = sfgets(inp, sizeof inp, InChannel); 1447356Seric 1457685Seric /* handle errors */ 1467356Seric if (p == NULL) 1477356Seric { 1484549Seric /* end of file, just die */ 1494558Seric message("421", "%s Lost input channel", HostName); 1504549Seric finis(); 1514549Seric } 1524549Seric 1534549Seric /* clean up end of line */ 1544558Seric fixcrlf(inp, TRUE); 1554549Seric 1564713Seric /* echo command to transcript */ 1579545Seric if (CurEnv->e_xfp != NULL) 1589545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1594713Seric 1604549Seric /* break off command */ 1614549Seric for (p = inp; isspace(*p); p++) 1624549Seric continue; 1634549Seric cmd = p; 1644549Seric while (*++p != '\0' && !isspace(*p)) 1654549Seric continue; 1664549Seric if (*p != '\0') 1674549Seric *p++ = '\0'; 1684549Seric 1694549Seric /* decode command */ 1704549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1714549Seric { 1724549Seric if (sameword(c->cmdname, cmd)) 1734549Seric break; 1744549Seric } 1754549Seric 1764549Seric /* process command */ 1774549Seric switch (c->cmdcode) 1784549Seric { 1794976Seric case CMDHELO: /* hello -- introduce yourself */ 18024943Seric SmtpPhase = "HELO"; 18114877Seric if (sameword(p, HostName)) 18214877Seric { 18314877Seric /* connected to an echo server */ 18414877Seric message("553", "%s I refuse to talk to myself", 18514877Seric HostName); 18614877Seric break; 18714877Seric } 18811146Seric if (RealHostName != NULL && !sameword(p, RealHostName)) 18911146Seric { 19011146Seric char buf[MAXNAME]; 19111146Seric 19211146Seric (void) sprintf(buf, "%s (%s)", p, RealHostName); 19311146Seric define('s', newstr(buf), CurEnv); 19411146Seric } 19511146Seric else 19611146Seric define('s', newstr(p), CurEnv); 1974997Seric message("250", "%s Hello %s, pleased to meet you", 1984997Seric HostName, p); 1994976Seric break; 2004976Seric 2014549Seric case CMDMAIL: /* mail -- designate sender */ 20224943Seric SmtpPhase = "MAIL"; 20324943Seric 20411151Seric /* force a sending host even if no HELO given */ 20511151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 20611151Seric define('s', RealHostName, CurEnv); 20711151Seric 2089314Seric /* check for validity of this command */ 2094558Seric if (hasmail) 2104558Seric { 2114558Seric message("503", "Sender already specified"); 2124558Seric break; 2134558Seric } 2149339Seric if (InChild) 2159339Seric { 2169339Seric syserr("Nested MAIL command"); 2179339Seric exit(0); 2189339Seric } 2199339Seric 2209339Seric /* fork a subprocess to process this command */ 2219339Seric if (runinchild("SMTP-MAIL") > 0) 2229339Seric break; 2239339Seric initsys(); 2249339Seric 2259339Seric /* child -- go do the processing */ 2264549Seric p = skipword(p, "from"); 2274549Seric if (p == NULL) 2284549Seric break; 2294549Seric setsender(p); 2304577Seric if (Errors == 0) 2314549Seric { 2324549Seric message("250", "Sender ok"); 2334549Seric hasmail = TRUE; 2344549Seric } 2359339Seric else if (InChild) 2369339Seric finis(); 2374549Seric break; 2384549Seric 2394976Seric case CMDRCPT: /* rcpt -- designate recipient */ 24024943Seric SmtpPhase = "RCPT"; 24112612Seric if (setjmp(TopFrame) > 0) 24214785Seric { 24314785Seric CurEnv->e_flags &= ~EF_FATALERRS; 24412612Seric break; 24514785Seric } 24612612Seric QuickAbort = TRUE; 2474549Seric p = skipword(p, "to"); 2484549Seric if (p == NULL) 2494549Seric break; 25016140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 25112612Seric if (a == NULL) 25212612Seric break; 25316886Seric a->q_flags |= QPRIMARY; 25412612Seric a = recipient(a, &CurEnv->e_sendqueue); 25512612Seric if (Errors != 0) 25612612Seric break; 25712612Seric 25812612Seric /* no errors during parsing, but might be a duplicate */ 25912612Seric CurEnv->e_to = p; 26012612Seric if (!bitset(QBADADDR, a->q_flags)) 26112612Seric message("250", "Recipient ok"); 26212612Seric else 2634549Seric { 26412612Seric /* punt -- should keep message in ADDRESS.... */ 26512612Seric message("550", "Addressee unknown"); 2664549Seric } 26712612Seric CurEnv->e_to = NULL; 2684549Seric break; 2694549Seric 2704549Seric case CMDDATA: /* data -- text of mail */ 27124943Seric SmtpPhase = "DATA"; 2724976Seric if (!hasmail) 2734549Seric { 2744976Seric message("503", "Need MAIL command"); 2754976Seric break; 2764549Seric } 27724943Seric else if (CurEnv->e_nrcpts <= 0) 2784549Seric { 2794976Seric message("503", "Need RCPT (recipient)"); 2804976Seric break; 2814549Seric } 2824976Seric 2834976Seric /* collect the text of the message */ 28424943Seric SmtpPhase = "collect"; 2854976Seric collect(TRUE); 2864976Seric if (Errors != 0) 2874976Seric break; 2884976Seric 2898238Seric /* 2908238Seric ** Arrange to send to everyone. 2918238Seric ** If sending to multiple people, mail back 2928238Seric ** errors rather than reporting directly. 2938238Seric ** In any case, don't mail back errors for 2948238Seric ** anything that has happened up to 2958238Seric ** now (the other end will do this). 29610197Seric ** Truncate our transcript -- the mail has gotten 29710197Seric ** to us successfully, and if we have 29810197Seric ** to mail this back, it will be easier 29910197Seric ** on the reader. 3008238Seric ** Then send to everyone. 3018238Seric ** Finally give a reply code. If an error has 3028238Seric ** already been given, don't mail a 3038238Seric ** message back. 3049339Seric ** We goose error returns by clearing error bit. 3058238Seric */ 3068238Seric 30724943Seric SmtpPhase = "delivery"; 30824943Seric if (CurEnv->e_nrcpts != 1) 3099378Seric { 3109378Seric HoldErrs = TRUE; 31116886Seric ErrorMode = EM_MAIL; 3129378Seric } 3139339Seric CurEnv->e_flags &= ~EF_FATALERRS; 31410197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3154976Seric 3164976Seric /* send to all recipients */ 31714877Seric sendall(CurEnv, SM_DEFAULT); 3186907Seric CurEnv->e_to = NULL; 3194976Seric 32023516Seric /* save statistics */ 32123516Seric markstats(CurEnv, (ADDRESS *) NULL); 32223516Seric 3238238Seric /* issue success if appropriate and reset */ 3248238Seric if (Errors == 0 || HoldErrs) 3259283Seric message("250", "Ok"); 3268238Seric else 3279339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3289339Seric 3299339Seric /* if in a child, pop back to our parent */ 3309339Seric if (InChild) 3319339Seric finis(); 33224943Seric 33324943Seric /* clean up a bit */ 33424943Seric hasmail = 0; 33524943Seric dropenvelope(CurEnv); 33624943Seric CurEnv = newenvelope(CurEnv); 33724943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3384549Seric break; 3394549Seric 3404549Seric case CMDRSET: /* rset -- reset state */ 3414549Seric message("250", "Reset state"); 3429339Seric if (InChild) 3439339Seric finis(); 3449339Seric break; 3454549Seric 3464549Seric case CMDVRFY: /* vrfy -- verify address */ 3479339Seric if (runinchild("SMTP-VRFY") > 0) 3489339Seric break; 3495003Seric vrfyqueue = NULL; 3507762Seric QuickAbort = TRUE; 3519619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3527762Seric if (Errors != 0) 3539339Seric { 3549339Seric if (InChild) 3559339Seric finis(); 3567762Seric break; 3579339Seric } 3585003Seric while (vrfyqueue != NULL) 3595003Seric { 3605003Seric register ADDRESS *a = vrfyqueue->q_next; 3615003Seric char *code; 3625003Seric 3637685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3645003Seric a = a->q_next; 3655003Seric 3667685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3675003Seric { 3685003Seric if (a != NULL) 3695003Seric code = "250-"; 3705003Seric else 3715003Seric code = "250"; 3725003Seric if (vrfyqueue->q_fullname == NULL) 3735003Seric message(code, "<%s>", vrfyqueue->q_paddr); 3745003Seric else 3755003Seric message(code, "%s <%s>", 3765003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 3775003Seric } 3785003Seric else if (a == NULL) 3795003Seric message("554", "Self destructive alias loop"); 3805003Seric vrfyqueue = a; 3815003Seric } 3829339Seric if (InChild) 3839339Seric finis(); 3844549Seric break; 3854549Seric 3864549Seric case CMDHELP: /* help -- give user info */ 3874577Seric if (*p == '\0') 3884577Seric p = "SMTP"; 3894577Seric help(p); 3904549Seric break; 3914549Seric 3924549Seric case CMDNOOP: /* noop -- do nothing */ 3934549Seric message("200", "OK"); 3944549Seric break; 3954549Seric 3964549Seric case CMDQUIT: /* quit -- leave mail */ 3974549Seric message("221", "%s closing connection", HostName); 3989339Seric if (InChild) 3999339Seric ExitStat = EX_QUIT; 4004549Seric finis(); 4014549Seric 4028544Seric case CMDVERB: /* set verbose mode */ 4038544Seric Verbose = TRUE; 4048544Seric message("200", "Verbose mode"); 4058544Seric break; 4068544Seric 4079314Seric case CMDONEX: /* doing one transaction only */ 4089378Seric OneXact = TRUE; 4099314Seric message("200", "Only one transaction"); 4109314Seric break; 4119314Seric 4125003Seric # ifdef DEBUG 4139339Seric case CMDDBGQSHOW: /* show queues */ 4146907Seric printf("Send Queue="); 4156907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4165003Seric break; 4177275Seric 4187275Seric case CMDDBGDEBUG: /* set debug mode */ 4197676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4207676Seric tTflag(p); 4217676Seric message("200", "Debug set"); 4227275Seric break; 42324945Seric # endif DEBUG 4247275Seric 42524945Seric # ifdef WIZ 4267282Seric case CMDDBGKILL: /* kill the parent */ 4278544Seric if (!iswiz()) 4288544Seric break; 4297282Seric if (kill(MotherPid, SIGTERM) >= 0) 4307282Seric message("200", "Mother is dead"); 4317282Seric else 4327282Seric message("500", "Can't kill Mom"); 4337282Seric break; 4348544Seric 4358544Seric case CMDDBGWIZ: /* become a wizard */ 4368544Seric if (WizWord != NULL) 4378544Seric { 4388544Seric char seed[3]; 4398544Seric extern char *crypt(); 4408544Seric 44123106Seric (void) strncpy(seed, WizWord, 2); 44215596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4438544Seric { 44415596Seric IsWiz = TRUE; 44515596Seric message("200", "Please pass, oh mighty wizard"); 4468544Seric break; 4478544Seric } 4488544Seric } 44915596Seric message("500", "You are no wizard!"); 4508544Seric break; 4515003Seric 45224945Seric # else WIZ 45324945Seric case CMDDBGWIZ: /* try to become a wizard */ 45424945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 45524945Seric break; 45624945Seric # endif WIZ 45724945Seric 4584549Seric case CMDERROR: /* unknown command */ 4594549Seric message("500", "Command unrecognized"); 4604549Seric break; 4614549Seric 4624549Seric default: 4634549Seric syserr("smtp: unknown code %d", c->cmdcode); 4644549Seric break; 4654549Seric } 4664549Seric } 4674549Seric } 4684549Seric /* 4694549Seric ** SKIPWORD -- skip a fixed word. 4704549Seric ** 4714549Seric ** Parameters: 4724549Seric ** p -- place to start looking. 4734549Seric ** w -- word to skip. 4744549Seric ** 4754549Seric ** Returns: 4764549Seric ** p following w. 4774549Seric ** NULL on error. 4784549Seric ** 4794549Seric ** Side Effects: 4804549Seric ** clobbers the p data area. 4814549Seric */ 4824549Seric 4834549Seric static char * 4844549Seric skipword(p, w) 4854549Seric register char *p; 4864549Seric char *w; 4874549Seric { 4884549Seric register char *q; 4894549Seric extern bool sameword(); 4904549Seric 4914549Seric /* find beginning of word */ 4924549Seric while (isspace(*p)) 4934549Seric p++; 4944549Seric q = p; 4954549Seric 4964549Seric /* find end of word */ 4974549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 4984549Seric p++; 4994549Seric while (isspace(*p)) 5004549Seric *p++ = '\0'; 5014549Seric if (*p != ':') 5024549Seric { 5034549Seric syntax: 5044549Seric message("501", "Syntax error"); 5054549Seric Errors++; 5064549Seric return (NULL); 5074549Seric } 5084549Seric *p++ = '\0'; 5094549Seric while (isspace(*p)) 5104549Seric p++; 5114549Seric 5124549Seric /* see if the input word matches desired word */ 5134549Seric if (!sameword(q, w)) 5144549Seric goto syntax; 5154549Seric 5164549Seric return (p); 5174549Seric } 5184577Seric /* 5194577Seric ** HELP -- implement the HELP command. 5204577Seric ** 5214577Seric ** Parameters: 5224577Seric ** topic -- the topic we want help for. 5234577Seric ** 5244577Seric ** Returns: 5254577Seric ** none. 5264577Seric ** 5274577Seric ** Side Effects: 5284577Seric ** outputs the help file to message output. 5294577Seric */ 5304577Seric 5314577Seric help(topic) 5324577Seric char *topic; 5334577Seric { 5344577Seric register FILE *hf; 5354577Seric int len; 5364577Seric char buf[MAXLINE]; 5374577Seric bool noinfo; 5384577Seric 5398269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5404577Seric { 5414577Seric /* no help */ 54211931Seric errno = 0; 5434577Seric message("502", "HELP not implemented"); 5444577Seric return; 5454577Seric } 5464577Seric 5474577Seric len = strlen(topic); 5484577Seric makelower(topic); 5494577Seric noinfo = TRUE; 5504577Seric 5514577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5524577Seric { 5534577Seric if (strncmp(buf, topic, len) == 0) 5544577Seric { 5554577Seric register char *p; 5564577Seric 5574577Seric p = index(buf, '\t'); 5584577Seric if (p == NULL) 5594577Seric p = buf; 5604577Seric else 5614577Seric p++; 5624577Seric fixcrlf(p, TRUE); 5634577Seric message("214-", p); 5644577Seric noinfo = FALSE; 5654577Seric } 5664577Seric } 5674577Seric 5684577Seric if (noinfo) 5694577Seric message("504", "HELP topic unknown"); 5704577Seric else 5714577Seric message("214", "End of HELP info"); 5724628Seric (void) fclose(hf); 5734577Seric } 5748544Seric /* 5758544Seric ** ISWIZ -- tell us if we are a wizard 5768544Seric ** 5778544Seric ** If not, print a nasty message. 5788544Seric ** 5798544Seric ** Parameters: 5808544Seric ** none. 5818544Seric ** 5828544Seric ** Returns: 5838544Seric ** TRUE if we are a wizard. 5848544Seric ** FALSE if we are not a wizard. 5858544Seric ** 5868544Seric ** Side Effects: 5878544Seric ** Prints a 500 exit stat if we are not a wizard. 5888544Seric */ 5895181Seric 59024945Seric #ifdef WIZ 59119038Seric 5928544Seric bool 5938544Seric iswiz() 5948544Seric { 5958544Seric if (!IsWiz) 5968544Seric message("500", "Mere mortals musn't mutter that mantra"); 5978544Seric return (IsWiz); 5988544Seric } 59919038Seric 60024945Seric #endif WIZ 6019339Seric /* 6029339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6039339Seric ** 6049339Seric ** Parameters: 6059339Seric ** label -- a string used in error messages 6069339Seric ** 6079339Seric ** Returns: 6089339Seric ** zero in the child 6099339Seric ** one in the parent 6109339Seric ** 6119339Seric ** Side Effects: 6129339Seric ** none. 6139339Seric */ 6148544Seric 6159339Seric runinchild(label) 6169339Seric char *label; 6179339Seric { 6189339Seric int childpid; 6199339Seric 62016158Seric if (!OneXact) 6219339Seric { 62216158Seric childpid = dofork(); 62316158Seric if (childpid < 0) 62416158Seric { 62516158Seric syserr("%s: cannot fork", label); 62616158Seric return (1); 62716158Seric } 62816158Seric if (childpid > 0) 62916158Seric { 63016158Seric auto int st; 6319339Seric 63216158Seric /* parent -- wait for child to complete */ 63316158Seric st = waitfor(childpid); 63416158Seric if (st == -1) 63516158Seric syserr("%s: lost child", label); 6369339Seric 63716158Seric /* if we exited on a QUIT command, complete the process */ 63816158Seric if (st == (EX_QUIT << 8)) 63916158Seric finis(); 6409339Seric 64116158Seric return (1); 64216158Seric } 64316158Seric else 64416158Seric { 64516158Seric /* child */ 64616158Seric InChild = TRUE; 64724945Seric clearenvelope(CurEnv); 64816158Seric } 6499339Seric } 65015256Seric 65116158Seric /* open alias database */ 65216158Seric initaliases(AliasFile, FALSE); 65316158Seric 65416158Seric return (0); 6559339Seric } 6569339Seric 6575181Seric # endif SMTP 658