122712Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822712Sdist 933731Sbostic # include "sendmail.h" 1022712Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef SMTP 13*59016Seric static char sccsid[] = "@(#)srvrsmtp.c 6.40 (Berkeley) 04/09/93 (with SMTP)"; 1433731Sbostic #else 15*59016Seric static char sccsid[] = "@(#)srvrsmtp.c 6.40 (Berkeley) 04/09/93 (without SMTP)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 199339Seric # include <errno.h> 2011728Seric # include <signal.h> 214549Seric 2233731Sbostic # ifdef SMTP 234556Seric 244549Seric /* 254549Seric ** SMTP -- run the SMTP protocol. 264549Seric ** 274549Seric ** Parameters: 284549Seric ** none. 294549Seric ** 304549Seric ** Returns: 314549Seric ** never. 324549Seric ** 334549Seric ** Side Effects: 344549Seric ** Reads commands from the input channel and processes 354549Seric ** them. 364549Seric */ 374549Seric 384549Seric struct cmd 394549Seric { 404549Seric char *cmdname; /* command name */ 414549Seric int cmdcode; /* internal code, see below */ 424549Seric }; 434549Seric 444549Seric /* values for cmdcode */ 454549Seric # define CMDERROR 0 /* bad command */ 464549Seric # define CMDMAIL 1 /* mail -- designate sender */ 474976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 484549Seric # define CMDDATA 3 /* data -- send message text */ 499339Seric # define CMDRSET 4 /* rset -- reset state */ 509339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 5158092Seric # define CMDEXPN 6 /* expn -- expand address */ 529339Seric # define CMDNOOP 7 /* noop -- do nothing */ 539339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 549339Seric # define CMDHELO 9 /* helo -- be polite */ 5558092Seric # define CMDHELP 10 /* help -- give usage info */ 5658323Seric # define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ 5758092Seric /* non-standard commands */ 5858092Seric # define CMDONEX 16 /* onex -- sending one transaction only */ 5958092Seric # define CMDVERB 17 /* verb -- go into verbose mode */ 6036230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 6158092Seric # define CMDDBGQSHOW 24 /* showq -- show send queue */ 6258092Seric # define CMDDBGDEBUG 25 /* debug -- set debug mode */ 634549Seric 644549Seric static struct cmd CmdTab[] = 654549Seric { 664549Seric "mail", CMDMAIL, 674976Seric "rcpt", CMDRCPT, 684549Seric "data", CMDDATA, 694549Seric "rset", CMDRSET, 704549Seric "vrfy", CMDVRFY, 7158092Seric "expn", CMDEXPN, 724549Seric "help", CMDHELP, 734549Seric "noop", CMDNOOP, 744549Seric "quit", CMDQUIT, 754976Seric "helo", CMDHELO, 7658323Seric "ehlo", CMDEHLO, 778544Seric "verb", CMDVERB, 789314Seric "onex", CMDONEX, 7936230Skarels /* 8036230Skarels * remaining commands are here only 8136230Skarels * to trap and log attempts to use them 8236230Skarels */ 839339Seric "showq", CMDDBGQSHOW, 848544Seric "debug", CMDDBGDEBUG, 854549Seric NULL, CMDERROR, 864549Seric }; 874549Seric 889339Seric bool InChild = FALSE; /* true if running in a subprocess */ 899378Seric bool OneXact = FALSE; /* one xaction only this run */ 9011146Seric 919339Seric #define EX_QUIT 22 /* special code for QUIT command */ 928544Seric 9355012Seric smtp(e) 9455012Seric register ENVELOPE *e; 954549Seric { 964549Seric register char *p; 978544Seric register struct cmd *c; 984549Seric char *cmd; 9946928Sbostic static char *skipword(); 1005003Seric auto ADDRESS *vrfyqueue; 10112612Seric ADDRESS *a; 10258109Seric bool gotmail; /* mail command received */ 10358092Seric bool gothello; /* helo command received */ 10458092Seric bool vrfy; /* set if this is a vrfy command */ 10558323Seric char *protocol; /* sending protocol */ 106*59016Seric char *sendinghost; /* sending hostname */ 10758333Seric long msize; /* approximate maximum message size */ 10858333Seric auto char *delimptr; 10958714Seric char *id; 1108544Seric char inp[MAXLINE]; 11157232Seric char cmdbuf[MAXLINE]; 1127124Seric extern char Version[]; 11311151Seric extern char *macvalue(); 11412612Seric extern ADDRESS *recipient(); 11524943Seric extern ENVELOPE BlankEnvelope; 11624943Seric extern ENVELOPE *newenvelope(); 11758755Seric extern char *anynet_ntoa(); 1184549Seric 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 } 12555012Seric settime(e); 12657642Seric CurHostName = RealHostName; 12757642Seric setproctitle("srvrsmtp %s", CurHostName); 12858050Seric expand("\201e", inp, &inp[sizeof inp], e); 12958151Seric message("220 %s", inp); 13024943Seric SmtpPhase = "startup"; 13158330Seric protocol = NULL; 132*59016Seric sendinghost = macvalue('s', e); 13358082Seric gothello = FALSE; 13458330Seric gotmail = FALSE; 1354549Seric for (;;) 1364549Seric { 13712612Seric /* arrange for backout */ 13812612Seric if (setjmp(TopFrame) > 0 && InChild) 13912612Seric finis(); 14012612Seric QuickAbort = FALSE; 14112612Seric HoldErrs = FALSE; 14251951Seric LogUsrErrs = FALSE; 14358092Seric e->e_flags &= ~EF_VRFYONLY; 14412612Seric 1457356Seric /* setup for the read */ 14655012Seric e->e_to = NULL; 1474577Seric Errors = 0; 1487275Seric (void) fflush(stdout); 1497356Seric 1507356Seric /* read the input line */ 15158109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1527356Seric 1537685Seric /* handle errors */ 1547356Seric if (p == NULL) 1557356Seric { 1564549Seric /* end of file, just die */ 15758151Seric message("421 %s Lost input channel from %s", 15825050Seric MyHostName, CurHostName); 15955464Seric #ifdef LOG 16058020Seric if (LogLevel > 1) 16155464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16255464Seric CurHostName); 16355464Seric #endif 16458069Seric if (InChild) 16558069Seric ExitStat = EX_QUIT; 1664549Seric finis(); 1674549Seric } 1684549Seric 1694549Seric /* clean up end of line */ 1704558Seric fixcrlf(inp, TRUE); 1714549Seric 1724713Seric /* echo command to transcript */ 17355012Seric if (e->e_xfp != NULL) 17455012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1754713Seric 1764549Seric /* break off command */ 17758050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1784549Seric continue; 17957232Seric cmd = cmdbuf; 18058050Seric while (*p != '\0' && 18158050Seric !(isascii(*p) && isspace(*p)) && 18258050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 18324981Seric *cmd++ = *p++; 18424981Seric *cmd = '\0'; 1854549Seric 18625691Seric /* throw away leading whitespace */ 18758050Seric while (isascii(*p) && isspace(*p)) 18825691Seric p++; 18925691Seric 1904549Seric /* decode command */ 1914549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1924549Seric { 19333725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1944549Seric break; 1954549Seric } 1964549Seric 19751954Seric /* reset errors */ 19851954Seric errno = 0; 19951954Seric 2004549Seric /* process command */ 2014549Seric switch (c->cmdcode) 2024549Seric { 2034976Seric case CMDHELO: /* hello -- introduce yourself */ 20458323Seric case CMDEHLO: /* extended hello */ 20558323Seric if (c->cmdcode == CMDEHLO) 20658323Seric { 20758323Seric protocol = "ESMTP"; 20858323Seric SmtpPhase = "EHLO"; 20958323Seric } 21058323Seric else 21158323Seric { 21258323Seric protocol = "SMTP"; 21358323Seric SmtpPhase = "HELO"; 21458323Seric } 21525050Seric setproctitle("%s: %s", CurHostName, inp); 216*59016Seric sendinghost = newstr(p); 21758308Seric if (strcasecmp(p, RealHostName) != 0) 21811146Seric { 21958789Seric auth_warning(e, "Host %s claimed to be %s", 22058789Seric RealHostName, p); 22111146Seric } 22258957Seric p = macvalue('_', e); 22358957Seric if (p == NULL) 224*59016Seric p = RealHostName; 22558323Seric 22658323Seric /* send ext. message -- old systems must ignore */ 22758323Seric message("250-%s Hello %s, pleased to meet you", 22858957Seric MyHostName, p); 22958323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 23058323Seric message("250-EXPN"); 23158338Seric message("250-SIZE"); 23258323Seric message("250 HELP"); 23358082Seric gothello = TRUE; 2344976Seric break; 2354976Seric 2364549Seric case CMDMAIL: /* mail -- designate sender */ 23724943Seric SmtpPhase = "MAIL"; 23824943Seric 2399314Seric /* check for validity of this command */ 24058789Seric if (!gothello) 24158082Seric { 24258957Seric /* set sending host to our known value */ 243*59016Seric if (sendinghost == NULL) 244*59016Seric sendinghost = RealHostName; 24558957Seric 24658789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 24758821Seric { 24858789Seric message("503 Polite people say HELO first"); 24958821Seric break; 25058821Seric } 25158789Seric else 25258821Seric { 25358789Seric auth_warning(e, 25458789Seric "Host %s didn't use HELO protocol", 25558789Seric RealHostName); 25658821Seric } 25758082Seric } 25858109Seric if (gotmail) 2594558Seric { 26058151Seric message("503 Sender already specified"); 2614558Seric break; 2624558Seric } 2639339Seric if (InChild) 2649339Seric { 26536230Skarels errno = 0; 26658151Seric syserr("503 Nested MAIL command: MAIL %s", p); 26758069Seric finis(); 2689339Seric } 2699339Seric 2709339Seric /* fork a subprocess to process this command */ 27155012Seric if (runinchild("SMTP-MAIL", e) > 0) 2729339Seric break; 27358323Seric if (protocol == NULL) 27458323Seric protocol = "SMTP"; 27558323Seric define('r', protocol, e); 276*59016Seric define('s', sendinghost, e); 27755012Seric initsys(e); 27857389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2799339Seric 2809339Seric /* child -- go do the processing */ 2814549Seric p = skipword(p, "from"); 2824549Seric if (p == NULL) 2834549Seric break; 28457977Seric if (setjmp(TopFrame) > 0) 28558147Seric { 28658147Seric /* this failed -- undo work */ 28758147Seric if (InChild) 28858147Seric finis(); 28957977Seric break; 29058147Seric } 29157977Seric QuickAbort = TRUE; 29258333Seric 29358333Seric /* must parse sender first */ 29458333Seric delimptr = NULL; 29558704Seric setsender(p, e, &delimptr, FALSE); 29658333Seric p = delimptr; 29758333Seric if (p != NULL && *p != '\0') 29858333Seric *p++ = '\0'; 29958333Seric 30058333Seric /* now parse ESMTP arguments */ 30158333Seric msize = 0; 30258333Seric for (; p != NULL && *p != '\0'; p++) 30358333Seric { 30458333Seric char *kp; 30558333Seric char *vp; 30658333Seric 30758333Seric /* locate the beginning of the keyword */ 30858333Seric while (isascii(*p) && isspace(*p)) 30958333Seric p++; 31058333Seric if (*p == '\0') 31158333Seric break; 31258333Seric kp = p; 31358333Seric 31458333Seric /* skip to the value portion */ 31558333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 31658333Seric p++; 31758333Seric if (*p == '=') 31858333Seric { 31958333Seric *p++ = '\0'; 32058333Seric vp = p; 32158333Seric 32258333Seric /* skip to the end of the value */ 32358333Seric while (*p != '\0' && *p != ' ' && 32458333Seric !(isascii(*p) && iscntrl(*p)) && 32558333Seric *p != '=') 32658333Seric p++; 32758333Seric } 32858333Seric 32958333Seric if (*p != '\0') 33058333Seric *p++ = '\0'; 33158333Seric 33258333Seric if (tTd(19, 1)) 33358333Seric printf("MAIL: got arg %s=%s\n", kp, 33458333Seric vp == NULL ? "<null>" : vp); 33558333Seric 33658333Seric if (strcasecmp(kp, "size") == 0) 33758333Seric { 33858333Seric if (kp == NULL) 33958333Seric { 34058333Seric usrerr("501 SIZE requires a value"); 34158333Seric /* NOTREACHED */ 34258333Seric } 34358333Seric msize = atol(vp); 34458333Seric } 34558333Seric else 34658333Seric { 34758333Seric usrerr("501 %s parameter unrecognized", kp); 34858333Seric /* NOTREACHED */ 34958333Seric } 35058333Seric } 35158333Seric 35258333Seric if (!enoughspace(msize)) 35358333Seric { 35458333Seric message("452 Insufficient disk space; try again later"); 35558333Seric break; 35658333Seric } 35758151Seric message("250 Sender ok"); 35858147Seric gotmail = TRUE; 3594549Seric break; 3604549Seric 3614976Seric case CMDRCPT: /* rcpt -- designate recipient */ 36258850Seric if (!gotmail) 36358850Seric { 36458850Seric usrerr("503 Need MAIL before RCPT"); 36558850Seric break; 36658850Seric } 36724943Seric SmtpPhase = "RCPT"; 36857389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 36912612Seric if (setjmp(TopFrame) > 0) 37014785Seric { 37155012Seric e->e_flags &= ~EF_FATALERRS; 37212612Seric break; 37314785Seric } 37412612Seric QuickAbort = TRUE; 37551951Seric LogUsrErrs = TRUE; 37658093Seric 37758919Seric e->e_flags |= EF_VRFYONLY; 37858919Seric 3794549Seric p = skipword(p, "to"); 3804549Seric if (p == NULL) 3814549Seric break; 38258333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 38312612Seric if (a == NULL) 38412612Seric break; 38516886Seric a->q_flags |= QPRIMARY; 38655012Seric a = recipient(a, &e->e_sendqueue, e); 38712612Seric if (Errors != 0) 38812612Seric break; 38912612Seric 39012612Seric /* no errors during parsing, but might be a duplicate */ 39155012Seric e->e_to = p; 39212612Seric if (!bitset(QBADADDR, a->q_flags)) 39358151Seric message("250 Recipient ok"); 39412612Seric else 3954549Seric { 39612612Seric /* punt -- should keep message in ADDRESS.... */ 39758151Seric message("550 Addressee unknown"); 3984549Seric } 39955012Seric e->e_to = NULL; 4004549Seric break; 4014549Seric 4024549Seric case CMDDATA: /* data -- text of mail */ 40324943Seric SmtpPhase = "DATA"; 40458109Seric if (!gotmail) 4054549Seric { 40658151Seric message("503 Need MAIL command"); 4074976Seric break; 4084549Seric } 40955012Seric else if (e->e_nrcpts <= 0) 4104549Seric { 41158151Seric message("503 Need RCPT (recipient)"); 4124976Seric break; 4134549Seric } 4144976Seric 41558929Seric /* check to see if we need to re-expand aliases */ 41658929Seric for (a = e->e_sendqueue; a != NULL; a = a->q_next) 41758929Seric { 41858929Seric if (bitset(QVERIFIED, a->q_flags)) 41958929Seric break; 42058929Seric } 42158929Seric 4224976Seric /* collect the text of the message */ 42324943Seric SmtpPhase = "collect"; 42457389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 42558929Seric collect(TRUE, a != NULL, e); 4264976Seric if (Errors != 0) 4274976Seric break; 4284976Seric 4298238Seric /* 4308238Seric ** Arrange to send to everyone. 4318238Seric ** If sending to multiple people, mail back 4328238Seric ** errors rather than reporting directly. 4338238Seric ** In any case, don't mail back errors for 4348238Seric ** anything that has happened up to 4358238Seric ** now (the other end will do this). 43610197Seric ** Truncate our transcript -- the mail has gotten 43710197Seric ** to us successfully, and if we have 43810197Seric ** to mail this back, it will be easier 43910197Seric ** on the reader. 4408238Seric ** Then send to everyone. 4418238Seric ** Finally give a reply code. If an error has 4428238Seric ** already been given, don't mail a 4438238Seric ** message back. 4449339Seric ** We goose error returns by clearing error bit. 4458238Seric */ 4468238Seric 44724943Seric SmtpPhase = "delivery"; 44855012Seric if (e->e_nrcpts != 1) 4499378Seric { 4509378Seric HoldErrs = TRUE; 45158734Seric e->e_errormode = EM_MAIL; 4529378Seric } 45355012Seric e->e_flags &= ~EF_FATALERRS; 45455012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 45558714Seric id = e->e_id; 4564976Seric 4574976Seric /* send to all recipients */ 45858919Seric sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 45955012Seric e->e_to = NULL; 4604976Seric 46123516Seric /* save statistics */ 46255012Seric markstats(e, (ADDRESS *) NULL); 46323516Seric 4648238Seric /* issue success if appropriate and reset */ 4658238Seric if (Errors == 0 || HoldErrs) 46658855Seric message("250 %s Message accepted for delivery", id); 4678238Seric else 46855012Seric e->e_flags &= ~EF_FATALERRS; 4699339Seric 47058919Seric /* if we just queued, poke it */ 47158919Seric if (a != NULL && e->e_sendmode != SM_QUEUE) 47258919Seric { 47358919Seric unlockqueue(e); 47458924Seric dowork(id, TRUE, TRUE, e); 47558919Seric e->e_id = NULL; 47658919Seric } 47758883Seric 4789339Seric /* if in a child, pop back to our parent */ 4799339Seric if (InChild) 4809339Seric finis(); 48124943Seric 48224943Seric /* clean up a bit */ 48358109Seric gotmail = FALSE; 48455012Seric dropenvelope(e); 48558179Seric CurEnv = e = newenvelope(e, CurEnv); 48655012Seric e->e_flags = BlankEnvelope.e_flags; 4874549Seric break; 4884549Seric 4894549Seric case CMDRSET: /* rset -- reset state */ 49058151Seric message("250 Reset state"); 4919339Seric if (InChild) 4929339Seric finis(); 49358109Seric 49458109Seric /* clean up a bit */ 49558109Seric gotmail = FALSE; 49658109Seric dropenvelope(e); 49758179Seric CurEnv = e = newenvelope(e, CurEnv); 4989339Seric break; 4994549Seric 5004549Seric case CMDVRFY: /* vrfy -- verify address */ 50158092Seric case CMDEXPN: /* expn -- expand address */ 50258092Seric vrfy = c->cmdcode == CMDVRFY; 50358092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 50458092Seric PrivacyFlags)) 50558082Seric { 50658412Seric if (vrfy) 50758412Seric message("252 Who's to say?"); 50858412Seric else 50958412Seric message("502 That's none of your business"); 51058082Seric break; 51158082Seric } 51258082Seric else if (!gothello && 51358092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 51458092Seric PrivacyFlags)) 51558082Seric { 51658151Seric message("503 I demand that you introduce yourself first"); 51758082Seric break; 51858082Seric } 51958092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5209339Seric break; 52125050Seric setproctitle("%s: %s", CurHostName, inp); 52255173Seric #ifdef LOG 52358020Seric if (LogLevel > 5) 52455173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 52555173Seric #endif 5265003Seric vrfyqueue = NULL; 5277762Seric QuickAbort = TRUE; 52858092Seric if (vrfy) 52958092Seric e->e_flags |= EF_VRFYONLY; 53058082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5317762Seric if (Errors != 0) 5329339Seric { 5339339Seric if (InChild) 5349339Seric finis(); 5357762Seric break; 5369339Seric } 5375003Seric while (vrfyqueue != NULL) 5385003Seric { 5395003Seric register ADDRESS *a = vrfyqueue->q_next; 5405003Seric char *code; 5415003Seric 5427685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5435003Seric a = a->q_next; 5445003Seric 5457685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 54658151Seric printvrfyaddr(vrfyqueue, a == NULL); 5475003Seric else if (a == NULL) 54858151Seric message("554 Self destructive alias loop"); 5495003Seric vrfyqueue = a; 5505003Seric } 5519339Seric if (InChild) 5529339Seric finis(); 5534549Seric break; 5544549Seric 5554549Seric case CMDHELP: /* help -- give user info */ 5564577Seric help(p); 5574549Seric break; 5584549Seric 5594549Seric case CMDNOOP: /* noop -- do nothing */ 56058151Seric message("200 OK"); 5614549Seric break; 5624549Seric 5634549Seric case CMDQUIT: /* quit -- leave mail */ 56458151Seric message("221 %s closing connection", MyHostName); 5659339Seric if (InChild) 5669339Seric ExitStat = EX_QUIT; 5674549Seric finis(); 5684549Seric 5698544Seric case CMDVERB: /* set verbose mode */ 5708544Seric Verbose = TRUE; 57158734Seric e->e_sendmode = SM_DELIVER; 57258151Seric message("200 Verbose mode"); 5738544Seric break; 5748544Seric 5759314Seric case CMDONEX: /* doing one transaction only */ 5769378Seric OneXact = TRUE; 57758151Seric message("200 Only one transaction"); 5789314Seric break; 5799314Seric 58036230Skarels # ifdef SMTPDEBUG 5819339Seric case CMDDBGQSHOW: /* show queues */ 5826907Seric printf("Send Queue="); 58355012Seric printaddr(e->e_sendqueue, TRUE); 5845003Seric break; 5857275Seric 5867275Seric case CMDDBGDEBUG: /* set debug mode */ 5877676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5887676Seric tTflag(p); 58958151Seric message("200 Debug set"); 5907275Seric break; 5917275Seric 59236230Skarels # else /* not SMTPDEBUG */ 59324945Seric 59436230Skarels case CMDDBGQSHOW: /* show queues */ 59536230Skarels case CMDDBGDEBUG: /* set debug mode */ 59636233Skarels # ifdef LOG 59758308Seric if (LogLevel > 0) 59836230Skarels syslog(LOG_NOTICE, 59958020Seric "\"%s\" command from %s (%s)", 60036230Skarels c->cmdname, RealHostName, 60158755Seric anynet_ntoa(&RealHostAddr)); 60236233Skarels # endif 60336230Skarels /* FALL THROUGH */ 60436230Skarels # endif /* SMTPDEBUG */ 60536230Skarels 6064549Seric case CMDERROR: /* unknown command */ 60758151Seric message("500 Command unrecognized"); 6084549Seric break; 6094549Seric 6104549Seric default: 61136230Skarels errno = 0; 61258151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6134549Seric break; 6144549Seric } 6154549Seric } 6164549Seric } 6174549Seric /* 6184549Seric ** SKIPWORD -- skip a fixed word. 6194549Seric ** 6204549Seric ** Parameters: 6214549Seric ** p -- place to start looking. 6224549Seric ** w -- word to skip. 6234549Seric ** 6244549Seric ** Returns: 6254549Seric ** p following w. 6264549Seric ** NULL on error. 6274549Seric ** 6284549Seric ** Side Effects: 6294549Seric ** clobbers the p data area. 6304549Seric */ 6314549Seric 6324549Seric static char * 6334549Seric skipword(p, w) 6344549Seric register char *p; 6354549Seric char *w; 6364549Seric { 6374549Seric register char *q; 6384549Seric 6394549Seric /* find beginning of word */ 64058050Seric while (isascii(*p) && isspace(*p)) 6414549Seric p++; 6424549Seric q = p; 6434549Seric 6444549Seric /* find end of word */ 64558050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6464549Seric p++; 64758050Seric while (isascii(*p) && isspace(*p)) 6484549Seric *p++ = '\0'; 6494549Seric if (*p != ':') 6504549Seric { 6514549Seric syntax: 65258151Seric message("501 Syntax error"); 6534549Seric Errors++; 6544549Seric return (NULL); 6554549Seric } 6564549Seric *p++ = '\0'; 65758050Seric while (isascii(*p) && isspace(*p)) 6584549Seric p++; 6594549Seric 6604549Seric /* see if the input word matches desired word */ 66133725Sbostic if (strcasecmp(q, w)) 6624549Seric goto syntax; 6634549Seric 6644549Seric return (p); 6654549Seric } 6664577Seric /* 66758151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 66858151Seric ** 66958151Seric ** Parameters: 67058151Seric ** a -- the address to print 67158151Seric ** last -- set if this is the last one. 67258151Seric ** 67358151Seric ** Returns: 67458151Seric ** none. 67558151Seric ** 67658151Seric ** Side Effects: 67758151Seric ** Prints the appropriate 250 codes. 67858151Seric */ 67958151Seric 68058151Seric printvrfyaddr(a, last) 68158151Seric register ADDRESS *a; 68258151Seric bool last; 68358151Seric { 68458151Seric char fmtbuf[20]; 68558151Seric 68658151Seric strcpy(fmtbuf, "250"); 68758151Seric fmtbuf[3] = last ? ' ' : '-'; 68858151Seric 68958151Seric if (strchr(a->q_paddr, '<') != NULL) 69058151Seric strcpy(&fmtbuf[4], "%s"); 69158151Seric else if (a->q_fullname == NULL) 69258151Seric strcpy(&fmtbuf[4], "<%s>"); 69358151Seric else 69458151Seric { 69558151Seric strcpy(&fmtbuf[4], "%s <%s>"); 69658151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 69758151Seric return; 69858151Seric } 69958151Seric message(fmtbuf, a->q_paddr); 70058151Seric } 70158151Seric /* 7024577Seric ** HELP -- implement the HELP command. 7034577Seric ** 7044577Seric ** Parameters: 7054577Seric ** topic -- the topic we want help for. 7064577Seric ** 7074577Seric ** Returns: 7084577Seric ** none. 7094577Seric ** 7104577Seric ** Side Effects: 7114577Seric ** outputs the help file to message output. 7124577Seric */ 7134577Seric 7144577Seric help(topic) 7154577Seric char *topic; 7164577Seric { 7174577Seric register FILE *hf; 7184577Seric int len; 7194577Seric char buf[MAXLINE]; 7204577Seric bool noinfo; 7214577Seric 7228269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7234577Seric { 7244577Seric /* no help */ 72511931Seric errno = 0; 72658151Seric message("502 HELP not implemented"); 7274577Seric return; 7284577Seric } 7294577Seric 73049669Seric if (topic == NULL || *topic == '\0') 73149669Seric topic = "smtp"; 73249669Seric else 73349669Seric makelower(topic); 73449669Seric 7354577Seric len = strlen(topic); 7364577Seric noinfo = TRUE; 7374577Seric 7384577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7394577Seric { 7404577Seric if (strncmp(buf, topic, len) == 0) 7414577Seric { 7424577Seric register char *p; 7434577Seric 74456795Seric p = strchr(buf, '\t'); 7454577Seric if (p == NULL) 7464577Seric p = buf; 7474577Seric else 7484577Seric p++; 7494577Seric fixcrlf(p, TRUE); 75058151Seric message("214-%s", p); 7514577Seric noinfo = FALSE; 7524577Seric } 7534577Seric } 7544577Seric 7554577Seric if (noinfo) 75658151Seric message("504 HELP topic unknown"); 7574577Seric else 75858151Seric message("214 End of HELP info"); 7594628Seric (void) fclose(hf); 7604577Seric } 7618544Seric /* 7629339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7639339Seric ** 7649339Seric ** Parameters: 7659339Seric ** label -- a string used in error messages 7669339Seric ** 7679339Seric ** Returns: 7689339Seric ** zero in the child 7699339Seric ** one in the parent 7709339Seric ** 7719339Seric ** Side Effects: 7729339Seric ** none. 7739339Seric */ 7748544Seric 77555012Seric runinchild(label, e) 7769339Seric char *label; 77755012Seric register ENVELOPE *e; 7789339Seric { 7799339Seric int childpid; 7809339Seric 78116158Seric if (!OneXact) 7829339Seric { 78316158Seric childpid = dofork(); 78416158Seric if (childpid < 0) 78516158Seric { 78616158Seric syserr("%s: cannot fork", label); 78716158Seric return (1); 78816158Seric } 78916158Seric if (childpid > 0) 79016158Seric { 79116158Seric auto int st; 7929339Seric 79316158Seric /* parent -- wait for child to complete */ 79416158Seric st = waitfor(childpid); 79516158Seric if (st == -1) 79616158Seric syserr("%s: lost child", label); 7979339Seric 79816158Seric /* if we exited on a QUIT command, complete the process */ 79916158Seric if (st == (EX_QUIT << 8)) 80016158Seric finis(); 8019339Seric 80216158Seric return (1); 80316158Seric } 80416158Seric else 80516158Seric { 80616158Seric /* child */ 80716158Seric InChild = TRUE; 80825050Seric QuickAbort = FALSE; 80955012Seric clearenvelope(e, FALSE); 81016158Seric } 8119339Seric } 81215256Seric 81316158Seric /* open alias database */ 81455012Seric initaliases(AliasFile, FALSE, e); 81516158Seric 81616158Seric return (0); 8179339Seric } 8189339Seric 81956795Seric # endif /* SMTP */ 820