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*60537Seric static char sccsid[] = "@(#)srvrsmtp.c 6.57 (Berkeley) 05/28/93 (with SMTP)"; 1433731Sbostic #else 15*60537Seric static char sccsid[] = "@(#)srvrsmtp.c 6.57 (Berkeley) 05/28/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 */ 10659016Seric char *sendinghost; /* sending hostname */ 10758333Seric long msize; /* approximate maximum message size */ 10858333Seric auto char *delimptr; 10958714Seric char *id; 11059747Seric int nrcpts; /* number of RCPT commands */ 1118544Seric char inp[MAXLINE]; 11257232Seric char cmdbuf[MAXLINE]; 1137124Seric extern char Version[]; 11424943Seric extern ENVELOPE BlankEnvelope; 1154549Seric 11659066Seric if (fileno(OutChannel) != fileno(stdout)) 1177363Seric { 1187363Seric /* arrange for debugging output to go to remote host */ 11959066Seric (void) dup2(fileno(OutChannel), fileno(stdout)); 1207363Seric } 12155012Seric settime(e); 12257642Seric CurHostName = RealHostName; 12359060Seric setproctitle("srvrsmtp %s startup", CurHostName); 12458050Seric expand("\201e", inp, &inp[sizeof inp], e); 12560210Seric message("220-%s", inp); 12660210Seric message("220 ESMTP spoken here"); 12758330Seric protocol = NULL; 12859016Seric sendinghost = macvalue('s', e); 12958082Seric gothello = FALSE; 13058330Seric gotmail = FALSE; 1314549Seric for (;;) 1324549Seric { 13312612Seric /* arrange for backout */ 13412612Seric if (setjmp(TopFrame) > 0 && InChild) 13559058Seric { 13659058Seric QuickAbort = FALSE; 13759058Seric SuprErrs = TRUE; 13812612Seric finis(); 13959058Seric } 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 */ 15159060Seric SmtpPhase = "srvrsmtp cmd read"; 15259060Seric setproctitle("srvrsmtp %s cmd read", CurHostName); 15358109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1547356Seric 1557685Seric /* handle errors */ 1567356Seric if (p == NULL) 1577356Seric { 1584549Seric /* end of file, just die */ 15958151Seric message("421 %s Lost input channel from %s", 16025050Seric MyHostName, CurHostName); 16155464Seric #ifdef LOG 16258020Seric if (LogLevel > 1) 16355464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16455464Seric CurHostName); 16555464Seric #endif 16658069Seric if (InChild) 16758069Seric ExitStat = EX_QUIT; 1684549Seric finis(); 1694549Seric } 1704549Seric 1714549Seric /* clean up end of line */ 1724558Seric fixcrlf(inp, TRUE); 1734549Seric 1744713Seric /* echo command to transcript */ 17555012Seric if (e->e_xfp != NULL) 17655012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1774713Seric 17859060Seric if (e->e_id == NULL) 17959060Seric setproctitle("%s: %s", CurHostName, inp); 18059060Seric else 18159060Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 18259060Seric 1834549Seric /* break off command */ 18458050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1854549Seric continue; 18657232Seric cmd = cmdbuf; 18758050Seric while (*p != '\0' && 18858050Seric !(isascii(*p) && isspace(*p)) && 18958050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 19024981Seric *cmd++ = *p++; 19124981Seric *cmd = '\0'; 1924549Seric 19325691Seric /* throw away leading whitespace */ 19458050Seric while (isascii(*p) && isspace(*p)) 19525691Seric p++; 19625691Seric 1974549Seric /* decode command */ 1984549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1994549Seric { 20033725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 2014549Seric break; 2024549Seric } 2034549Seric 20451954Seric /* reset errors */ 20551954Seric errno = 0; 20651954Seric 2074549Seric /* process command */ 2084549Seric switch (c->cmdcode) 2094549Seric { 2104976Seric case CMDHELO: /* hello -- introduce yourself */ 21158323Seric case CMDEHLO: /* extended hello */ 21258323Seric if (c->cmdcode == CMDEHLO) 21358323Seric { 21458323Seric protocol = "ESMTP"; 21558323Seric SmtpPhase = "EHLO"; 21658323Seric } 21758323Seric else 21858323Seric { 21958323Seric protocol = "SMTP"; 22058323Seric SmtpPhase = "HELO"; 22158323Seric } 22259016Seric sendinghost = newstr(p); 22358308Seric if (strcasecmp(p, RealHostName) != 0) 22411146Seric { 22558789Seric auth_warning(e, "Host %s claimed to be %s", 22658789Seric RealHostName, p); 22711146Seric } 22858957Seric p = macvalue('_', e); 22958957Seric if (p == NULL) 23059016Seric p = RealHostName; 23158323Seric 23260210Seric gothello = TRUE; 23360210Seric if (c->cmdcode != CMDEHLO) 23460239Seric { 23560239Seric /* print old message and be done with it */ 23660239Seric message("250 %s Hello %s, pleased to meet you", 23760239Seric MyHostName, p); 23860210Seric break; 23960239Seric } 24060239Seric 24160239Seric /* print extended message and brag */ 24260239Seric message("250-%s Hello %s, pleased to meet you", 24360239Seric MyHostName, p); 24458323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 24558323Seric message("250-EXPN"); 24659271Seric if (MaxMessageSize > 0) 24759271Seric message("250-SIZE %ld", MaxMessageSize); 24859271Seric else 24959271Seric message("250-SIZE"); 25058323Seric message("250 HELP"); 2514976Seric break; 2524976Seric 2534549Seric case CMDMAIL: /* mail -- designate sender */ 25424943Seric SmtpPhase = "MAIL"; 25524943Seric 2569314Seric /* check for validity of this command */ 25758789Seric if (!gothello) 25858082Seric { 25958957Seric /* set sending host to our known value */ 26059016Seric if (sendinghost == NULL) 26159016Seric sendinghost = RealHostName; 26258957Seric 26358789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 26458821Seric { 26558789Seric message("503 Polite people say HELO first"); 26658821Seric break; 26758821Seric } 26858789Seric else 26958821Seric { 27058789Seric auth_warning(e, 27158789Seric "Host %s didn't use HELO protocol", 27258789Seric RealHostName); 27358821Seric } 27458082Seric } 27558109Seric if (gotmail) 2764558Seric { 27758151Seric message("503 Sender already specified"); 2784558Seric break; 2794558Seric } 2809339Seric if (InChild) 2819339Seric { 28236230Skarels errno = 0; 28358151Seric syserr("503 Nested MAIL command: MAIL %s", p); 28458069Seric finis(); 2859339Seric } 2869339Seric 2879339Seric /* fork a subprocess to process this command */ 28855012Seric if (runinchild("SMTP-MAIL", e) > 0) 2899339Seric break; 29058323Seric if (protocol == NULL) 29158323Seric protocol = "SMTP"; 29258323Seric define('r', protocol, e); 29359016Seric define('s', sendinghost, e); 29455012Seric initsys(e); 29559747Seric nrcpts = 0; 29657389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2979339Seric 2989339Seric /* child -- go do the processing */ 2994549Seric p = skipword(p, "from"); 3004549Seric if (p == NULL) 3014549Seric break; 30257977Seric if (setjmp(TopFrame) > 0) 30358147Seric { 30458147Seric /* this failed -- undo work */ 30558147Seric if (InChild) 30659058Seric { 30759058Seric QuickAbort = FALSE; 30859058Seric SuprErrs = TRUE; 30958147Seric finis(); 31059058Seric } 31157977Seric break; 31258147Seric } 31357977Seric QuickAbort = TRUE; 31458333Seric 31558333Seric /* must parse sender first */ 31658333Seric delimptr = NULL; 31758704Seric setsender(p, e, &delimptr, FALSE); 31858333Seric p = delimptr; 31958333Seric if (p != NULL && *p != '\0') 32058333Seric *p++ = '\0'; 32158333Seric 32258333Seric /* now parse ESMTP arguments */ 32358333Seric msize = 0; 32458333Seric for (; p != NULL && *p != '\0'; p++) 32558333Seric { 32658333Seric char *kp; 32758333Seric char *vp; 32858333Seric 32958333Seric /* locate the beginning of the keyword */ 33058333Seric while (isascii(*p) && isspace(*p)) 33158333Seric p++; 33258333Seric if (*p == '\0') 33358333Seric break; 33458333Seric kp = p; 33558333Seric 33658333Seric /* skip to the value portion */ 33758333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 33858333Seric p++; 33958333Seric if (*p == '=') 34058333Seric { 34158333Seric *p++ = '\0'; 34258333Seric vp = p; 34358333Seric 34458333Seric /* skip to the end of the value */ 34558333Seric while (*p != '\0' && *p != ' ' && 34658333Seric !(isascii(*p) && iscntrl(*p)) && 34758333Seric *p != '=') 34858333Seric p++; 34958333Seric } 35058333Seric 35158333Seric if (*p != '\0') 35258333Seric *p++ = '\0'; 35358333Seric 35458333Seric if (tTd(19, 1)) 35558333Seric printf("MAIL: got arg %s=%s\n", kp, 35658333Seric vp == NULL ? "<null>" : vp); 35758333Seric 35858333Seric if (strcasecmp(kp, "size") == 0) 35958333Seric { 36059093Seric if (vp == NULL) 36158333Seric { 36258333Seric usrerr("501 SIZE requires a value"); 36358333Seric /* NOTREACHED */ 36458333Seric } 36558333Seric msize = atol(vp); 36658333Seric } 36759093Seric else if (strcasecmp(kp, "body") == 0) 36859093Seric { 36959093Seric if (vp == NULL) 37059093Seric { 37159093Seric usrerr("501 BODY requires a value"); 37259093Seric /* NOTREACHED */ 37359093Seric } 37459093Seric # ifdef MIME 37559093Seric if (strcasecmp(vp, "8bitmime") == 0) 37659093Seric { 37759093Seric e->e_bodytype = "8BITMIME"; 37859709Seric SevenBit = FALSE; 37959093Seric } 38059093Seric else if (strcasecmp(vp, "7bit") == 0) 38159093Seric { 38259093Seric e->e_bodytype = "7BIT"; 38359709Seric SevenBit = TRUE; 38459093Seric } 38559093Seric else 38659093Seric { 38759093Seric usrerr("501 Unknown BODY type %s", 38859093Seric vp); 38959093Seric } 39059093Seric # endif 39159093Seric } 39258333Seric else 39358333Seric { 39458333Seric usrerr("501 %s parameter unrecognized", kp); 39558333Seric /* NOTREACHED */ 39658333Seric } 39758333Seric } 39859284Seric 39959284Seric if (MaxMessageSize > 0 && msize > MaxMessageSize) 40059284Seric { 40159284Seric usrerr("552 Message size exceeds fixed maximum message size (%ld)", 40259284Seric MaxMessageSize); 40359284Seric /* NOTREACHED */ 40459284Seric } 40558333Seric 40658333Seric if (!enoughspace(msize)) 40758333Seric { 40858333Seric message("452 Insufficient disk space; try again later"); 40958333Seric break; 41058333Seric } 41158151Seric message("250 Sender ok"); 41258147Seric gotmail = TRUE; 4134549Seric break; 4144549Seric 4154976Seric case CMDRCPT: /* rcpt -- designate recipient */ 41658850Seric if (!gotmail) 41758850Seric { 41858850Seric usrerr("503 Need MAIL before RCPT"); 41958850Seric break; 42058850Seric } 42124943Seric SmtpPhase = "RCPT"; 42212612Seric if (setjmp(TopFrame) > 0) 42314785Seric { 42455012Seric e->e_flags &= ~EF_FATALERRS; 42512612Seric break; 42614785Seric } 42712612Seric QuickAbort = TRUE; 42851951Seric LogUsrErrs = TRUE; 42958093Seric 43059699Seric if (e->e_sendmode != SM_DELIVER) 43159699Seric e->e_flags |= EF_VRFYONLY; 43258919Seric 4334549Seric p = skipword(p, "to"); 4344549Seric if (p == NULL) 4354549Seric break; 43658333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 43712612Seric if (a == NULL) 43812612Seric break; 43916886Seric a->q_flags |= QPRIMARY; 44055012Seric a = recipient(a, &e->e_sendqueue, e); 44112612Seric if (Errors != 0) 44212612Seric break; 44312612Seric 44412612Seric /* no errors during parsing, but might be a duplicate */ 44555012Seric e->e_to = p; 44612612Seric if (!bitset(QBADADDR, a->q_flags)) 44759747Seric { 44858151Seric message("250 Recipient ok"); 44959747Seric nrcpts++; 45059747Seric } 45112612Seric else 4524549Seric { 45312612Seric /* punt -- should keep message in ADDRESS.... */ 45458151Seric message("550 Addressee unknown"); 4554549Seric } 45655012Seric e->e_to = NULL; 4574549Seric break; 4584549Seric 4594549Seric case CMDDATA: /* data -- text of mail */ 46024943Seric SmtpPhase = "DATA"; 46158109Seric if (!gotmail) 4624549Seric { 46358151Seric message("503 Need MAIL command"); 4644976Seric break; 4654549Seric } 46655012Seric else if (e->e_nrcpts <= 0) 4674549Seric { 46858151Seric message("503 Need RCPT (recipient)"); 4694976Seric break; 4704549Seric } 4714976Seric 47258929Seric /* check to see if we need to re-expand aliases */ 47358929Seric for (a = e->e_sendqueue; a != NULL; a = a->q_next) 47458929Seric { 47558929Seric if (bitset(QVERIFIED, a->q_flags)) 47658929Seric break; 47758929Seric } 47858929Seric 4794976Seric /* collect the text of the message */ 48024943Seric SmtpPhase = "collect"; 48158929Seric collect(TRUE, a != NULL, e); 48259730Seric e->e_flags &= ~EF_FATALERRS; 4834976Seric if (Errors != 0) 48459747Seric goto abortmessage; 4854976Seric 4868238Seric /* 4878238Seric ** Arrange to send to everyone. 4888238Seric ** If sending to multiple people, mail back 4898238Seric ** errors rather than reporting directly. 4908238Seric ** In any case, don't mail back errors for 4918238Seric ** anything that has happened up to 4928238Seric ** now (the other end will do this). 49310197Seric ** Truncate our transcript -- the mail has gotten 49410197Seric ** to us successfully, and if we have 49510197Seric ** to mail this back, it will be easier 49610197Seric ** on the reader. 4978238Seric ** Then send to everyone. 4988238Seric ** Finally give a reply code. If an error has 4998238Seric ** already been given, don't mail a 5008238Seric ** message back. 5019339Seric ** We goose error returns by clearing error bit. 5028238Seric */ 5038238Seric 50424943Seric SmtpPhase = "delivery"; 50559747Seric if (nrcpts != 1 && a == NULL) 5069378Seric { 5079378Seric HoldErrs = TRUE; 50858734Seric e->e_errormode = EM_MAIL; 5099378Seric } 51055012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 51158714Seric id = e->e_id; 5124976Seric 5134976Seric /* send to all recipients */ 51458919Seric sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 51555012Seric e->e_to = NULL; 5164976Seric 51723516Seric /* save statistics */ 51855012Seric markstats(e, (ADDRESS *) NULL); 51923516Seric 5208238Seric /* issue success if appropriate and reset */ 5218238Seric if (Errors == 0 || HoldErrs) 52258855Seric message("250 %s Message accepted for delivery", id); 52359747Seric 52459747Seric if (bitset(EF_FATALERRS, e->e_flags) && !HoldErrs) 52559730Seric { 52659730Seric /* avoid sending back an extra message */ 52759730Seric e->e_flags &= ~EF_FATALERRS; 52859747Seric e->e_flags |= EF_CLRQUEUE; 52959730Seric } 5308238Seric else 53158919Seric { 53259747Seric /* from now on, we have to operate silently */ 53359747Seric HoldErrs = TRUE; 53459747Seric e->e_errormode = EM_MAIL; 53559747Seric 53659730Seric /* if we just queued, poke it */ 53759730Seric if (a != NULL && e->e_sendmode != SM_QUEUE) 53859730Seric { 53959730Seric unlockqueue(e); 54059730Seric dowork(id, TRUE, TRUE, e); 54159730Seric e->e_id = NULL; 54259730Seric } 54358919Seric } 54458883Seric 54559747Seric abortmessage: 5469339Seric /* if in a child, pop back to our parent */ 5479339Seric if (InChild) 5489339Seric finis(); 54924943Seric 55024943Seric /* clean up a bit */ 55158109Seric gotmail = FALSE; 55255012Seric dropenvelope(e); 55358179Seric CurEnv = e = newenvelope(e, CurEnv); 55455012Seric e->e_flags = BlankEnvelope.e_flags; 5554549Seric break; 5564549Seric 5574549Seric case CMDRSET: /* rset -- reset state */ 55858151Seric message("250 Reset state"); 5599339Seric if (InChild) 5609339Seric finis(); 56158109Seric 56258109Seric /* clean up a bit */ 56358109Seric gotmail = FALSE; 56458109Seric dropenvelope(e); 56558179Seric CurEnv = e = newenvelope(e, CurEnv); 5669339Seric break; 5674549Seric 5684549Seric case CMDVRFY: /* vrfy -- verify address */ 56958092Seric case CMDEXPN: /* expn -- expand address */ 57058092Seric vrfy = c->cmdcode == CMDVRFY; 57158092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 57258092Seric PrivacyFlags)) 57358082Seric { 57458412Seric if (vrfy) 57558412Seric message("252 Who's to say?"); 57658412Seric else 57758412Seric message("502 That's none of your business"); 57858082Seric break; 57958082Seric } 58058082Seric else if (!gothello && 58158092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 58258092Seric PrivacyFlags)) 58358082Seric { 58458151Seric message("503 I demand that you introduce yourself first"); 58558082Seric break; 58658082Seric } 58758092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5889339Seric break; 58955173Seric #ifdef LOG 59058020Seric if (LogLevel > 5) 59155173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 59255173Seric #endif 5935003Seric vrfyqueue = NULL; 5947762Seric QuickAbort = TRUE; 59558092Seric if (vrfy) 59658092Seric e->e_flags |= EF_VRFYONLY; 59758082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5987762Seric if (Errors != 0) 5999339Seric { 6009339Seric if (InChild) 6019339Seric finis(); 6027762Seric break; 6039339Seric } 6045003Seric while (vrfyqueue != NULL) 6055003Seric { 6065003Seric register ADDRESS *a = vrfyqueue->q_next; 6075003Seric char *code; 6085003Seric 6097685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 6105003Seric a = a->q_next; 6115003Seric 6127685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 61358151Seric printvrfyaddr(vrfyqueue, a == NULL); 6145003Seric else if (a == NULL) 61558151Seric message("554 Self destructive alias loop"); 6165003Seric vrfyqueue = a; 6175003Seric } 6189339Seric if (InChild) 6199339Seric finis(); 6204549Seric break; 6214549Seric 6224549Seric case CMDHELP: /* help -- give user info */ 6234577Seric help(p); 6244549Seric break; 6254549Seric 6264549Seric case CMDNOOP: /* noop -- do nothing */ 62758151Seric message("200 OK"); 6284549Seric break; 6294549Seric 6304549Seric case CMDQUIT: /* quit -- leave mail */ 63158151Seric message("221 %s closing connection", MyHostName); 6329339Seric if (InChild) 6339339Seric ExitStat = EX_QUIT; 6344549Seric finis(); 6354549Seric 6368544Seric case CMDVERB: /* set verbose mode */ 63759957Seric if (bitset(PRIV_NOEXPN, PrivacyFlags)) 63859957Seric { 63959957Seric /* this would give out the same info */ 64059957Seric message("502 Verbose unavailable"); 64159957Seric break; 64259957Seric } 6438544Seric Verbose = TRUE; 64458734Seric e->e_sendmode = SM_DELIVER; 64559957Seric message("250 Verbose mode"); 6468544Seric break; 6478544Seric 6489314Seric case CMDONEX: /* doing one transaction only */ 6499378Seric OneXact = TRUE; 65059957Seric message("250 Only one transaction"); 6519314Seric break; 6529314Seric 65336230Skarels # ifdef SMTPDEBUG 6549339Seric case CMDDBGQSHOW: /* show queues */ 6556907Seric printf("Send Queue="); 65655012Seric printaddr(e->e_sendqueue, TRUE); 6575003Seric break; 6587275Seric 6597275Seric case CMDDBGDEBUG: /* set debug mode */ 6607676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 6617676Seric tTflag(p); 66258151Seric message("200 Debug set"); 6637275Seric break; 6647275Seric 66536230Skarels # else /* not SMTPDEBUG */ 66624945Seric 66736230Skarels case CMDDBGQSHOW: /* show queues */ 66836230Skarels case CMDDBGDEBUG: /* set debug mode */ 66936233Skarels # ifdef LOG 67058308Seric if (LogLevel > 0) 67136230Skarels syslog(LOG_NOTICE, 67258020Seric "\"%s\" command from %s (%s)", 67336230Skarels c->cmdname, RealHostName, 67458755Seric anynet_ntoa(&RealHostAddr)); 67536233Skarels # endif 67636230Skarels /* FALL THROUGH */ 67736230Skarels # endif /* SMTPDEBUG */ 67836230Skarels 6794549Seric case CMDERROR: /* unknown command */ 68058151Seric message("500 Command unrecognized"); 6814549Seric break; 6824549Seric 6834549Seric default: 68436230Skarels errno = 0; 68558151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6864549Seric break; 6874549Seric } 6884549Seric } 6894549Seric } 6904549Seric /* 6914549Seric ** SKIPWORD -- skip a fixed word. 6924549Seric ** 6934549Seric ** Parameters: 6944549Seric ** p -- place to start looking. 6954549Seric ** w -- word to skip. 6964549Seric ** 6974549Seric ** Returns: 6984549Seric ** p following w. 6994549Seric ** NULL on error. 7004549Seric ** 7014549Seric ** Side Effects: 7024549Seric ** clobbers the p data area. 7034549Seric */ 7044549Seric 7054549Seric static char * 7064549Seric skipword(p, w) 7074549Seric register char *p; 7084549Seric char *w; 7094549Seric { 7104549Seric register char *q; 7114549Seric 7124549Seric /* find beginning of word */ 71358050Seric while (isascii(*p) && isspace(*p)) 7144549Seric p++; 7154549Seric q = p; 7164549Seric 7174549Seric /* find end of word */ 71858050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 7194549Seric p++; 72058050Seric while (isascii(*p) && isspace(*p)) 7214549Seric *p++ = '\0'; 7224549Seric if (*p != ':') 7234549Seric { 7244549Seric syntax: 72558151Seric message("501 Syntax error"); 7264549Seric Errors++; 7274549Seric return (NULL); 7284549Seric } 7294549Seric *p++ = '\0'; 73058050Seric while (isascii(*p) && isspace(*p)) 7314549Seric p++; 7324549Seric 7334549Seric /* see if the input word matches desired word */ 73433725Sbostic if (strcasecmp(q, w)) 7354549Seric goto syntax; 7364549Seric 7374549Seric return (p); 7384549Seric } 7394577Seric /* 74058151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 74158151Seric ** 74258151Seric ** Parameters: 74358151Seric ** a -- the address to print 74458151Seric ** last -- set if this is the last one. 74558151Seric ** 74658151Seric ** Returns: 74758151Seric ** none. 74858151Seric ** 74958151Seric ** Side Effects: 75058151Seric ** Prints the appropriate 250 codes. 75158151Seric */ 75258151Seric 75358151Seric printvrfyaddr(a, last) 75458151Seric register ADDRESS *a; 75558151Seric bool last; 75658151Seric { 75758151Seric char fmtbuf[20]; 75858151Seric 75958151Seric strcpy(fmtbuf, "250"); 76058151Seric fmtbuf[3] = last ? ' ' : '-'; 76158151Seric 76259746Seric if (a->q_fullname == NULL) 76359746Seric { 76459746Seric if (strchr(a->q_user, '@') == NULL) 76559746Seric strcpy(&fmtbuf[4], "<%s@%s>"); 76659746Seric else 76759746Seric strcpy(&fmtbuf[4], "<%s>"); 76859746Seric message(fmtbuf, a->q_user, MyHostName); 76959746Seric } 77058151Seric else 77158151Seric { 77259746Seric if (strchr(a->q_user, '@') == NULL) 77359746Seric strcpy(&fmtbuf[4], "%s <%s@%s>"); 77459746Seric else 77559746Seric strcpy(&fmtbuf[4], "%s <%s>"); 77659746Seric message(fmtbuf, a->q_fullname, a->q_user, MyHostName); 77758151Seric } 77858151Seric } 77958151Seric /* 7804577Seric ** HELP -- implement the HELP command. 7814577Seric ** 7824577Seric ** Parameters: 7834577Seric ** topic -- the topic we want help for. 7844577Seric ** 7854577Seric ** Returns: 7864577Seric ** none. 7874577Seric ** 7884577Seric ** Side Effects: 7894577Seric ** outputs the help file to message output. 7904577Seric */ 7914577Seric 7924577Seric help(topic) 7934577Seric char *topic; 7944577Seric { 7954577Seric register FILE *hf; 7964577Seric int len; 7974577Seric char buf[MAXLINE]; 7984577Seric bool noinfo; 7994577Seric 8008269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 8014577Seric { 8024577Seric /* no help */ 80311931Seric errno = 0; 80458151Seric message("502 HELP not implemented"); 8054577Seric return; 8064577Seric } 8074577Seric 80849669Seric if (topic == NULL || *topic == '\0') 80949669Seric topic = "smtp"; 81049669Seric else 81149669Seric makelower(topic); 81249669Seric 8134577Seric len = strlen(topic); 8144577Seric noinfo = TRUE; 8154577Seric 8164577Seric while (fgets(buf, sizeof buf, hf) != NULL) 8174577Seric { 8184577Seric if (strncmp(buf, topic, len) == 0) 8194577Seric { 8204577Seric register char *p; 8214577Seric 82256795Seric p = strchr(buf, '\t'); 8234577Seric if (p == NULL) 8244577Seric p = buf; 8254577Seric else 8264577Seric p++; 8274577Seric fixcrlf(p, TRUE); 82858151Seric message("214-%s", p); 8294577Seric noinfo = FALSE; 8304577Seric } 8314577Seric } 8324577Seric 8334577Seric if (noinfo) 83458151Seric message("504 HELP topic unknown"); 8354577Seric else 83658151Seric message("214 End of HELP info"); 8374628Seric (void) fclose(hf); 8384577Seric } 8398544Seric /* 8409339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 8419339Seric ** 8429339Seric ** Parameters: 8439339Seric ** label -- a string used in error messages 8449339Seric ** 8459339Seric ** Returns: 8469339Seric ** zero in the child 8479339Seric ** one in the parent 8489339Seric ** 8499339Seric ** Side Effects: 8509339Seric ** none. 8519339Seric */ 8528544Seric 85355012Seric runinchild(label, e) 8549339Seric char *label; 85555012Seric register ENVELOPE *e; 8569339Seric { 8579339Seric int childpid; 8589339Seric 85916158Seric if (!OneXact) 8609339Seric { 86116158Seric childpid = dofork(); 86216158Seric if (childpid < 0) 86316158Seric { 86416158Seric syserr("%s: cannot fork", label); 86516158Seric return (1); 86616158Seric } 86716158Seric if (childpid > 0) 86816158Seric { 86916158Seric auto int st; 8709339Seric 87116158Seric /* parent -- wait for child to complete */ 87259060Seric setproctitle("srvrsmtp %s child wait", CurHostName); 87316158Seric st = waitfor(childpid); 87416158Seric if (st == -1) 87516158Seric syserr("%s: lost child", label); 8769339Seric 87716158Seric /* if we exited on a QUIT command, complete the process */ 87816158Seric if (st == (EX_QUIT << 8)) 87916158Seric finis(); 8809339Seric 88116158Seric return (1); 88216158Seric } 88316158Seric else 88416158Seric { 88516158Seric /* child */ 88616158Seric InChild = TRUE; 88725050Seric QuickAbort = FALSE; 88855012Seric clearenvelope(e, FALSE); 88916158Seric } 8909339Seric } 89115256Seric 89216158Seric /* open alias database */ 893*60537Seric initmaps(FALSE, e); 89416158Seric 89516158Seric return (0); 8969339Seric } 8979339Seric 89856795Seric # endif /* SMTP */ 899