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*58924Seric static char sccsid[] = "@(#)srvrsmtp.c 6.37 (Berkeley) 04/01/93 (with SMTP)"; 1433731Sbostic #else 15*58924Seric static char sccsid[] = "@(#)srvrsmtp.c 6.37 (Berkeley) 04/01/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; 10230448Seric char *sendinghost; 10358109Seric bool gotmail; /* mail command received */ 10458092Seric bool gothello; /* helo command received */ 10558092Seric bool vrfy; /* set if this is a vrfy command */ 10658323Seric char *protocol; /* sending protocol */ 10758333Seric long msize; /* approximate maximum message size */ 10858333Seric auto char *delimptr; 10958714Seric char *id; 1108544Seric char inp[MAXLINE]; 11157232Seric char cmdbuf[MAXLINE]; 11258512Seric char hostbuf[MAXNAME]; 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 1207363Seric if (OutChannel != stdout) 1217363Seric { 1227363Seric /* arrange for debugging output to go to remote host */ 1237363Seric (void) close(1); 1247363Seric (void) dup(fileno(OutChannel)); 1257363Seric } 12655012Seric settime(e); 12757642Seric CurHostName = RealHostName; 12857642Seric setproctitle("srvrsmtp %s", CurHostName); 12958050Seric expand("\201e", inp, &inp[sizeof inp], e); 13058151Seric message("220 %s", inp); 13124943Seric SmtpPhase = "startup"; 13230448Seric sendinghost = NULL; 13358330Seric protocol = NULL; 13458082Seric gothello = FALSE; 13558330Seric gotmail = FALSE; 1364549Seric for (;;) 1374549Seric { 13812612Seric /* arrange for backout */ 13912612Seric if (setjmp(TopFrame) > 0 && InChild) 14012612Seric finis(); 14112612Seric QuickAbort = FALSE; 14212612Seric HoldErrs = FALSE; 14351951Seric LogUsrErrs = FALSE; 14458092Seric e->e_flags &= ~EF_VRFYONLY; 14512612Seric 1467356Seric /* setup for the read */ 14755012Seric e->e_to = NULL; 1484577Seric Errors = 0; 1497275Seric (void) fflush(stdout); 1507356Seric 1517356Seric /* read the input line */ 15258109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1537356Seric 1547685Seric /* handle errors */ 1557356Seric if (p == NULL) 1567356Seric { 1574549Seric /* end of file, just die */ 15858151Seric message("421 %s Lost input channel from %s", 15925050Seric MyHostName, CurHostName); 16055464Seric #ifdef LOG 16158020Seric if (LogLevel > 1) 16255464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16355464Seric CurHostName); 16455464Seric #endif 16558069Seric if (InChild) 16658069Seric ExitStat = EX_QUIT; 1674549Seric finis(); 1684549Seric } 1694549Seric 1704549Seric /* clean up end of line */ 1714558Seric fixcrlf(inp, TRUE); 1724549Seric 1734713Seric /* echo command to transcript */ 17455012Seric if (e->e_xfp != NULL) 17555012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1764713Seric 1774549Seric /* break off command */ 17858050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1794549Seric continue; 18057232Seric cmd = cmdbuf; 18158050Seric while (*p != '\0' && 18258050Seric !(isascii(*p) && isspace(*p)) && 18358050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 18424981Seric *cmd++ = *p++; 18524981Seric *cmd = '\0'; 1864549Seric 18725691Seric /* throw away leading whitespace */ 18858050Seric while (isascii(*p) && isspace(*p)) 18925691Seric p++; 19025691Seric 1914549Seric /* decode command */ 1924549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1934549Seric { 19433725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1954549Seric break; 1964549Seric } 1974549Seric 19851954Seric /* reset errors */ 19951954Seric errno = 0; 20051954Seric 2014549Seric /* process command */ 2024549Seric switch (c->cmdcode) 2034549Seric { 2044976Seric case CMDHELO: /* hello -- introduce yourself */ 20558323Seric case CMDEHLO: /* extended hello */ 20658323Seric if (c->cmdcode == CMDEHLO) 20758323Seric { 20858323Seric protocol = "ESMTP"; 20958323Seric SmtpPhase = "EHLO"; 21058323Seric } 21158323Seric else 21258323Seric { 21358323Seric protocol = "SMTP"; 21458323Seric SmtpPhase = "HELO"; 21558323Seric } 21625050Seric setproctitle("%s: %s", CurHostName, inp); 21758109Seric if (strcasecmp(p, MyHostName) == 0) 21814877Seric { 21936230Skarels /* 22058109Seric ** Didn't know about alias or MX, 22158109Seric ** or connected to an echo server 22258109Seric */ 22358109Seric 22458151Seric message("553 %s config error: mail loops back to myself", 22547570Seric MyHostName); 22614877Seric break; 22714877Seric } 22858512Seric (void) strcpy(hostbuf, p); 22958512Seric (void) strcat(hostbuf, " ("); 23058755Seric (void) strcat(hostbuf, anynet_ntoa(&RealHostAddr)); 23158308Seric if (strcasecmp(p, RealHostName) != 0) 23211146Seric { 23358789Seric auth_warning(e, "Host %s claimed to be %s", 23458789Seric RealHostName, p); 23558512Seric (void) strcat(hostbuf, "; "); 23658512Seric (void) strcat(hostbuf, RealHostName); 23711146Seric } 23858512Seric (void) strcat(hostbuf, ")"); 23958512Seric sendinghost = newstr(hostbuf); 24058323Seric 24158323Seric /* send ext. message -- old systems must ignore */ 24258323Seric message("250-%s Hello %s, pleased to meet you", 24336230Skarels MyHostName, sendinghost); 24458323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 24558323Seric message("250-EXPN"); 24658338Seric message("250-SIZE"); 24758323Seric message("250 HELP"); 24858082Seric gothello = TRUE; 2494976Seric break; 2504976Seric 2514549Seric case CMDMAIL: /* mail -- designate sender */ 25224943Seric SmtpPhase = "MAIL"; 25324943Seric 25411151Seric /* force a sending host even if no HELO given */ 25558064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 25630448Seric sendinghost = RealHostName; 25711151Seric 2589314Seric /* check for validity of this command */ 25958789Seric if (!gothello) 26058082Seric { 26158789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 26258821Seric { 26358789Seric message("503 Polite people say HELO first"); 26458821Seric break; 26558821Seric } 26658789Seric else 26758821Seric { 26858789Seric auth_warning(e, 26958789Seric "Host %s didn't use HELO protocol", 27058789Seric RealHostName); 27158821Seric } 27258082Seric } 27358109Seric if (gotmail) 2744558Seric { 27558151Seric message("503 Sender already specified"); 2764558Seric break; 2774558Seric } 2789339Seric if (InChild) 2799339Seric { 28036230Skarels errno = 0; 28158151Seric syserr("503 Nested MAIL command: MAIL %s", p); 28258069Seric finis(); 2839339Seric } 2849339Seric 2859339Seric /* fork a subprocess to process this command */ 28655012Seric if (runinchild("SMTP-MAIL", e) > 0) 2879339Seric break; 28858064Seric if (sendinghost != NULL) 28958064Seric define('s', sendinghost, e); 29058323Seric if (protocol == NULL) 29158323Seric protocol = "SMTP"; 29258323Seric define('r', protocol, e); 29355012Seric initsys(e); 29457389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2959339Seric 2969339Seric /* child -- go do the processing */ 2974549Seric p = skipword(p, "from"); 2984549Seric if (p == NULL) 2994549Seric break; 30057977Seric if (setjmp(TopFrame) > 0) 30158147Seric { 30258147Seric /* this failed -- undo work */ 30358147Seric if (InChild) 30458147Seric finis(); 30557977Seric break; 30658147Seric } 30757977Seric QuickAbort = TRUE; 30858333Seric 30958333Seric /* must parse sender first */ 31058333Seric delimptr = NULL; 31158704Seric setsender(p, e, &delimptr, FALSE); 31258333Seric p = delimptr; 31358333Seric if (p != NULL && *p != '\0') 31458333Seric *p++ = '\0'; 31558333Seric 31658333Seric /* now parse ESMTP arguments */ 31758333Seric msize = 0; 31858333Seric for (; p != NULL && *p != '\0'; p++) 31958333Seric { 32058333Seric char *kp; 32158333Seric char *vp; 32258333Seric 32358333Seric /* locate the beginning of the keyword */ 32458333Seric while (isascii(*p) && isspace(*p)) 32558333Seric p++; 32658333Seric if (*p == '\0') 32758333Seric break; 32858333Seric kp = p; 32958333Seric 33058333Seric /* skip to the value portion */ 33158333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 33258333Seric p++; 33358333Seric if (*p == '=') 33458333Seric { 33558333Seric *p++ = '\0'; 33658333Seric vp = p; 33758333Seric 33858333Seric /* skip to the end of the value */ 33958333Seric while (*p != '\0' && *p != ' ' && 34058333Seric !(isascii(*p) && iscntrl(*p)) && 34158333Seric *p != '=') 34258333Seric p++; 34358333Seric } 34458333Seric 34558333Seric if (*p != '\0') 34658333Seric *p++ = '\0'; 34758333Seric 34858333Seric if (tTd(19, 1)) 34958333Seric printf("MAIL: got arg %s=%s\n", kp, 35058333Seric vp == NULL ? "<null>" : vp); 35158333Seric 35258333Seric if (strcasecmp(kp, "size") == 0) 35358333Seric { 35458333Seric if (kp == NULL) 35558333Seric { 35658333Seric usrerr("501 SIZE requires a value"); 35758333Seric /* NOTREACHED */ 35858333Seric } 35958333Seric msize = atol(vp); 36058333Seric } 36158333Seric else 36258333Seric { 36358333Seric usrerr("501 %s parameter unrecognized", kp); 36458333Seric /* NOTREACHED */ 36558333Seric } 36658333Seric } 36758333Seric 36858333Seric if (!enoughspace(msize)) 36958333Seric { 37058333Seric message("452 Insufficient disk space; try again later"); 37158333Seric break; 37258333Seric } 37358151Seric message("250 Sender ok"); 37458147Seric gotmail = TRUE; 3754549Seric break; 3764549Seric 3774976Seric case CMDRCPT: /* rcpt -- designate recipient */ 37858850Seric if (!gotmail) 37958850Seric { 38058850Seric usrerr("503 Need MAIL before RCPT"); 38158850Seric break; 38258850Seric } 38324943Seric SmtpPhase = "RCPT"; 38457389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 38512612Seric if (setjmp(TopFrame) > 0) 38614785Seric { 38755012Seric e->e_flags &= ~EF_FATALERRS; 38812612Seric break; 38914785Seric } 39012612Seric QuickAbort = TRUE; 39151951Seric LogUsrErrs = TRUE; 39258093Seric 39358919Seric e->e_flags |= EF_VRFYONLY; 39458919Seric 3954549Seric p = skipword(p, "to"); 3964549Seric if (p == NULL) 3974549Seric break; 39858333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 39912612Seric if (a == NULL) 40012612Seric break; 40116886Seric a->q_flags |= QPRIMARY; 40255012Seric a = recipient(a, &e->e_sendqueue, e); 40312612Seric if (Errors != 0) 40412612Seric break; 40512612Seric 40612612Seric /* no errors during parsing, but might be a duplicate */ 40755012Seric e->e_to = p; 40812612Seric if (!bitset(QBADADDR, a->q_flags)) 40958151Seric message("250 Recipient ok"); 41012612Seric else 4114549Seric { 41212612Seric /* punt -- should keep message in ADDRESS.... */ 41358151Seric message("550 Addressee unknown"); 4144549Seric } 41555012Seric e->e_to = NULL; 4164549Seric break; 4174549Seric 4184549Seric case CMDDATA: /* data -- text of mail */ 41924943Seric SmtpPhase = "DATA"; 42058109Seric if (!gotmail) 4214549Seric { 42258151Seric message("503 Need MAIL command"); 4234976Seric break; 4244549Seric } 42555012Seric else if (e->e_nrcpts <= 0) 4264549Seric { 42758151Seric message("503 Need RCPT (recipient)"); 4284976Seric break; 4294549Seric } 4304976Seric 4314976Seric /* collect the text of the message */ 43224943Seric SmtpPhase = "collect"; 43357389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 43455012Seric collect(TRUE, e); 4354976Seric if (Errors != 0) 4364976Seric break; 4374976Seric 4388238Seric /* 4398238Seric ** Arrange to send to everyone. 4408238Seric ** If sending to multiple people, mail back 4418238Seric ** errors rather than reporting directly. 4428238Seric ** In any case, don't mail back errors for 4438238Seric ** anything that has happened up to 4448238Seric ** now (the other end will do this). 44510197Seric ** Truncate our transcript -- the mail has gotten 44610197Seric ** to us successfully, and if we have 44710197Seric ** to mail this back, it will be easier 44810197Seric ** on the reader. 4498238Seric ** Then send to everyone. 4508238Seric ** Finally give a reply code. If an error has 4518238Seric ** already been given, don't mail a 4528238Seric ** message back. 4539339Seric ** We goose error returns by clearing error bit. 4548238Seric */ 4558238Seric 45624943Seric SmtpPhase = "delivery"; 45755012Seric if (e->e_nrcpts != 1) 4589378Seric { 4599378Seric HoldErrs = TRUE; 46058734Seric e->e_errormode = EM_MAIL; 4619378Seric } 46255012Seric e->e_flags &= ~EF_FATALERRS; 46355012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 46458714Seric id = e->e_id; 4654976Seric 46658919Seric /* check to see if we need to re-expand aliases */ 46758919Seric for (a = e->e_sendqueue; a != NULL; a = a->q_next) 46858919Seric { 46958919Seric if (bitset(QVERIFIED, a->q_flags)) 47058919Seric break; 47158919Seric } 47258919Seric 4734976Seric /* send to all recipients */ 47458919Seric sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 47555012Seric e->e_to = NULL; 4764976Seric 47723516Seric /* save statistics */ 47855012Seric markstats(e, (ADDRESS *) NULL); 47923516Seric 4808238Seric /* issue success if appropriate and reset */ 4818238Seric if (Errors == 0 || HoldErrs) 48258855Seric message("250 %s Message accepted for delivery", id); 4838238Seric else 48455012Seric e->e_flags &= ~EF_FATALERRS; 4859339Seric 48658919Seric /* if we just queued, poke it */ 48758919Seric if (a != NULL && e->e_sendmode != SM_QUEUE) 48858919Seric { 48958919Seric unlockqueue(e); 490*58924Seric dowork(id, TRUE, TRUE, e); 49158919Seric e->e_id = NULL; 49258919Seric } 49358883Seric 4949339Seric /* if in a child, pop back to our parent */ 4959339Seric if (InChild) 4969339Seric finis(); 49724943Seric 49824943Seric /* clean up a bit */ 49958109Seric gotmail = FALSE; 50055012Seric dropenvelope(e); 50158179Seric CurEnv = e = newenvelope(e, CurEnv); 50255012Seric e->e_flags = BlankEnvelope.e_flags; 5034549Seric break; 5044549Seric 5054549Seric case CMDRSET: /* rset -- reset state */ 50658151Seric message("250 Reset state"); 5079339Seric if (InChild) 5089339Seric finis(); 50958109Seric 51058109Seric /* clean up a bit */ 51158109Seric gotmail = FALSE; 51258109Seric dropenvelope(e); 51358179Seric CurEnv = e = newenvelope(e, CurEnv); 5149339Seric break; 5154549Seric 5164549Seric case CMDVRFY: /* vrfy -- verify address */ 51758092Seric case CMDEXPN: /* expn -- expand address */ 51858092Seric vrfy = c->cmdcode == CMDVRFY; 51958092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 52058092Seric PrivacyFlags)) 52158082Seric { 52258412Seric if (vrfy) 52358412Seric message("252 Who's to say?"); 52458412Seric else 52558412Seric message("502 That's none of your business"); 52658082Seric break; 52758082Seric } 52858082Seric else if (!gothello && 52958092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 53058092Seric PrivacyFlags)) 53158082Seric { 53258151Seric message("503 I demand that you introduce yourself first"); 53358082Seric break; 53458082Seric } 53558092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5369339Seric break; 53725050Seric setproctitle("%s: %s", CurHostName, inp); 53855173Seric #ifdef LOG 53958020Seric if (LogLevel > 5) 54055173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 54155173Seric #endif 5425003Seric vrfyqueue = NULL; 5437762Seric QuickAbort = TRUE; 54458092Seric if (vrfy) 54558092Seric e->e_flags |= EF_VRFYONLY; 54658082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5477762Seric if (Errors != 0) 5489339Seric { 5499339Seric if (InChild) 5509339Seric finis(); 5517762Seric break; 5529339Seric } 5535003Seric while (vrfyqueue != NULL) 5545003Seric { 5555003Seric register ADDRESS *a = vrfyqueue->q_next; 5565003Seric char *code; 5575003Seric 5587685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5595003Seric a = a->q_next; 5605003Seric 5617685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 56258151Seric printvrfyaddr(vrfyqueue, a == NULL); 5635003Seric else if (a == NULL) 56458151Seric message("554 Self destructive alias loop"); 5655003Seric vrfyqueue = a; 5665003Seric } 5679339Seric if (InChild) 5689339Seric finis(); 5694549Seric break; 5704549Seric 5714549Seric case CMDHELP: /* help -- give user info */ 5724577Seric help(p); 5734549Seric break; 5744549Seric 5754549Seric case CMDNOOP: /* noop -- do nothing */ 57658151Seric message("200 OK"); 5774549Seric break; 5784549Seric 5794549Seric case CMDQUIT: /* quit -- leave mail */ 58058151Seric message("221 %s closing connection", MyHostName); 5819339Seric if (InChild) 5829339Seric ExitStat = EX_QUIT; 5834549Seric finis(); 5844549Seric 5858544Seric case CMDVERB: /* set verbose mode */ 5868544Seric Verbose = TRUE; 58758734Seric e->e_sendmode = SM_DELIVER; 58858151Seric message("200 Verbose mode"); 5898544Seric break; 5908544Seric 5919314Seric case CMDONEX: /* doing one transaction only */ 5929378Seric OneXact = TRUE; 59358151Seric message("200 Only one transaction"); 5949314Seric break; 5959314Seric 59636230Skarels # ifdef SMTPDEBUG 5979339Seric case CMDDBGQSHOW: /* show queues */ 5986907Seric printf("Send Queue="); 59955012Seric printaddr(e->e_sendqueue, TRUE); 6005003Seric break; 6017275Seric 6027275Seric case CMDDBGDEBUG: /* set debug mode */ 6037676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 6047676Seric tTflag(p); 60558151Seric message("200 Debug set"); 6067275Seric break; 6077275Seric 60836230Skarels # else /* not SMTPDEBUG */ 60924945Seric 61036230Skarels case CMDDBGQSHOW: /* show queues */ 61136230Skarels case CMDDBGDEBUG: /* set debug mode */ 61236233Skarels # ifdef LOG 61358308Seric if (LogLevel > 0) 61436230Skarels syslog(LOG_NOTICE, 61558020Seric "\"%s\" command from %s (%s)", 61636230Skarels c->cmdname, RealHostName, 61758755Seric anynet_ntoa(&RealHostAddr)); 61836233Skarels # endif 61936230Skarels /* FALL THROUGH */ 62036230Skarels # endif /* SMTPDEBUG */ 62136230Skarels 6224549Seric case CMDERROR: /* unknown command */ 62358151Seric message("500 Command unrecognized"); 6244549Seric break; 6254549Seric 6264549Seric default: 62736230Skarels errno = 0; 62858151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6294549Seric break; 6304549Seric } 6314549Seric } 6324549Seric } 6334549Seric /* 6344549Seric ** SKIPWORD -- skip a fixed word. 6354549Seric ** 6364549Seric ** Parameters: 6374549Seric ** p -- place to start looking. 6384549Seric ** w -- word to skip. 6394549Seric ** 6404549Seric ** Returns: 6414549Seric ** p following w. 6424549Seric ** NULL on error. 6434549Seric ** 6444549Seric ** Side Effects: 6454549Seric ** clobbers the p data area. 6464549Seric */ 6474549Seric 6484549Seric static char * 6494549Seric skipword(p, w) 6504549Seric register char *p; 6514549Seric char *w; 6524549Seric { 6534549Seric register char *q; 6544549Seric 6554549Seric /* find beginning of word */ 65658050Seric while (isascii(*p) && isspace(*p)) 6574549Seric p++; 6584549Seric q = p; 6594549Seric 6604549Seric /* find end of word */ 66158050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6624549Seric p++; 66358050Seric while (isascii(*p) && isspace(*p)) 6644549Seric *p++ = '\0'; 6654549Seric if (*p != ':') 6664549Seric { 6674549Seric syntax: 66858151Seric message("501 Syntax error"); 6694549Seric Errors++; 6704549Seric return (NULL); 6714549Seric } 6724549Seric *p++ = '\0'; 67358050Seric while (isascii(*p) && isspace(*p)) 6744549Seric p++; 6754549Seric 6764549Seric /* see if the input word matches desired word */ 67733725Sbostic if (strcasecmp(q, w)) 6784549Seric goto syntax; 6794549Seric 6804549Seric return (p); 6814549Seric } 6824577Seric /* 68358151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 68458151Seric ** 68558151Seric ** Parameters: 68658151Seric ** a -- the address to print 68758151Seric ** last -- set if this is the last one. 68858151Seric ** 68958151Seric ** Returns: 69058151Seric ** none. 69158151Seric ** 69258151Seric ** Side Effects: 69358151Seric ** Prints the appropriate 250 codes. 69458151Seric */ 69558151Seric 69658151Seric printvrfyaddr(a, last) 69758151Seric register ADDRESS *a; 69858151Seric bool last; 69958151Seric { 70058151Seric char fmtbuf[20]; 70158151Seric 70258151Seric strcpy(fmtbuf, "250"); 70358151Seric fmtbuf[3] = last ? ' ' : '-'; 70458151Seric 70558151Seric if (strchr(a->q_paddr, '<') != NULL) 70658151Seric strcpy(&fmtbuf[4], "%s"); 70758151Seric else if (a->q_fullname == NULL) 70858151Seric strcpy(&fmtbuf[4], "<%s>"); 70958151Seric else 71058151Seric { 71158151Seric strcpy(&fmtbuf[4], "%s <%s>"); 71258151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 71358151Seric return; 71458151Seric } 71558151Seric message(fmtbuf, a->q_paddr); 71658151Seric } 71758151Seric /* 7184577Seric ** HELP -- implement the HELP command. 7194577Seric ** 7204577Seric ** Parameters: 7214577Seric ** topic -- the topic we want help for. 7224577Seric ** 7234577Seric ** Returns: 7244577Seric ** none. 7254577Seric ** 7264577Seric ** Side Effects: 7274577Seric ** outputs the help file to message output. 7284577Seric */ 7294577Seric 7304577Seric help(topic) 7314577Seric char *topic; 7324577Seric { 7334577Seric register FILE *hf; 7344577Seric int len; 7354577Seric char buf[MAXLINE]; 7364577Seric bool noinfo; 7374577Seric 7388269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7394577Seric { 7404577Seric /* no help */ 74111931Seric errno = 0; 74258151Seric message("502 HELP not implemented"); 7434577Seric return; 7444577Seric } 7454577Seric 74649669Seric if (topic == NULL || *topic == '\0') 74749669Seric topic = "smtp"; 74849669Seric else 74949669Seric makelower(topic); 75049669Seric 7514577Seric len = strlen(topic); 7524577Seric noinfo = TRUE; 7534577Seric 7544577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7554577Seric { 7564577Seric if (strncmp(buf, topic, len) == 0) 7574577Seric { 7584577Seric register char *p; 7594577Seric 76056795Seric p = strchr(buf, '\t'); 7614577Seric if (p == NULL) 7624577Seric p = buf; 7634577Seric else 7644577Seric p++; 7654577Seric fixcrlf(p, TRUE); 76658151Seric message("214-%s", p); 7674577Seric noinfo = FALSE; 7684577Seric } 7694577Seric } 7704577Seric 7714577Seric if (noinfo) 77258151Seric message("504 HELP topic unknown"); 7734577Seric else 77458151Seric message("214 End of HELP info"); 7754628Seric (void) fclose(hf); 7764577Seric } 7778544Seric /* 7789339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7799339Seric ** 7809339Seric ** Parameters: 7819339Seric ** label -- a string used in error messages 7829339Seric ** 7839339Seric ** Returns: 7849339Seric ** zero in the child 7859339Seric ** one in the parent 7869339Seric ** 7879339Seric ** Side Effects: 7889339Seric ** none. 7899339Seric */ 7908544Seric 79155012Seric runinchild(label, e) 7929339Seric char *label; 79355012Seric register ENVELOPE *e; 7949339Seric { 7959339Seric int childpid; 7969339Seric 79716158Seric if (!OneXact) 7989339Seric { 79916158Seric childpid = dofork(); 80016158Seric if (childpid < 0) 80116158Seric { 80216158Seric syserr("%s: cannot fork", label); 80316158Seric return (1); 80416158Seric } 80516158Seric if (childpid > 0) 80616158Seric { 80716158Seric auto int st; 8089339Seric 80916158Seric /* parent -- wait for child to complete */ 81016158Seric st = waitfor(childpid); 81116158Seric if (st == -1) 81216158Seric syserr("%s: lost child", label); 8139339Seric 81416158Seric /* if we exited on a QUIT command, complete the process */ 81516158Seric if (st == (EX_QUIT << 8)) 81616158Seric finis(); 8179339Seric 81816158Seric return (1); 81916158Seric } 82016158Seric else 82116158Seric { 82216158Seric /* child */ 82316158Seric InChild = TRUE; 82425050Seric QuickAbort = FALSE; 82555012Seric clearenvelope(e, FALSE); 82616158Seric } 8279339Seric } 82815256Seric 82916158Seric /* open alias database */ 83055012Seric initaliases(AliasFile, FALSE, e); 83116158Seric 83216158Seric return (0); 8339339Seric } 8349339Seric 83556795Seric # endif /* SMTP */ 836