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*59066Seric static char sccsid[] = "@(#)srvrsmtp.c 6.43 (Berkeley) 04/13/93 (with SMTP)"; 1433731Sbostic #else 15*59066Seric static char sccsid[] = "@(#)srvrsmtp.c 6.43 (Berkeley) 04/13/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; 1108544Seric char inp[MAXLINE]; 11157232Seric char cmdbuf[MAXLINE]; 1127124Seric extern char Version[]; 11311151Seric extern char *macvalue(); 11412612Seric extern ADDRESS *recipient(); 11524943Seric extern ENVELOPE BlankEnvelope; 11624943Seric extern ENVELOPE *newenvelope(); 11758755Seric extern char *anynet_ntoa(); 1184549Seric 119*59066Seric if (fileno(OutChannel) != fileno(stdout)) 1207363Seric { 1217363Seric /* arrange for debugging output to go to remote host */ 122*59066Seric (void) dup2(fileno(OutChannel), fileno(stdout)); 1237363Seric } 12455012Seric settime(e); 12557642Seric CurHostName = RealHostName; 12659060Seric setproctitle("srvrsmtp %s startup", CurHostName); 12758050Seric expand("\201e", inp, &inp[sizeof inp], e); 12858151Seric message("220 %s", inp); 12958330Seric protocol = NULL; 13059016Seric sendinghost = macvalue('s', e); 13158082Seric gothello = FALSE; 13258330Seric gotmail = FALSE; 1334549Seric for (;;) 1344549Seric { 13512612Seric /* arrange for backout */ 13612612Seric if (setjmp(TopFrame) > 0 && InChild) 13759058Seric { 13859058Seric QuickAbort = FALSE; 13959058Seric SuprErrs = TRUE; 14012612Seric finis(); 14159058Seric } 14212612Seric QuickAbort = FALSE; 14312612Seric HoldErrs = FALSE; 14451951Seric LogUsrErrs = FALSE; 14558092Seric e->e_flags &= ~EF_VRFYONLY; 14612612Seric 1477356Seric /* setup for the read */ 14855012Seric e->e_to = NULL; 1494577Seric Errors = 0; 1507275Seric (void) fflush(stdout); 1517356Seric 1527356Seric /* read the input line */ 15359060Seric SmtpPhase = "srvrsmtp cmd read"; 15459060Seric setproctitle("srvrsmtp %s cmd read", CurHostName); 15558109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1567356Seric 1577685Seric /* handle errors */ 1587356Seric if (p == NULL) 1597356Seric { 1604549Seric /* end of file, just die */ 16158151Seric message("421 %s Lost input channel from %s", 16225050Seric MyHostName, CurHostName); 16355464Seric #ifdef LOG 16458020Seric if (LogLevel > 1) 16555464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16655464Seric CurHostName); 16755464Seric #endif 16858069Seric if (InChild) 16958069Seric ExitStat = EX_QUIT; 1704549Seric finis(); 1714549Seric } 1724549Seric 1734549Seric /* clean up end of line */ 1744558Seric fixcrlf(inp, TRUE); 1754549Seric 1764713Seric /* echo command to transcript */ 17755012Seric if (e->e_xfp != NULL) 17855012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1794713Seric 18059060Seric if (e->e_id == NULL) 18159060Seric setproctitle("%s: %s", CurHostName, inp); 18259060Seric else 18359060Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 18459060Seric 1854549Seric /* break off command */ 18658050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1874549Seric continue; 18857232Seric cmd = cmdbuf; 18958050Seric while (*p != '\0' && 19058050Seric !(isascii(*p) && isspace(*p)) && 19158050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 19224981Seric *cmd++ = *p++; 19324981Seric *cmd = '\0'; 1944549Seric 19525691Seric /* throw away leading whitespace */ 19658050Seric while (isascii(*p) && isspace(*p)) 19725691Seric p++; 19825691Seric 1994549Seric /* decode command */ 2004549Seric for (c = CmdTab; c->cmdname != NULL; c++) 2014549Seric { 20233725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 2034549Seric break; 2044549Seric } 2054549Seric 20651954Seric /* reset errors */ 20751954Seric errno = 0; 20851954Seric 2094549Seric /* process command */ 2104549Seric switch (c->cmdcode) 2114549Seric { 2124976Seric case CMDHELO: /* hello -- introduce yourself */ 21358323Seric case CMDEHLO: /* extended hello */ 21458323Seric if (c->cmdcode == CMDEHLO) 21558323Seric { 21658323Seric protocol = "ESMTP"; 21758323Seric SmtpPhase = "EHLO"; 21858323Seric } 21958323Seric else 22058323Seric { 22158323Seric protocol = "SMTP"; 22258323Seric SmtpPhase = "HELO"; 22358323Seric } 22459016Seric sendinghost = newstr(p); 22558308Seric if (strcasecmp(p, RealHostName) != 0) 22611146Seric { 22758789Seric auth_warning(e, "Host %s claimed to be %s", 22858789Seric RealHostName, p); 22911146Seric } 23058957Seric p = macvalue('_', e); 23158957Seric if (p == NULL) 23259016Seric p = RealHostName; 23358323Seric 23458323Seric /* send ext. message -- old systems must ignore */ 23558323Seric message("250-%s Hello %s, pleased to meet you", 23658957Seric MyHostName, p); 23758323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 23858323Seric message("250-EXPN"); 23958338Seric message("250-SIZE"); 24058323Seric message("250 HELP"); 24158082Seric gothello = TRUE; 2424976Seric break; 2434976Seric 2444549Seric case CMDMAIL: /* mail -- designate sender */ 24524943Seric SmtpPhase = "MAIL"; 24624943Seric 2479314Seric /* check for validity of this command */ 24858789Seric if (!gothello) 24958082Seric { 25058957Seric /* set sending host to our known value */ 25159016Seric if (sendinghost == NULL) 25259016Seric sendinghost = RealHostName; 25358957Seric 25458789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25558821Seric { 25658789Seric message("503 Polite people say HELO first"); 25758821Seric break; 25858821Seric } 25958789Seric else 26058821Seric { 26158789Seric auth_warning(e, 26258789Seric "Host %s didn't use HELO protocol", 26358789Seric RealHostName); 26458821Seric } 26558082Seric } 26658109Seric if (gotmail) 2674558Seric { 26858151Seric message("503 Sender already specified"); 2694558Seric break; 2704558Seric } 2719339Seric if (InChild) 2729339Seric { 27336230Skarels errno = 0; 27458151Seric syserr("503 Nested MAIL command: MAIL %s", p); 27558069Seric finis(); 2769339Seric } 2779339Seric 2789339Seric /* fork a subprocess to process this command */ 27955012Seric if (runinchild("SMTP-MAIL", e) > 0) 2809339Seric break; 28158323Seric if (protocol == NULL) 28258323Seric protocol = "SMTP"; 28358323Seric define('r', protocol, e); 28459016Seric define('s', sendinghost, e); 28555012Seric initsys(e); 28657389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2879339Seric 2889339Seric /* child -- go do the processing */ 2894549Seric p = skipword(p, "from"); 2904549Seric if (p == NULL) 2914549Seric break; 29257977Seric if (setjmp(TopFrame) > 0) 29358147Seric { 29458147Seric /* this failed -- undo work */ 29558147Seric if (InChild) 29659058Seric { 29759058Seric QuickAbort = FALSE; 29859058Seric SuprErrs = TRUE; 29958147Seric finis(); 30059058Seric } 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 */ 37458850Seric if (!gotmail) 37558850Seric { 37658850Seric usrerr("503 Need MAIL before RCPT"); 37758850Seric break; 37858850Seric } 37924943Seric SmtpPhase = "RCPT"; 38012612Seric if (setjmp(TopFrame) > 0) 38114785Seric { 38255012Seric e->e_flags &= ~EF_FATALERRS; 38312612Seric break; 38414785Seric } 38512612Seric QuickAbort = TRUE; 38651951Seric LogUsrErrs = TRUE; 38758093Seric 38858919Seric e->e_flags |= EF_VRFYONLY; 38958919Seric 3904549Seric p = skipword(p, "to"); 3914549Seric if (p == NULL) 3924549Seric break; 39358333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 39412612Seric if (a == NULL) 39512612Seric break; 39616886Seric a->q_flags |= QPRIMARY; 39755012Seric a = recipient(a, &e->e_sendqueue, e); 39812612Seric if (Errors != 0) 39912612Seric break; 40012612Seric 40112612Seric /* no errors during parsing, but might be a duplicate */ 40255012Seric e->e_to = p; 40312612Seric if (!bitset(QBADADDR, a->q_flags)) 40458151Seric message("250 Recipient ok"); 40512612Seric else 4064549Seric { 40712612Seric /* punt -- should keep message in ADDRESS.... */ 40858151Seric message("550 Addressee unknown"); 4094549Seric } 41055012Seric e->e_to = NULL; 4114549Seric break; 4124549Seric 4134549Seric case CMDDATA: /* data -- text of mail */ 41424943Seric SmtpPhase = "DATA"; 41558109Seric if (!gotmail) 4164549Seric { 41758151Seric message("503 Need MAIL command"); 4184976Seric break; 4194549Seric } 42055012Seric else if (e->e_nrcpts <= 0) 4214549Seric { 42258151Seric message("503 Need RCPT (recipient)"); 4234976Seric break; 4244549Seric } 4254976Seric 42658929Seric /* check to see if we need to re-expand aliases */ 42758929Seric for (a = e->e_sendqueue; a != NULL; a = a->q_next) 42858929Seric { 42958929Seric if (bitset(QVERIFIED, a->q_flags)) 43058929Seric break; 43158929Seric } 43258929Seric 4334976Seric /* collect the text of the message */ 43424943Seric SmtpPhase = "collect"; 43558929Seric collect(TRUE, a != NULL, e); 4364976Seric if (Errors != 0) 4374976Seric break; 4384976Seric 4398238Seric /* 4408238Seric ** Arrange to send to everyone. 4418238Seric ** If sending to multiple people, mail back 4428238Seric ** errors rather than reporting directly. 4438238Seric ** In any case, don't mail back errors for 4448238Seric ** anything that has happened up to 4458238Seric ** now (the other end will do this). 44610197Seric ** Truncate our transcript -- the mail has gotten 44710197Seric ** to us successfully, and if we have 44810197Seric ** to mail this back, it will be easier 44910197Seric ** on the reader. 4508238Seric ** Then send to everyone. 4518238Seric ** Finally give a reply code. If an error has 4528238Seric ** already been given, don't mail a 4538238Seric ** message back. 4549339Seric ** We goose error returns by clearing error bit. 4558238Seric */ 4568238Seric 45724943Seric SmtpPhase = "delivery"; 45855012Seric if (e->e_nrcpts != 1) 4599378Seric { 4609378Seric HoldErrs = TRUE; 46158734Seric e->e_errormode = EM_MAIL; 4629378Seric } 46355012Seric e->e_flags &= ~EF_FATALERRS; 46455012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 46558714Seric id = e->e_id; 4664976Seric 4674976Seric /* send to all recipients */ 46858919Seric sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 46955012Seric e->e_to = NULL; 4704976Seric 47123516Seric /* save statistics */ 47255012Seric markstats(e, (ADDRESS *) NULL); 47323516Seric 4748238Seric /* issue success if appropriate and reset */ 4758238Seric if (Errors == 0 || HoldErrs) 47658855Seric message("250 %s Message accepted for delivery", id); 4778238Seric else 47855012Seric e->e_flags &= ~EF_FATALERRS; 4799339Seric 48058919Seric /* if we just queued, poke it */ 48158919Seric if (a != NULL && e->e_sendmode != SM_QUEUE) 48258919Seric { 48358919Seric unlockqueue(e); 48458924Seric dowork(id, TRUE, TRUE, e); 48558919Seric e->e_id = NULL; 48658919Seric } 48758883Seric 4889339Seric /* if in a child, pop back to our parent */ 4899339Seric if (InChild) 4909339Seric finis(); 49124943Seric 49224943Seric /* clean up a bit */ 49358109Seric gotmail = FALSE; 49455012Seric dropenvelope(e); 49558179Seric CurEnv = e = newenvelope(e, CurEnv); 49655012Seric e->e_flags = BlankEnvelope.e_flags; 4974549Seric break; 4984549Seric 4994549Seric case CMDRSET: /* rset -- reset state */ 50058151Seric message("250 Reset state"); 5019339Seric if (InChild) 5029339Seric finis(); 50358109Seric 50458109Seric /* clean up a bit */ 50558109Seric gotmail = FALSE; 50658109Seric dropenvelope(e); 50758179Seric CurEnv = e = newenvelope(e, CurEnv); 5089339Seric break; 5094549Seric 5104549Seric case CMDVRFY: /* vrfy -- verify address */ 51158092Seric case CMDEXPN: /* expn -- expand address */ 51258092Seric vrfy = c->cmdcode == CMDVRFY; 51358092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 51458092Seric PrivacyFlags)) 51558082Seric { 51658412Seric if (vrfy) 51758412Seric message("252 Who's to say?"); 51858412Seric else 51958412Seric message("502 That's none of your business"); 52058082Seric break; 52158082Seric } 52258082Seric else if (!gothello && 52358092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 52458092Seric PrivacyFlags)) 52558082Seric { 52658151Seric message("503 I demand that you introduce yourself first"); 52758082Seric break; 52858082Seric } 52958092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5309339Seric break; 53155173Seric #ifdef LOG 53258020Seric if (LogLevel > 5) 53355173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 53455173Seric #endif 5355003Seric vrfyqueue = NULL; 5367762Seric QuickAbort = TRUE; 53758092Seric if (vrfy) 53858092Seric e->e_flags |= EF_VRFYONLY; 53958082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5407762Seric if (Errors != 0) 5419339Seric { 5429339Seric if (InChild) 5439339Seric finis(); 5447762Seric break; 5459339Seric } 5465003Seric while (vrfyqueue != NULL) 5475003Seric { 5485003Seric register ADDRESS *a = vrfyqueue->q_next; 5495003Seric char *code; 5505003Seric 5517685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5525003Seric a = a->q_next; 5535003Seric 5547685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 55558151Seric printvrfyaddr(vrfyqueue, a == NULL); 5565003Seric else if (a == NULL) 55758151Seric message("554 Self destructive alias loop"); 5585003Seric vrfyqueue = a; 5595003Seric } 5609339Seric if (InChild) 5619339Seric finis(); 5624549Seric break; 5634549Seric 5644549Seric case CMDHELP: /* help -- give user info */ 5654577Seric help(p); 5664549Seric break; 5674549Seric 5684549Seric case CMDNOOP: /* noop -- do nothing */ 56958151Seric message("200 OK"); 5704549Seric break; 5714549Seric 5724549Seric case CMDQUIT: /* quit -- leave mail */ 57358151Seric message("221 %s closing connection", MyHostName); 5749339Seric if (InChild) 5759339Seric ExitStat = EX_QUIT; 5764549Seric finis(); 5774549Seric 5788544Seric case CMDVERB: /* set verbose mode */ 5798544Seric Verbose = TRUE; 58058734Seric e->e_sendmode = SM_DELIVER; 58158151Seric message("200 Verbose mode"); 5828544Seric break; 5838544Seric 5849314Seric case CMDONEX: /* doing one transaction only */ 5859378Seric OneXact = TRUE; 58658151Seric message("200 Only one transaction"); 5879314Seric break; 5889314Seric 58936230Skarels # ifdef SMTPDEBUG 5909339Seric case CMDDBGQSHOW: /* show queues */ 5916907Seric printf("Send Queue="); 59255012Seric printaddr(e->e_sendqueue, TRUE); 5935003Seric break; 5947275Seric 5957275Seric case CMDDBGDEBUG: /* set debug mode */ 5967676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5977676Seric tTflag(p); 59858151Seric message("200 Debug set"); 5997275Seric break; 6007275Seric 60136230Skarels # else /* not SMTPDEBUG */ 60224945Seric 60336230Skarels case CMDDBGQSHOW: /* show queues */ 60436230Skarels case CMDDBGDEBUG: /* set debug mode */ 60536233Skarels # ifdef LOG 60658308Seric if (LogLevel > 0) 60736230Skarels syslog(LOG_NOTICE, 60858020Seric "\"%s\" command from %s (%s)", 60936230Skarels c->cmdname, RealHostName, 61058755Seric anynet_ntoa(&RealHostAddr)); 61136233Skarels # endif 61236230Skarels /* FALL THROUGH */ 61336230Skarels # endif /* SMTPDEBUG */ 61436230Skarels 6154549Seric case CMDERROR: /* unknown command */ 61658151Seric message("500 Command unrecognized"); 6174549Seric break; 6184549Seric 6194549Seric default: 62036230Skarels errno = 0; 62158151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6224549Seric break; 6234549Seric } 6244549Seric } 6254549Seric } 6264549Seric /* 6274549Seric ** SKIPWORD -- skip a fixed word. 6284549Seric ** 6294549Seric ** Parameters: 6304549Seric ** p -- place to start looking. 6314549Seric ** w -- word to skip. 6324549Seric ** 6334549Seric ** Returns: 6344549Seric ** p following w. 6354549Seric ** NULL on error. 6364549Seric ** 6374549Seric ** Side Effects: 6384549Seric ** clobbers the p data area. 6394549Seric */ 6404549Seric 6414549Seric static char * 6424549Seric skipword(p, w) 6434549Seric register char *p; 6444549Seric char *w; 6454549Seric { 6464549Seric register char *q; 6474549Seric 6484549Seric /* find beginning of word */ 64958050Seric while (isascii(*p) && isspace(*p)) 6504549Seric p++; 6514549Seric q = p; 6524549Seric 6534549Seric /* find end of word */ 65458050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6554549Seric p++; 65658050Seric while (isascii(*p) && isspace(*p)) 6574549Seric *p++ = '\0'; 6584549Seric if (*p != ':') 6594549Seric { 6604549Seric syntax: 66158151Seric message("501 Syntax error"); 6624549Seric Errors++; 6634549Seric return (NULL); 6644549Seric } 6654549Seric *p++ = '\0'; 66658050Seric while (isascii(*p) && isspace(*p)) 6674549Seric p++; 6684549Seric 6694549Seric /* see if the input word matches desired word */ 67033725Sbostic if (strcasecmp(q, w)) 6714549Seric goto syntax; 6724549Seric 6734549Seric return (p); 6744549Seric } 6754577Seric /* 67658151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 67758151Seric ** 67858151Seric ** Parameters: 67958151Seric ** a -- the address to print 68058151Seric ** last -- set if this is the last one. 68158151Seric ** 68258151Seric ** Returns: 68358151Seric ** none. 68458151Seric ** 68558151Seric ** Side Effects: 68658151Seric ** Prints the appropriate 250 codes. 68758151Seric */ 68858151Seric 68958151Seric printvrfyaddr(a, last) 69058151Seric register ADDRESS *a; 69158151Seric bool last; 69258151Seric { 69358151Seric char fmtbuf[20]; 69458151Seric 69558151Seric strcpy(fmtbuf, "250"); 69658151Seric fmtbuf[3] = last ? ' ' : '-'; 69758151Seric 69858151Seric if (strchr(a->q_paddr, '<') != NULL) 69958151Seric strcpy(&fmtbuf[4], "%s"); 70058151Seric else if (a->q_fullname == NULL) 70158151Seric strcpy(&fmtbuf[4], "<%s>"); 70258151Seric else 70358151Seric { 70458151Seric strcpy(&fmtbuf[4], "%s <%s>"); 70558151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 70658151Seric return; 70758151Seric } 70858151Seric message(fmtbuf, a->q_paddr); 70958151Seric } 71058151Seric /* 7114577Seric ** HELP -- implement the HELP command. 7124577Seric ** 7134577Seric ** Parameters: 7144577Seric ** topic -- the topic we want help for. 7154577Seric ** 7164577Seric ** Returns: 7174577Seric ** none. 7184577Seric ** 7194577Seric ** Side Effects: 7204577Seric ** outputs the help file to message output. 7214577Seric */ 7224577Seric 7234577Seric help(topic) 7244577Seric char *topic; 7254577Seric { 7264577Seric register FILE *hf; 7274577Seric int len; 7284577Seric char buf[MAXLINE]; 7294577Seric bool noinfo; 7304577Seric 7318269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7324577Seric { 7334577Seric /* no help */ 73411931Seric errno = 0; 73558151Seric message("502 HELP not implemented"); 7364577Seric return; 7374577Seric } 7384577Seric 73949669Seric if (topic == NULL || *topic == '\0') 74049669Seric topic = "smtp"; 74149669Seric else 74249669Seric makelower(topic); 74349669Seric 7444577Seric len = strlen(topic); 7454577Seric noinfo = TRUE; 7464577Seric 7474577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7484577Seric { 7494577Seric if (strncmp(buf, topic, len) == 0) 7504577Seric { 7514577Seric register char *p; 7524577Seric 75356795Seric p = strchr(buf, '\t'); 7544577Seric if (p == NULL) 7554577Seric p = buf; 7564577Seric else 7574577Seric p++; 7584577Seric fixcrlf(p, TRUE); 75958151Seric message("214-%s", p); 7604577Seric noinfo = FALSE; 7614577Seric } 7624577Seric } 7634577Seric 7644577Seric if (noinfo) 76558151Seric message("504 HELP topic unknown"); 7664577Seric else 76758151Seric message("214 End of HELP info"); 7684628Seric (void) fclose(hf); 7694577Seric } 7708544Seric /* 7719339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7729339Seric ** 7739339Seric ** Parameters: 7749339Seric ** label -- a string used in error messages 7759339Seric ** 7769339Seric ** Returns: 7779339Seric ** zero in the child 7789339Seric ** one in the parent 7799339Seric ** 7809339Seric ** Side Effects: 7819339Seric ** none. 7829339Seric */ 7838544Seric 78455012Seric runinchild(label, e) 7859339Seric char *label; 78655012Seric register ENVELOPE *e; 7879339Seric { 7889339Seric int childpid; 7899339Seric 79016158Seric if (!OneXact) 7919339Seric { 79216158Seric childpid = dofork(); 79316158Seric if (childpid < 0) 79416158Seric { 79516158Seric syserr("%s: cannot fork", label); 79616158Seric return (1); 79716158Seric } 79816158Seric if (childpid > 0) 79916158Seric { 80016158Seric auto int st; 8019339Seric 80216158Seric /* parent -- wait for child to complete */ 80359060Seric setproctitle("srvrsmtp %s child wait", CurHostName); 80416158Seric st = waitfor(childpid); 80516158Seric if (st == -1) 80616158Seric syserr("%s: lost child", label); 8079339Seric 80816158Seric /* if we exited on a QUIT command, complete the process */ 80916158Seric if (st == (EX_QUIT << 8)) 81016158Seric finis(); 8119339Seric 81216158Seric return (1); 81316158Seric } 81416158Seric else 81516158Seric { 81616158Seric /* child */ 81716158Seric InChild = TRUE; 81825050Seric QuickAbort = FALSE; 81955012Seric clearenvelope(e, FALSE); 82016158Seric } 8219339Seric } 82215256Seric 82316158Seric /* open alias database */ 82455012Seric initaliases(AliasFile, FALSE, e); 82516158Seric 82616158Seric return (0); 8279339Seric } 8289339Seric 82956795Seric # endif /* SMTP */ 830