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*58789Seric static char sccsid[] = "@(#)srvrsmtp.c 6.29 (Berkeley) 03/23/93 (with SMTP)"; 1433731Sbostic #else 15*58789Seric static char sccsid[] = "@(#)srvrsmtp.c 6.29 (Berkeley) 03/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; 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 { 233*58789Seric auth_warning(e, "Host %s claimed to be %s", 234*58789Seric 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 */ 259*58789Seric if (!gothello) 26058082Seric { 261*58789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 262*58789Seric message("503 Polite people say HELO first"); 263*58789Seric else 264*58789Seric auth_warning(e, 265*58789Seric "Host %s didn't use HELO protocol", 266*58789Seric RealHostName); 26758082Seric break; 26858082Seric } 26958109Seric if (gotmail) 2704558Seric { 27158151Seric message("503 Sender already specified"); 2724558Seric break; 2734558Seric } 2749339Seric if (InChild) 2759339Seric { 27636230Skarels errno = 0; 27758151Seric syserr("503 Nested MAIL command: MAIL %s", p); 27858069Seric finis(); 2799339Seric } 2809339Seric 2819339Seric /* fork a subprocess to process this command */ 28255012Seric if (runinchild("SMTP-MAIL", e) > 0) 2839339Seric break; 28458064Seric if (sendinghost != NULL) 28558064Seric define('s', sendinghost, e); 28658323Seric if (protocol == NULL) 28758323Seric protocol = "SMTP"; 28858323Seric define('r', protocol, e); 28955012Seric initsys(e); 29057389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2919339Seric 2929339Seric /* child -- go do the processing */ 2934549Seric p = skipword(p, "from"); 2944549Seric if (p == NULL) 2954549Seric break; 29657977Seric if (setjmp(TopFrame) > 0) 29758147Seric { 29858147Seric /* this failed -- undo work */ 29958147Seric if (InChild) 30058147Seric finis(); 30157977Seric break; 30258147Seric } 30357977Seric QuickAbort = TRUE; 30458333Seric 30558333Seric /* must parse sender first */ 30658333Seric delimptr = NULL; 30758704Seric setsender(p, e, &delimptr, FALSE); 30858333Seric p = delimptr; 30958333Seric if (p != NULL && *p != '\0') 31058333Seric *p++ = '\0'; 31158333Seric 31258333Seric /* now parse ESMTP arguments */ 31358333Seric msize = 0; 31458333Seric for (; p != NULL && *p != '\0'; p++) 31558333Seric { 31658333Seric char *kp; 31758333Seric char *vp; 31858333Seric 31958333Seric /* locate the beginning of the keyword */ 32058333Seric while (isascii(*p) && isspace(*p)) 32158333Seric p++; 32258333Seric if (*p == '\0') 32358333Seric break; 32458333Seric kp = p; 32558333Seric 32658333Seric /* skip to the value portion */ 32758333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 32858333Seric p++; 32958333Seric if (*p == '=') 33058333Seric { 33158333Seric *p++ = '\0'; 33258333Seric vp = p; 33358333Seric 33458333Seric /* skip to the end of the value */ 33558333Seric while (*p != '\0' && *p != ' ' && 33658333Seric !(isascii(*p) && iscntrl(*p)) && 33758333Seric *p != '=') 33858333Seric p++; 33958333Seric } 34058333Seric 34158333Seric if (*p != '\0') 34258333Seric *p++ = '\0'; 34358333Seric 34458333Seric if (tTd(19, 1)) 34558333Seric printf("MAIL: got arg %s=%s\n", kp, 34658333Seric vp == NULL ? "<null>" : vp); 34758333Seric 34858333Seric if (strcasecmp(kp, "size") == 0) 34958333Seric { 35058333Seric if (kp == NULL) 35158333Seric { 35258333Seric usrerr("501 SIZE requires a value"); 35358333Seric /* NOTREACHED */ 35458333Seric } 35558333Seric msize = atol(vp); 35658333Seric } 35758333Seric else 35858333Seric { 35958333Seric usrerr("501 %s parameter unrecognized", kp); 36058333Seric /* NOTREACHED */ 36158333Seric } 36258333Seric } 36358333Seric 36458333Seric if (!enoughspace(msize)) 36558333Seric { 36658333Seric message("452 Insufficient disk space; try again later"); 36758333Seric break; 36858333Seric } 36958151Seric message("250 Sender ok"); 37058147Seric gotmail = TRUE; 3714549Seric break; 3724549Seric 3734976Seric case CMDRCPT: /* rcpt -- designate recipient */ 37424943Seric SmtpPhase = "RCPT"; 37557389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 37612612Seric if (setjmp(TopFrame) > 0) 37714785Seric { 37855012Seric e->e_flags &= ~EF_FATALERRS; 37912612Seric break; 38014785Seric } 38112612Seric QuickAbort = TRUE; 38251951Seric LogUsrErrs = TRUE; 38358093Seric 38458093Seric /* optimization -- if queueing, don't expand aliases */ 38558734Seric if (e->e_sendmode == SM_QUEUE) 38658093Seric e->e_flags |= EF_VRFYONLY; 38758093Seric 3884549Seric p = skipword(p, "to"); 3894549Seric if (p == NULL) 3904549Seric break; 39158333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 39212612Seric if (a == NULL) 39312612Seric break; 39416886Seric a->q_flags |= QPRIMARY; 39555012Seric a = recipient(a, &e->e_sendqueue, e); 39612612Seric if (Errors != 0) 39712612Seric break; 39812612Seric 39912612Seric /* no errors during parsing, but might be a duplicate */ 40055012Seric e->e_to = p; 40112612Seric if (!bitset(QBADADDR, a->q_flags)) 40258151Seric message("250 Recipient ok"); 40312612Seric else 4044549Seric { 40512612Seric /* punt -- should keep message in ADDRESS.... */ 40658151Seric message("550 Addressee unknown"); 4074549Seric } 40855012Seric e->e_to = NULL; 4094549Seric break; 4104549Seric 4114549Seric case CMDDATA: /* data -- text of mail */ 41224943Seric SmtpPhase = "DATA"; 41358109Seric if (!gotmail) 4144549Seric { 41558151Seric message("503 Need MAIL command"); 4164976Seric break; 4174549Seric } 41855012Seric else if (e->e_nrcpts <= 0) 4194549Seric { 42058151Seric message("503 Need RCPT (recipient)"); 4214976Seric break; 4224549Seric } 4234976Seric 4244976Seric /* collect the text of the message */ 42524943Seric SmtpPhase = "collect"; 42657389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 42755012Seric collect(TRUE, e); 4284976Seric if (Errors != 0) 4294976Seric break; 4304976Seric 4318238Seric /* 4328238Seric ** Arrange to send to everyone. 4338238Seric ** If sending to multiple people, mail back 4348238Seric ** errors rather than reporting directly. 4358238Seric ** In any case, don't mail back errors for 4368238Seric ** anything that has happened up to 4378238Seric ** now (the other end will do this). 43810197Seric ** Truncate our transcript -- the mail has gotten 43910197Seric ** to us successfully, and if we have 44010197Seric ** to mail this back, it will be easier 44110197Seric ** on the reader. 4428238Seric ** Then send to everyone. 4438238Seric ** Finally give a reply code. If an error has 4448238Seric ** already been given, don't mail a 4458238Seric ** message back. 4469339Seric ** We goose error returns by clearing error bit. 4478238Seric */ 4488238Seric 44924943Seric SmtpPhase = "delivery"; 45055012Seric if (e->e_nrcpts != 1) 4519378Seric { 4529378Seric HoldErrs = TRUE; 45358734Seric e->e_errormode = EM_MAIL; 4549378Seric } 45555012Seric e->e_flags &= ~EF_FATALERRS; 45655012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 45758714Seric id = e->e_id; 4584976Seric 4594976Seric /* send to all recipients */ 46055012Seric sendall(e, SM_DEFAULT); 46155012Seric e->e_to = NULL; 4624976Seric 46323516Seric /* save statistics */ 46455012Seric markstats(e, (ADDRESS *) NULL); 46523516Seric 4668238Seric /* issue success if appropriate and reset */ 4678238Seric if (Errors == 0 || HoldErrs) 46858714Seric message("250 %s OK", id); 4698238Seric else 47055012Seric e->e_flags &= ~EF_FATALERRS; 4719339Seric 4729339Seric /* if in a child, pop back to our parent */ 4739339Seric if (InChild) 4749339Seric finis(); 47524943Seric 47624943Seric /* clean up a bit */ 47758109Seric gotmail = FALSE; 47855012Seric dropenvelope(e); 47958179Seric CurEnv = e = newenvelope(e, CurEnv); 48055012Seric e->e_flags = BlankEnvelope.e_flags; 4814549Seric break; 4824549Seric 4834549Seric case CMDRSET: /* rset -- reset state */ 48458151Seric message("250 Reset state"); 4859339Seric if (InChild) 4869339Seric finis(); 48758109Seric 48858109Seric /* clean up a bit */ 48958109Seric gotmail = FALSE; 49058109Seric dropenvelope(e); 49158179Seric CurEnv = e = newenvelope(e, CurEnv); 4929339Seric break; 4934549Seric 4944549Seric case CMDVRFY: /* vrfy -- verify address */ 49558092Seric case CMDEXPN: /* expn -- expand address */ 49658092Seric vrfy = c->cmdcode == CMDVRFY; 49758092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 49858092Seric PrivacyFlags)) 49958082Seric { 50058412Seric if (vrfy) 50158412Seric message("252 Who's to say?"); 50258412Seric else 50358412Seric message("502 That's none of your business"); 50458082Seric break; 50558082Seric } 50658082Seric else if (!gothello && 50758092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 50858092Seric PrivacyFlags)) 50958082Seric { 51058151Seric message("503 I demand that you introduce yourself first"); 51158082Seric break; 51258082Seric } 51358092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5149339Seric break; 51525050Seric setproctitle("%s: %s", CurHostName, inp); 51655173Seric #ifdef LOG 51758020Seric if (LogLevel > 5) 51855173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 51955173Seric #endif 5205003Seric vrfyqueue = NULL; 5217762Seric QuickAbort = TRUE; 52258092Seric if (vrfy) 52358092Seric e->e_flags |= EF_VRFYONLY; 52458082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5257762Seric if (Errors != 0) 5269339Seric { 5279339Seric if (InChild) 5289339Seric finis(); 5297762Seric break; 5309339Seric } 5315003Seric while (vrfyqueue != NULL) 5325003Seric { 5335003Seric register ADDRESS *a = vrfyqueue->q_next; 5345003Seric char *code; 5355003Seric 5367685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5375003Seric a = a->q_next; 5385003Seric 5397685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 54058151Seric printvrfyaddr(vrfyqueue, a == NULL); 5415003Seric else if (a == NULL) 54258151Seric message("554 Self destructive alias loop"); 5435003Seric vrfyqueue = a; 5445003Seric } 5459339Seric if (InChild) 5469339Seric finis(); 5474549Seric break; 5484549Seric 5494549Seric case CMDHELP: /* help -- give user info */ 5504577Seric help(p); 5514549Seric break; 5524549Seric 5534549Seric case CMDNOOP: /* noop -- do nothing */ 55458151Seric message("200 OK"); 5554549Seric break; 5564549Seric 5574549Seric case CMDQUIT: /* quit -- leave mail */ 55858151Seric message("221 %s closing connection", MyHostName); 5599339Seric if (InChild) 5609339Seric ExitStat = EX_QUIT; 5614549Seric finis(); 5624549Seric 5638544Seric case CMDVERB: /* set verbose mode */ 5648544Seric Verbose = TRUE; 56558734Seric e->e_sendmode = SM_DELIVER; 56658151Seric message("200 Verbose mode"); 5678544Seric break; 5688544Seric 5699314Seric case CMDONEX: /* doing one transaction only */ 5709378Seric OneXact = TRUE; 57158151Seric message("200 Only one transaction"); 5729314Seric break; 5739314Seric 57436230Skarels # ifdef SMTPDEBUG 5759339Seric case CMDDBGQSHOW: /* show queues */ 5766907Seric printf("Send Queue="); 57755012Seric printaddr(e->e_sendqueue, TRUE); 5785003Seric break; 5797275Seric 5807275Seric case CMDDBGDEBUG: /* set debug mode */ 5817676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5827676Seric tTflag(p); 58358151Seric message("200 Debug set"); 5847275Seric break; 5857275Seric 58636230Skarels # else /* not SMTPDEBUG */ 58724945Seric 58836230Skarels case CMDDBGQSHOW: /* show queues */ 58936230Skarels case CMDDBGDEBUG: /* set debug mode */ 59036233Skarels # ifdef LOG 59158308Seric if (LogLevel > 0) 59236230Skarels syslog(LOG_NOTICE, 59358020Seric "\"%s\" command from %s (%s)", 59436230Skarels c->cmdname, RealHostName, 59558755Seric anynet_ntoa(&RealHostAddr)); 59636233Skarels # endif 59736230Skarels /* FALL THROUGH */ 59836230Skarels # endif /* SMTPDEBUG */ 59936230Skarels 6004549Seric case CMDERROR: /* unknown command */ 60158151Seric message("500 Command unrecognized"); 6024549Seric break; 6034549Seric 6044549Seric default: 60536230Skarels errno = 0; 60658151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6074549Seric break; 6084549Seric } 6094549Seric } 6104549Seric } 6114549Seric /* 6124549Seric ** SKIPWORD -- skip a fixed word. 6134549Seric ** 6144549Seric ** Parameters: 6154549Seric ** p -- place to start looking. 6164549Seric ** w -- word to skip. 6174549Seric ** 6184549Seric ** Returns: 6194549Seric ** p following w. 6204549Seric ** NULL on error. 6214549Seric ** 6224549Seric ** Side Effects: 6234549Seric ** clobbers the p data area. 6244549Seric */ 6254549Seric 6264549Seric static char * 6274549Seric skipword(p, w) 6284549Seric register char *p; 6294549Seric char *w; 6304549Seric { 6314549Seric register char *q; 6324549Seric 6334549Seric /* find beginning of word */ 63458050Seric while (isascii(*p) && isspace(*p)) 6354549Seric p++; 6364549Seric q = p; 6374549Seric 6384549Seric /* find end of word */ 63958050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6404549Seric p++; 64158050Seric while (isascii(*p) && isspace(*p)) 6424549Seric *p++ = '\0'; 6434549Seric if (*p != ':') 6444549Seric { 6454549Seric syntax: 64658151Seric message("501 Syntax error"); 6474549Seric Errors++; 6484549Seric return (NULL); 6494549Seric } 6504549Seric *p++ = '\0'; 65158050Seric while (isascii(*p) && isspace(*p)) 6524549Seric p++; 6534549Seric 6544549Seric /* see if the input word matches desired word */ 65533725Sbostic if (strcasecmp(q, w)) 6564549Seric goto syntax; 6574549Seric 6584549Seric return (p); 6594549Seric } 6604577Seric /* 66158151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 66258151Seric ** 66358151Seric ** Parameters: 66458151Seric ** a -- the address to print 66558151Seric ** last -- set if this is the last one. 66658151Seric ** 66758151Seric ** Returns: 66858151Seric ** none. 66958151Seric ** 67058151Seric ** Side Effects: 67158151Seric ** Prints the appropriate 250 codes. 67258151Seric */ 67358151Seric 67458151Seric printvrfyaddr(a, last) 67558151Seric register ADDRESS *a; 67658151Seric bool last; 67758151Seric { 67858151Seric char fmtbuf[20]; 67958151Seric 68058151Seric strcpy(fmtbuf, "250"); 68158151Seric fmtbuf[3] = last ? ' ' : '-'; 68258151Seric 68358151Seric if (strchr(a->q_paddr, '<') != NULL) 68458151Seric strcpy(&fmtbuf[4], "%s"); 68558151Seric else if (a->q_fullname == NULL) 68658151Seric strcpy(&fmtbuf[4], "<%s>"); 68758151Seric else 68858151Seric { 68958151Seric strcpy(&fmtbuf[4], "%s <%s>"); 69058151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 69158151Seric return; 69258151Seric } 69358151Seric message(fmtbuf, a->q_paddr); 69458151Seric } 69558151Seric /* 6964577Seric ** HELP -- implement the HELP command. 6974577Seric ** 6984577Seric ** Parameters: 6994577Seric ** topic -- the topic we want help for. 7004577Seric ** 7014577Seric ** Returns: 7024577Seric ** none. 7034577Seric ** 7044577Seric ** Side Effects: 7054577Seric ** outputs the help file to message output. 7064577Seric */ 7074577Seric 7084577Seric help(topic) 7094577Seric char *topic; 7104577Seric { 7114577Seric register FILE *hf; 7124577Seric int len; 7134577Seric char buf[MAXLINE]; 7144577Seric bool noinfo; 7154577Seric 7168269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7174577Seric { 7184577Seric /* no help */ 71911931Seric errno = 0; 72058151Seric message("502 HELP not implemented"); 7214577Seric return; 7224577Seric } 7234577Seric 72449669Seric if (topic == NULL || *topic == '\0') 72549669Seric topic = "smtp"; 72649669Seric else 72749669Seric makelower(topic); 72849669Seric 7294577Seric len = strlen(topic); 7304577Seric noinfo = TRUE; 7314577Seric 7324577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7334577Seric { 7344577Seric if (strncmp(buf, topic, len) == 0) 7354577Seric { 7364577Seric register char *p; 7374577Seric 73856795Seric p = strchr(buf, '\t'); 7394577Seric if (p == NULL) 7404577Seric p = buf; 7414577Seric else 7424577Seric p++; 7434577Seric fixcrlf(p, TRUE); 74458151Seric message("214-%s", p); 7454577Seric noinfo = FALSE; 7464577Seric } 7474577Seric } 7484577Seric 7494577Seric if (noinfo) 75058151Seric message("504 HELP topic unknown"); 7514577Seric else 75258151Seric message("214 End of HELP info"); 7534628Seric (void) fclose(hf); 7544577Seric } 7558544Seric /* 7569339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7579339Seric ** 7589339Seric ** Parameters: 7599339Seric ** label -- a string used in error messages 7609339Seric ** 7619339Seric ** Returns: 7629339Seric ** zero in the child 7639339Seric ** one in the parent 7649339Seric ** 7659339Seric ** Side Effects: 7669339Seric ** none. 7679339Seric */ 7688544Seric 76955012Seric runinchild(label, e) 7709339Seric char *label; 77155012Seric register ENVELOPE *e; 7729339Seric { 7739339Seric int childpid; 7749339Seric 77516158Seric if (!OneXact) 7769339Seric { 77716158Seric childpid = dofork(); 77816158Seric if (childpid < 0) 77916158Seric { 78016158Seric syserr("%s: cannot fork", label); 78116158Seric return (1); 78216158Seric } 78316158Seric if (childpid > 0) 78416158Seric { 78516158Seric auto int st; 7869339Seric 78716158Seric /* parent -- wait for child to complete */ 78816158Seric st = waitfor(childpid); 78916158Seric if (st == -1) 79016158Seric syserr("%s: lost child", label); 7919339Seric 79216158Seric /* if we exited on a QUIT command, complete the process */ 79316158Seric if (st == (EX_QUIT << 8)) 79416158Seric finis(); 7959339Seric 79616158Seric return (1); 79716158Seric } 79816158Seric else 79916158Seric { 80016158Seric /* child */ 80116158Seric InChild = TRUE; 80225050Seric QuickAbort = FALSE; 80355012Seric clearenvelope(e, FALSE); 80416158Seric } 8059339Seric } 80615256Seric 80716158Seric /* open alias database */ 80855012Seric initaliases(AliasFile, FALSE, e); 80916158Seric 81016158Seric return (0); 8119339Seric } 8129339Seric 81356795Seric # endif /* SMTP */ 814