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*60239Seric static char sccsid[] = "@(#)srvrsmtp.c 6.55 (Berkeley) 05/23/93 (with SMTP)"; 1433731Sbostic #else 15*60239Seric static char sccsid[] = "@(#)srvrsmtp.c 6.55 (Berkeley) 05/23/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[]; 11411151Seric extern char *macvalue(); 11512612Seric extern ADDRESS *recipient(); 11624943Seric extern ENVELOPE BlankEnvelope; 11724943Seric extern ENVELOPE *newenvelope(); 11858755Seric extern char *anynet_ntoa(); 1194549Seric 12059066Seric if (fileno(OutChannel) != fileno(stdout)) 1217363Seric { 1227363Seric /* arrange for debugging output to go to remote host */ 12359066Seric (void) dup2(fileno(OutChannel), fileno(stdout)); 1247363Seric } 12555012Seric settime(e); 12657642Seric CurHostName = RealHostName; 12759060Seric setproctitle("srvrsmtp %s startup", CurHostName); 12858050Seric expand("\201e", inp, &inp[sizeof inp], e); 12960210Seric message("220-%s", inp); 13060210Seric message("220 ESMTP spoken here"); 13158330Seric protocol = NULL; 13259016Seric sendinghost = macvalue('s', e); 13358082Seric gothello = FALSE; 13458330Seric gotmail = FALSE; 1354549Seric for (;;) 1364549Seric { 13712612Seric /* arrange for backout */ 13812612Seric if (setjmp(TopFrame) > 0 && InChild) 13959058Seric { 14059058Seric QuickAbort = FALSE; 14159058Seric SuprErrs = TRUE; 14212612Seric finis(); 14359058Seric } 14412612Seric QuickAbort = FALSE; 14512612Seric HoldErrs = FALSE; 14651951Seric LogUsrErrs = FALSE; 14758092Seric e->e_flags &= ~EF_VRFYONLY; 14812612Seric 1497356Seric /* setup for the read */ 15055012Seric e->e_to = NULL; 1514577Seric Errors = 0; 1527275Seric (void) fflush(stdout); 1537356Seric 1547356Seric /* read the input line */ 15559060Seric SmtpPhase = "srvrsmtp cmd read"; 15659060Seric setproctitle("srvrsmtp %s cmd read", CurHostName); 15758109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1587356Seric 1597685Seric /* handle errors */ 1607356Seric if (p == NULL) 1617356Seric { 1624549Seric /* end of file, just die */ 16358151Seric message("421 %s Lost input channel from %s", 16425050Seric MyHostName, CurHostName); 16555464Seric #ifdef LOG 16658020Seric if (LogLevel > 1) 16755464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16855464Seric CurHostName); 16955464Seric #endif 17058069Seric if (InChild) 17158069Seric ExitStat = EX_QUIT; 1724549Seric finis(); 1734549Seric } 1744549Seric 1754549Seric /* clean up end of line */ 1764558Seric fixcrlf(inp, TRUE); 1774549Seric 1784713Seric /* echo command to transcript */ 17955012Seric if (e->e_xfp != NULL) 18055012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1814713Seric 18259060Seric if (e->e_id == NULL) 18359060Seric setproctitle("%s: %s", CurHostName, inp); 18459060Seric else 18559060Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 18659060Seric 1874549Seric /* break off command */ 18858050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1894549Seric continue; 19057232Seric cmd = cmdbuf; 19158050Seric while (*p != '\0' && 19258050Seric !(isascii(*p) && isspace(*p)) && 19358050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 19424981Seric *cmd++ = *p++; 19524981Seric *cmd = '\0'; 1964549Seric 19725691Seric /* throw away leading whitespace */ 19858050Seric while (isascii(*p) && isspace(*p)) 19925691Seric p++; 20025691Seric 2014549Seric /* decode command */ 2024549Seric for (c = CmdTab; c->cmdname != NULL; c++) 2034549Seric { 20433725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 2054549Seric break; 2064549Seric } 2074549Seric 20851954Seric /* reset errors */ 20951954Seric errno = 0; 21051954Seric 2114549Seric /* process command */ 2124549Seric switch (c->cmdcode) 2134549Seric { 2144976Seric case CMDHELO: /* hello -- introduce yourself */ 21558323Seric case CMDEHLO: /* extended hello */ 21658323Seric if (c->cmdcode == CMDEHLO) 21758323Seric { 21858323Seric protocol = "ESMTP"; 21958323Seric SmtpPhase = "EHLO"; 22058323Seric } 22158323Seric else 22258323Seric { 22358323Seric protocol = "SMTP"; 22458323Seric SmtpPhase = "HELO"; 22558323Seric } 22659016Seric sendinghost = newstr(p); 22758308Seric if (strcasecmp(p, RealHostName) != 0) 22811146Seric { 22958789Seric auth_warning(e, "Host %s claimed to be %s", 23058789Seric RealHostName, p); 23111146Seric } 23258957Seric p = macvalue('_', e); 23358957Seric if (p == NULL) 23459016Seric p = RealHostName; 23558323Seric 23660210Seric gothello = TRUE; 23760210Seric if (c->cmdcode != CMDEHLO) 238*60239Seric { 239*60239Seric /* print old message and be done with it */ 240*60239Seric message("250 %s Hello %s, pleased to meet you", 241*60239Seric MyHostName, p); 24260210Seric break; 243*60239Seric } 244*60239Seric 245*60239Seric /* print extended message and brag */ 246*60239Seric message("250-%s Hello %s, pleased to meet you", 247*60239Seric MyHostName, p); 24858323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 24958323Seric message("250-EXPN"); 25059271Seric if (MaxMessageSize > 0) 25159271Seric message("250-SIZE %ld", MaxMessageSize); 25259271Seric else 25359271Seric message("250-SIZE"); 25458323Seric message("250 HELP"); 2554976Seric break; 2564976Seric 2574549Seric case CMDMAIL: /* mail -- designate sender */ 25824943Seric SmtpPhase = "MAIL"; 25924943Seric 2609314Seric /* check for validity of this command */ 26158789Seric if (!gothello) 26258082Seric { 26358957Seric /* set sending host to our known value */ 26459016Seric if (sendinghost == NULL) 26559016Seric sendinghost = RealHostName; 26658957Seric 26758789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 26858821Seric { 26958789Seric message("503 Polite people say HELO first"); 27058821Seric break; 27158821Seric } 27258789Seric else 27358821Seric { 27458789Seric auth_warning(e, 27558789Seric "Host %s didn't use HELO protocol", 27658789Seric RealHostName); 27758821Seric } 27858082Seric } 27958109Seric if (gotmail) 2804558Seric { 28158151Seric message("503 Sender already specified"); 2824558Seric break; 2834558Seric } 2849339Seric if (InChild) 2859339Seric { 28636230Skarels errno = 0; 28758151Seric syserr("503 Nested MAIL command: MAIL %s", p); 28858069Seric finis(); 2899339Seric } 2909339Seric 2919339Seric /* fork a subprocess to process this command */ 29255012Seric if (runinchild("SMTP-MAIL", e) > 0) 2939339Seric break; 29458323Seric if (protocol == NULL) 29558323Seric protocol = "SMTP"; 29658323Seric define('r', protocol, e); 29759016Seric define('s', sendinghost, e); 29855012Seric initsys(e); 29959747Seric nrcpts = 0; 30057389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 3019339Seric 3029339Seric /* child -- go do the processing */ 3034549Seric p = skipword(p, "from"); 3044549Seric if (p == NULL) 3054549Seric break; 30657977Seric if (setjmp(TopFrame) > 0) 30758147Seric { 30858147Seric /* this failed -- undo work */ 30958147Seric if (InChild) 31059058Seric { 31159058Seric QuickAbort = FALSE; 31259058Seric SuprErrs = TRUE; 31358147Seric finis(); 31459058Seric } 31557977Seric break; 31658147Seric } 31757977Seric QuickAbort = TRUE; 31858333Seric 31958333Seric /* must parse sender first */ 32058333Seric delimptr = NULL; 32158704Seric setsender(p, e, &delimptr, FALSE); 32258333Seric p = delimptr; 32358333Seric if (p != NULL && *p != '\0') 32458333Seric *p++ = '\0'; 32558333Seric 32658333Seric /* now parse ESMTP arguments */ 32758333Seric msize = 0; 32858333Seric for (; p != NULL && *p != '\0'; p++) 32958333Seric { 33058333Seric char *kp; 33158333Seric char *vp; 33258333Seric 33358333Seric /* locate the beginning of the keyword */ 33458333Seric while (isascii(*p) && isspace(*p)) 33558333Seric p++; 33658333Seric if (*p == '\0') 33758333Seric break; 33858333Seric kp = p; 33958333Seric 34058333Seric /* skip to the value portion */ 34158333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 34258333Seric p++; 34358333Seric if (*p == '=') 34458333Seric { 34558333Seric *p++ = '\0'; 34658333Seric vp = p; 34758333Seric 34858333Seric /* skip to the end of the value */ 34958333Seric while (*p != '\0' && *p != ' ' && 35058333Seric !(isascii(*p) && iscntrl(*p)) && 35158333Seric *p != '=') 35258333Seric p++; 35358333Seric } 35458333Seric 35558333Seric if (*p != '\0') 35658333Seric *p++ = '\0'; 35758333Seric 35858333Seric if (tTd(19, 1)) 35958333Seric printf("MAIL: got arg %s=%s\n", kp, 36058333Seric vp == NULL ? "<null>" : vp); 36158333Seric 36258333Seric if (strcasecmp(kp, "size") == 0) 36358333Seric { 36459093Seric if (vp == NULL) 36558333Seric { 36658333Seric usrerr("501 SIZE requires a value"); 36758333Seric /* NOTREACHED */ 36858333Seric } 36958333Seric msize = atol(vp); 37058333Seric } 37159093Seric else if (strcasecmp(kp, "body") == 0) 37259093Seric { 37359093Seric if (vp == NULL) 37459093Seric { 37559093Seric usrerr("501 BODY requires a value"); 37659093Seric /* NOTREACHED */ 37759093Seric } 37859093Seric # ifdef MIME 37959093Seric if (strcasecmp(vp, "8bitmime") == 0) 38059093Seric { 38159093Seric e->e_bodytype = "8BITMIME"; 38259709Seric SevenBit = FALSE; 38359093Seric } 38459093Seric else if (strcasecmp(vp, "7bit") == 0) 38559093Seric { 38659093Seric e->e_bodytype = "7BIT"; 38759709Seric SevenBit = TRUE; 38859093Seric } 38959093Seric else 39059093Seric { 39159093Seric usrerr("501 Unknown BODY type %s", 39259093Seric vp); 39359093Seric } 39459093Seric # endif 39559093Seric } 39658333Seric else 39758333Seric { 39858333Seric usrerr("501 %s parameter unrecognized", kp); 39958333Seric /* NOTREACHED */ 40058333Seric } 40158333Seric } 40259284Seric 40359284Seric if (MaxMessageSize > 0 && msize > MaxMessageSize) 40459284Seric { 40559284Seric usrerr("552 Message size exceeds fixed maximum message size (%ld)", 40659284Seric MaxMessageSize); 40759284Seric /* NOTREACHED */ 40859284Seric } 40958333Seric 41058333Seric if (!enoughspace(msize)) 41158333Seric { 41258333Seric message("452 Insufficient disk space; try again later"); 41358333Seric break; 41458333Seric } 41558151Seric message("250 Sender ok"); 41658147Seric gotmail = TRUE; 4174549Seric break; 4184549Seric 4194976Seric case CMDRCPT: /* rcpt -- designate recipient */ 42058850Seric if (!gotmail) 42158850Seric { 42258850Seric usrerr("503 Need MAIL before RCPT"); 42358850Seric break; 42458850Seric } 42524943Seric SmtpPhase = "RCPT"; 42612612Seric if (setjmp(TopFrame) > 0) 42714785Seric { 42855012Seric e->e_flags &= ~EF_FATALERRS; 42912612Seric break; 43014785Seric } 43112612Seric QuickAbort = TRUE; 43251951Seric LogUsrErrs = TRUE; 43358093Seric 43459699Seric if (e->e_sendmode != SM_DELIVER) 43559699Seric e->e_flags |= EF_VRFYONLY; 43658919Seric 4374549Seric p = skipword(p, "to"); 4384549Seric if (p == NULL) 4394549Seric break; 44058333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 44112612Seric if (a == NULL) 44212612Seric break; 44316886Seric a->q_flags |= QPRIMARY; 44455012Seric a = recipient(a, &e->e_sendqueue, e); 44512612Seric if (Errors != 0) 44612612Seric break; 44712612Seric 44812612Seric /* no errors during parsing, but might be a duplicate */ 44955012Seric e->e_to = p; 45012612Seric if (!bitset(QBADADDR, a->q_flags)) 45159747Seric { 45258151Seric message("250 Recipient ok"); 45359747Seric nrcpts++; 45459747Seric } 45512612Seric else 4564549Seric { 45712612Seric /* punt -- should keep message in ADDRESS.... */ 45858151Seric message("550 Addressee unknown"); 4594549Seric } 46055012Seric e->e_to = NULL; 4614549Seric break; 4624549Seric 4634549Seric case CMDDATA: /* data -- text of mail */ 46424943Seric SmtpPhase = "DATA"; 46558109Seric if (!gotmail) 4664549Seric { 46758151Seric message("503 Need MAIL command"); 4684976Seric break; 4694549Seric } 47055012Seric else if (e->e_nrcpts <= 0) 4714549Seric { 47258151Seric message("503 Need RCPT (recipient)"); 4734976Seric break; 4744549Seric } 4754976Seric 47658929Seric /* check to see if we need to re-expand aliases */ 47758929Seric for (a = e->e_sendqueue; a != NULL; a = a->q_next) 47858929Seric { 47958929Seric if (bitset(QVERIFIED, a->q_flags)) 48058929Seric break; 48158929Seric } 48258929Seric 4834976Seric /* collect the text of the message */ 48424943Seric SmtpPhase = "collect"; 48558929Seric collect(TRUE, a != NULL, e); 48659730Seric e->e_flags &= ~EF_FATALERRS; 4874976Seric if (Errors != 0) 48859747Seric goto abortmessage; 4894976Seric 4908238Seric /* 4918238Seric ** Arrange to send to everyone. 4928238Seric ** If sending to multiple people, mail back 4938238Seric ** errors rather than reporting directly. 4948238Seric ** In any case, don't mail back errors for 4958238Seric ** anything that has happened up to 4968238Seric ** now (the other end will do this). 49710197Seric ** Truncate our transcript -- the mail has gotten 49810197Seric ** to us successfully, and if we have 49910197Seric ** to mail this back, it will be easier 50010197Seric ** on the reader. 5018238Seric ** Then send to everyone. 5028238Seric ** Finally give a reply code. If an error has 5038238Seric ** already been given, don't mail a 5048238Seric ** message back. 5059339Seric ** We goose error returns by clearing error bit. 5068238Seric */ 5078238Seric 50824943Seric SmtpPhase = "delivery"; 50959747Seric if (nrcpts != 1 && a == NULL) 5109378Seric { 5119378Seric HoldErrs = TRUE; 51258734Seric e->e_errormode = EM_MAIL; 5139378Seric } 51455012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 51558714Seric id = e->e_id; 5164976Seric 5174976Seric /* send to all recipients */ 51858919Seric sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 51955012Seric e->e_to = NULL; 5204976Seric 52123516Seric /* save statistics */ 52255012Seric markstats(e, (ADDRESS *) NULL); 52323516Seric 5248238Seric /* issue success if appropriate and reset */ 5258238Seric if (Errors == 0 || HoldErrs) 52658855Seric message("250 %s Message accepted for delivery", id); 52759747Seric 52859747Seric if (bitset(EF_FATALERRS, e->e_flags) && !HoldErrs) 52959730Seric { 53059730Seric /* avoid sending back an extra message */ 53159730Seric e->e_flags &= ~EF_FATALERRS; 53259747Seric e->e_flags |= EF_CLRQUEUE; 53359730Seric } 5348238Seric else 53558919Seric { 53659747Seric /* from now on, we have to operate silently */ 53759747Seric HoldErrs = TRUE; 53859747Seric e->e_errormode = EM_MAIL; 53959747Seric 54059730Seric /* if we just queued, poke it */ 54159730Seric if (a != NULL && e->e_sendmode != SM_QUEUE) 54259730Seric { 54359730Seric unlockqueue(e); 54459730Seric dowork(id, TRUE, TRUE, e); 54559730Seric e->e_id = NULL; 54659730Seric } 54758919Seric } 54858883Seric 54959747Seric abortmessage: 5509339Seric /* if in a child, pop back to our parent */ 5519339Seric if (InChild) 5529339Seric finis(); 55324943Seric 55424943Seric /* clean up a bit */ 55558109Seric gotmail = FALSE; 55655012Seric dropenvelope(e); 55758179Seric CurEnv = e = newenvelope(e, CurEnv); 55855012Seric e->e_flags = BlankEnvelope.e_flags; 5594549Seric break; 5604549Seric 5614549Seric case CMDRSET: /* rset -- reset state */ 56258151Seric message("250 Reset state"); 5639339Seric if (InChild) 5649339Seric finis(); 56558109Seric 56658109Seric /* clean up a bit */ 56758109Seric gotmail = FALSE; 56858109Seric dropenvelope(e); 56958179Seric CurEnv = e = newenvelope(e, CurEnv); 5709339Seric break; 5714549Seric 5724549Seric case CMDVRFY: /* vrfy -- verify address */ 57358092Seric case CMDEXPN: /* expn -- expand address */ 57458092Seric vrfy = c->cmdcode == CMDVRFY; 57558092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 57658092Seric PrivacyFlags)) 57758082Seric { 57858412Seric if (vrfy) 57958412Seric message("252 Who's to say?"); 58058412Seric else 58158412Seric message("502 That's none of your business"); 58258082Seric break; 58358082Seric } 58458082Seric else if (!gothello && 58558092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 58658092Seric PrivacyFlags)) 58758082Seric { 58858151Seric message("503 I demand that you introduce yourself first"); 58958082Seric break; 59058082Seric } 59158092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5929339Seric break; 59355173Seric #ifdef LOG 59458020Seric if (LogLevel > 5) 59555173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 59655173Seric #endif 5975003Seric vrfyqueue = NULL; 5987762Seric QuickAbort = TRUE; 59958092Seric if (vrfy) 60058092Seric e->e_flags |= EF_VRFYONLY; 60158082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 6027762Seric if (Errors != 0) 6039339Seric { 6049339Seric if (InChild) 6059339Seric finis(); 6067762Seric break; 6079339Seric } 6085003Seric while (vrfyqueue != NULL) 6095003Seric { 6105003Seric register ADDRESS *a = vrfyqueue->q_next; 6115003Seric char *code; 6125003Seric 6137685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 6145003Seric a = a->q_next; 6155003Seric 6167685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 61758151Seric printvrfyaddr(vrfyqueue, a == NULL); 6185003Seric else if (a == NULL) 61958151Seric message("554 Self destructive alias loop"); 6205003Seric vrfyqueue = a; 6215003Seric } 6229339Seric if (InChild) 6239339Seric finis(); 6244549Seric break; 6254549Seric 6264549Seric case CMDHELP: /* help -- give user info */ 6274577Seric help(p); 6284549Seric break; 6294549Seric 6304549Seric case CMDNOOP: /* noop -- do nothing */ 63158151Seric message("200 OK"); 6324549Seric break; 6334549Seric 6344549Seric case CMDQUIT: /* quit -- leave mail */ 63558151Seric message("221 %s closing connection", MyHostName); 6369339Seric if (InChild) 6379339Seric ExitStat = EX_QUIT; 6384549Seric finis(); 6394549Seric 6408544Seric case CMDVERB: /* set verbose mode */ 64159957Seric if (bitset(PRIV_NOEXPN, PrivacyFlags)) 64259957Seric { 64359957Seric /* this would give out the same info */ 64459957Seric message("502 Verbose unavailable"); 64559957Seric break; 64659957Seric } 6478544Seric Verbose = TRUE; 64858734Seric e->e_sendmode = SM_DELIVER; 64959957Seric message("250 Verbose mode"); 6508544Seric break; 6518544Seric 6529314Seric case CMDONEX: /* doing one transaction only */ 6539378Seric OneXact = TRUE; 65459957Seric message("250 Only one transaction"); 6559314Seric break; 6569314Seric 65736230Skarels # ifdef SMTPDEBUG 6589339Seric case CMDDBGQSHOW: /* show queues */ 6596907Seric printf("Send Queue="); 66055012Seric printaddr(e->e_sendqueue, TRUE); 6615003Seric break; 6627275Seric 6637275Seric case CMDDBGDEBUG: /* set debug mode */ 6647676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 6657676Seric tTflag(p); 66658151Seric message("200 Debug set"); 6677275Seric break; 6687275Seric 66936230Skarels # else /* not SMTPDEBUG */ 67024945Seric 67136230Skarels case CMDDBGQSHOW: /* show queues */ 67236230Skarels case CMDDBGDEBUG: /* set debug mode */ 67336233Skarels # ifdef LOG 67458308Seric if (LogLevel > 0) 67536230Skarels syslog(LOG_NOTICE, 67658020Seric "\"%s\" command from %s (%s)", 67736230Skarels c->cmdname, RealHostName, 67858755Seric anynet_ntoa(&RealHostAddr)); 67936233Skarels # endif 68036230Skarels /* FALL THROUGH */ 68136230Skarels # endif /* SMTPDEBUG */ 68236230Skarels 6834549Seric case CMDERROR: /* unknown command */ 68458151Seric message("500 Command unrecognized"); 6854549Seric break; 6864549Seric 6874549Seric default: 68836230Skarels errno = 0; 68958151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6904549Seric break; 6914549Seric } 6924549Seric } 6934549Seric } 6944549Seric /* 6954549Seric ** SKIPWORD -- skip a fixed word. 6964549Seric ** 6974549Seric ** Parameters: 6984549Seric ** p -- place to start looking. 6994549Seric ** w -- word to skip. 7004549Seric ** 7014549Seric ** Returns: 7024549Seric ** p following w. 7034549Seric ** NULL on error. 7044549Seric ** 7054549Seric ** Side Effects: 7064549Seric ** clobbers the p data area. 7074549Seric */ 7084549Seric 7094549Seric static char * 7104549Seric skipword(p, w) 7114549Seric register char *p; 7124549Seric char *w; 7134549Seric { 7144549Seric register char *q; 7154549Seric 7164549Seric /* find beginning of word */ 71758050Seric while (isascii(*p) && isspace(*p)) 7184549Seric p++; 7194549Seric q = p; 7204549Seric 7214549Seric /* find end of word */ 72258050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 7234549Seric p++; 72458050Seric while (isascii(*p) && isspace(*p)) 7254549Seric *p++ = '\0'; 7264549Seric if (*p != ':') 7274549Seric { 7284549Seric syntax: 72958151Seric message("501 Syntax error"); 7304549Seric Errors++; 7314549Seric return (NULL); 7324549Seric } 7334549Seric *p++ = '\0'; 73458050Seric while (isascii(*p) && isspace(*p)) 7354549Seric p++; 7364549Seric 7374549Seric /* see if the input word matches desired word */ 73833725Sbostic if (strcasecmp(q, w)) 7394549Seric goto syntax; 7404549Seric 7414549Seric return (p); 7424549Seric } 7434577Seric /* 74458151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 74558151Seric ** 74658151Seric ** Parameters: 74758151Seric ** a -- the address to print 74858151Seric ** last -- set if this is the last one. 74958151Seric ** 75058151Seric ** Returns: 75158151Seric ** none. 75258151Seric ** 75358151Seric ** Side Effects: 75458151Seric ** Prints the appropriate 250 codes. 75558151Seric */ 75658151Seric 75758151Seric printvrfyaddr(a, last) 75858151Seric register ADDRESS *a; 75958151Seric bool last; 76058151Seric { 76158151Seric char fmtbuf[20]; 76258151Seric 76358151Seric strcpy(fmtbuf, "250"); 76458151Seric fmtbuf[3] = last ? ' ' : '-'; 76558151Seric 76659746Seric if (a->q_fullname == NULL) 76759746Seric { 76859746Seric if (strchr(a->q_user, '@') == NULL) 76959746Seric strcpy(&fmtbuf[4], "<%s@%s>"); 77059746Seric else 77159746Seric strcpy(&fmtbuf[4], "<%s>"); 77259746Seric message(fmtbuf, a->q_user, MyHostName); 77359746Seric } 77458151Seric else 77558151Seric { 77659746Seric if (strchr(a->q_user, '@') == NULL) 77759746Seric strcpy(&fmtbuf[4], "%s <%s@%s>"); 77859746Seric else 77959746Seric strcpy(&fmtbuf[4], "%s <%s>"); 78059746Seric message(fmtbuf, a->q_fullname, a->q_user, MyHostName); 78158151Seric } 78258151Seric } 78358151Seric /* 7844577Seric ** HELP -- implement the HELP command. 7854577Seric ** 7864577Seric ** Parameters: 7874577Seric ** topic -- the topic we want help for. 7884577Seric ** 7894577Seric ** Returns: 7904577Seric ** none. 7914577Seric ** 7924577Seric ** Side Effects: 7934577Seric ** outputs the help file to message output. 7944577Seric */ 7954577Seric 7964577Seric help(topic) 7974577Seric char *topic; 7984577Seric { 7994577Seric register FILE *hf; 8004577Seric int len; 8014577Seric char buf[MAXLINE]; 8024577Seric bool noinfo; 8034577Seric 8048269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 8054577Seric { 8064577Seric /* no help */ 80711931Seric errno = 0; 80858151Seric message("502 HELP not implemented"); 8094577Seric return; 8104577Seric } 8114577Seric 81249669Seric if (topic == NULL || *topic == '\0') 81349669Seric topic = "smtp"; 81449669Seric else 81549669Seric makelower(topic); 81649669Seric 8174577Seric len = strlen(topic); 8184577Seric noinfo = TRUE; 8194577Seric 8204577Seric while (fgets(buf, sizeof buf, hf) != NULL) 8214577Seric { 8224577Seric if (strncmp(buf, topic, len) == 0) 8234577Seric { 8244577Seric register char *p; 8254577Seric 82656795Seric p = strchr(buf, '\t'); 8274577Seric if (p == NULL) 8284577Seric p = buf; 8294577Seric else 8304577Seric p++; 8314577Seric fixcrlf(p, TRUE); 83258151Seric message("214-%s", p); 8334577Seric noinfo = FALSE; 8344577Seric } 8354577Seric } 8364577Seric 8374577Seric if (noinfo) 83858151Seric message("504 HELP topic unknown"); 8394577Seric else 84058151Seric message("214 End of HELP info"); 8414628Seric (void) fclose(hf); 8424577Seric } 8438544Seric /* 8449339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 8459339Seric ** 8469339Seric ** Parameters: 8479339Seric ** label -- a string used in error messages 8489339Seric ** 8499339Seric ** Returns: 8509339Seric ** zero in the child 8519339Seric ** one in the parent 8529339Seric ** 8539339Seric ** Side Effects: 8549339Seric ** none. 8559339Seric */ 8568544Seric 85755012Seric runinchild(label, e) 8589339Seric char *label; 85955012Seric register ENVELOPE *e; 8609339Seric { 8619339Seric int childpid; 8629339Seric 86316158Seric if (!OneXact) 8649339Seric { 86516158Seric childpid = dofork(); 86616158Seric if (childpid < 0) 86716158Seric { 86816158Seric syserr("%s: cannot fork", label); 86916158Seric return (1); 87016158Seric } 87116158Seric if (childpid > 0) 87216158Seric { 87316158Seric auto int st; 8749339Seric 87516158Seric /* parent -- wait for child to complete */ 87659060Seric setproctitle("srvrsmtp %s child wait", CurHostName); 87716158Seric st = waitfor(childpid); 87816158Seric if (st == -1) 87916158Seric syserr("%s: lost child", label); 8809339Seric 88116158Seric /* if we exited on a QUIT command, complete the process */ 88216158Seric if (st == (EX_QUIT << 8)) 88316158Seric finis(); 8849339Seric 88516158Seric return (1); 88616158Seric } 88716158Seric else 88816158Seric { 88916158Seric /* child */ 89016158Seric InChild = TRUE; 89125050Seric QuickAbort = FALSE; 89255012Seric clearenvelope(e, FALSE); 89316158Seric } 8949339Seric } 89515256Seric 89616158Seric /* open alias database */ 89759672Seric initaliases(FALSE, e); 89816158Seric 89916158Seric return (0); 9009339Seric } 9019339Seric 90256795Seric # endif /* SMTP */ 903