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*59058Seric static char sccsid[] = "@(#)srvrsmtp.c 6.41 (Berkeley) 04/13/93 (with SMTP)"; 1433731Sbostic #else 15*59058Seric static char sccsid[] = "@(#)srvrsmtp.c 6.41 (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 1197363Seric if (OutChannel != stdout) 1207363Seric { 1217363Seric /* arrange for debugging output to go to remote host */ 1227363Seric (void) close(1); 1237363Seric (void) dup(fileno(OutChannel)); 1247363Seric } 12555012Seric settime(e); 12657642Seric CurHostName = RealHostName; 12757642Seric setproctitle("srvrsmtp %s", CurHostName); 12858050Seric expand("\201e", inp, &inp[sizeof inp], e); 12958151Seric message("220 %s", inp); 13024943Seric SmtpPhase = "startup"; 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) 139*59058Seric { 140*59058Seric QuickAbort = FALSE; 141*59058Seric SuprErrs = TRUE; 14212612Seric finis(); 143*59058Seric } 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 */ 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 1804549Seric /* break off command */ 18158050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1824549Seric continue; 18357232Seric cmd = cmdbuf; 18458050Seric while (*p != '\0' && 18558050Seric !(isascii(*p) && isspace(*p)) && 18658050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 18724981Seric *cmd++ = *p++; 18824981Seric *cmd = '\0'; 1894549Seric 19025691Seric /* throw away leading whitespace */ 19158050Seric while (isascii(*p) && isspace(*p)) 19225691Seric p++; 19325691Seric 1944549Seric /* decode command */ 1954549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1964549Seric { 19733725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1984549Seric break; 1994549Seric } 2004549Seric 20151954Seric /* reset errors */ 20251954Seric errno = 0; 20351954Seric 2044549Seric /* process command */ 2054549Seric switch (c->cmdcode) 2064549Seric { 2074976Seric case CMDHELO: /* hello -- introduce yourself */ 20858323Seric case CMDEHLO: /* extended hello */ 20958323Seric if (c->cmdcode == CMDEHLO) 21058323Seric { 21158323Seric protocol = "ESMTP"; 21258323Seric SmtpPhase = "EHLO"; 21358323Seric } 21458323Seric else 21558323Seric { 21658323Seric protocol = "SMTP"; 21758323Seric SmtpPhase = "HELO"; 21858323Seric } 21925050Seric setproctitle("%s: %s", CurHostName, inp); 22059016Seric sendinghost = newstr(p); 22158308Seric if (strcasecmp(p, RealHostName) != 0) 22211146Seric { 22358789Seric auth_warning(e, "Host %s claimed to be %s", 22458789Seric RealHostName, p); 22511146Seric } 22658957Seric p = macvalue('_', e); 22758957Seric if (p == NULL) 22859016Seric p = RealHostName; 22958323Seric 23058323Seric /* send ext. message -- old systems must ignore */ 23158323Seric message("250-%s Hello %s, pleased to meet you", 23258957Seric MyHostName, p); 23358323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 23458323Seric message("250-EXPN"); 23558338Seric message("250-SIZE"); 23658323Seric message("250 HELP"); 23758082Seric gothello = TRUE; 2384976Seric break; 2394976Seric 2404549Seric case CMDMAIL: /* mail -- designate sender */ 24124943Seric SmtpPhase = "MAIL"; 24224943Seric 2439314Seric /* check for validity of this command */ 24458789Seric if (!gothello) 24558082Seric { 24658957Seric /* set sending host to our known value */ 24759016Seric if (sendinghost == NULL) 24859016Seric sendinghost = RealHostName; 24958957Seric 25058789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25158821Seric { 25258789Seric message("503 Polite people say HELO first"); 25358821Seric break; 25458821Seric } 25558789Seric else 25658821Seric { 25758789Seric auth_warning(e, 25858789Seric "Host %s didn't use HELO protocol", 25958789Seric RealHostName); 26058821Seric } 26158082Seric } 26258109Seric if (gotmail) 2634558Seric { 26458151Seric message("503 Sender already specified"); 2654558Seric break; 2664558Seric } 2679339Seric if (InChild) 2689339Seric { 26936230Skarels errno = 0; 27058151Seric syserr("503 Nested MAIL command: MAIL %s", p); 27158069Seric finis(); 2729339Seric } 2739339Seric 2749339Seric /* fork a subprocess to process this command */ 27555012Seric if (runinchild("SMTP-MAIL", e) > 0) 2769339Seric break; 27758323Seric if (protocol == NULL) 27858323Seric protocol = "SMTP"; 27958323Seric define('r', protocol, e); 28059016Seric define('s', sendinghost, e); 28155012Seric initsys(e); 28257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2839339Seric 2849339Seric /* child -- go do the processing */ 2854549Seric p = skipword(p, "from"); 2864549Seric if (p == NULL) 2874549Seric break; 28857977Seric if (setjmp(TopFrame) > 0) 28958147Seric { 29058147Seric /* this failed -- undo work */ 29158147Seric if (InChild) 292*59058Seric { 293*59058Seric QuickAbort = FALSE; 294*59058Seric SuprErrs = TRUE; 29558147Seric finis(); 296*59058Seric } 29757977Seric break; 29858147Seric } 29957977Seric QuickAbort = TRUE; 30058333Seric 30158333Seric /* must parse sender first */ 30258333Seric delimptr = NULL; 30358704Seric setsender(p, e, &delimptr, FALSE); 30458333Seric p = delimptr; 30558333Seric if (p != NULL && *p != '\0') 30658333Seric *p++ = '\0'; 30758333Seric 30858333Seric /* now parse ESMTP arguments */ 30958333Seric msize = 0; 31058333Seric for (; p != NULL && *p != '\0'; p++) 31158333Seric { 31258333Seric char *kp; 31358333Seric char *vp; 31458333Seric 31558333Seric /* locate the beginning of the keyword */ 31658333Seric while (isascii(*p) && isspace(*p)) 31758333Seric p++; 31858333Seric if (*p == '\0') 31958333Seric break; 32058333Seric kp = p; 32158333Seric 32258333Seric /* skip to the value portion */ 32358333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 32458333Seric p++; 32558333Seric if (*p == '=') 32658333Seric { 32758333Seric *p++ = '\0'; 32858333Seric vp = p; 32958333Seric 33058333Seric /* skip to the end of the value */ 33158333Seric while (*p != '\0' && *p != ' ' && 33258333Seric !(isascii(*p) && iscntrl(*p)) && 33358333Seric *p != '=') 33458333Seric p++; 33558333Seric } 33658333Seric 33758333Seric if (*p != '\0') 33858333Seric *p++ = '\0'; 33958333Seric 34058333Seric if (tTd(19, 1)) 34158333Seric printf("MAIL: got arg %s=%s\n", kp, 34258333Seric vp == NULL ? "<null>" : vp); 34358333Seric 34458333Seric if (strcasecmp(kp, "size") == 0) 34558333Seric { 34658333Seric if (kp == NULL) 34758333Seric { 34858333Seric usrerr("501 SIZE requires a value"); 34958333Seric /* NOTREACHED */ 35058333Seric } 35158333Seric msize = atol(vp); 35258333Seric } 35358333Seric else 35458333Seric { 35558333Seric usrerr("501 %s parameter unrecognized", kp); 35658333Seric /* NOTREACHED */ 35758333Seric } 35858333Seric } 35958333Seric 36058333Seric if (!enoughspace(msize)) 36158333Seric { 36258333Seric message("452 Insufficient disk space; try again later"); 36358333Seric break; 36458333Seric } 36558151Seric message("250 Sender ok"); 36658147Seric gotmail = TRUE; 3674549Seric break; 3684549Seric 3694976Seric case CMDRCPT: /* rcpt -- designate recipient */ 37058850Seric if (!gotmail) 37158850Seric { 37258850Seric usrerr("503 Need MAIL before RCPT"); 37358850Seric break; 37458850Seric } 37524943Seric SmtpPhase = "RCPT"; 37657389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 37712612Seric if (setjmp(TopFrame) > 0) 37814785Seric { 37955012Seric e->e_flags &= ~EF_FATALERRS; 38012612Seric break; 38114785Seric } 38212612Seric QuickAbort = TRUE; 38351951Seric LogUsrErrs = TRUE; 38458093Seric 38558919Seric e->e_flags |= EF_VRFYONLY; 38658919Seric 3874549Seric p = skipword(p, "to"); 3884549Seric if (p == NULL) 3894549Seric break; 39058333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 39112612Seric if (a == NULL) 39212612Seric break; 39316886Seric a->q_flags |= QPRIMARY; 39455012Seric a = recipient(a, &e->e_sendqueue, e); 39512612Seric if (Errors != 0) 39612612Seric break; 39712612Seric 39812612Seric /* no errors during parsing, but might be a duplicate */ 39955012Seric e->e_to = p; 40012612Seric if (!bitset(QBADADDR, a->q_flags)) 40158151Seric message("250 Recipient ok"); 40212612Seric else 4034549Seric { 40412612Seric /* punt -- should keep message in ADDRESS.... */ 40558151Seric message("550 Addressee unknown"); 4064549Seric } 40755012Seric e->e_to = NULL; 4084549Seric break; 4094549Seric 4104549Seric case CMDDATA: /* data -- text of mail */ 41124943Seric SmtpPhase = "DATA"; 41258109Seric if (!gotmail) 4134549Seric { 41458151Seric message("503 Need MAIL command"); 4154976Seric break; 4164549Seric } 41755012Seric else if (e->e_nrcpts <= 0) 4184549Seric { 41958151Seric message("503 Need RCPT (recipient)"); 4204976Seric break; 4214549Seric } 4224976Seric 42358929Seric /* check to see if we need to re-expand aliases */ 42458929Seric for (a = e->e_sendqueue; a != NULL; a = a->q_next) 42558929Seric { 42658929Seric if (bitset(QVERIFIED, a->q_flags)) 42758929Seric break; 42858929Seric } 42958929Seric 4304976Seric /* collect the text of the message */ 43124943Seric SmtpPhase = "collect"; 43257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 43358929Seric collect(TRUE, a != NULL, e); 4344976Seric if (Errors != 0) 4354976Seric break; 4364976Seric 4378238Seric /* 4388238Seric ** Arrange to send to everyone. 4398238Seric ** If sending to multiple people, mail back 4408238Seric ** errors rather than reporting directly. 4418238Seric ** In any case, don't mail back errors for 4428238Seric ** anything that has happened up to 4438238Seric ** now (the other end will do this). 44410197Seric ** Truncate our transcript -- the mail has gotten 44510197Seric ** to us successfully, and if we have 44610197Seric ** to mail this back, it will be easier 44710197Seric ** on the reader. 4488238Seric ** Then send to everyone. 4498238Seric ** Finally give a reply code. If an error has 4508238Seric ** already been given, don't mail a 4518238Seric ** message back. 4529339Seric ** We goose error returns by clearing error bit. 4538238Seric */ 4548238Seric 45524943Seric SmtpPhase = "delivery"; 45655012Seric if (e->e_nrcpts != 1) 4579378Seric { 4589378Seric HoldErrs = TRUE; 45958734Seric e->e_errormode = EM_MAIL; 4609378Seric } 46155012Seric e->e_flags &= ~EF_FATALERRS; 46255012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 46358714Seric id = e->e_id; 4644976Seric 4654976Seric /* send to all recipients */ 46658919Seric sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 46755012Seric e->e_to = NULL; 4684976Seric 46923516Seric /* save statistics */ 47055012Seric markstats(e, (ADDRESS *) NULL); 47123516Seric 4728238Seric /* issue success if appropriate and reset */ 4738238Seric if (Errors == 0 || HoldErrs) 47458855Seric message("250 %s Message accepted for delivery", id); 4758238Seric else 47655012Seric e->e_flags &= ~EF_FATALERRS; 4779339Seric 47858919Seric /* if we just queued, poke it */ 47958919Seric if (a != NULL && e->e_sendmode != SM_QUEUE) 48058919Seric { 48158919Seric unlockqueue(e); 48258924Seric dowork(id, TRUE, TRUE, e); 48358919Seric e->e_id = NULL; 48458919Seric } 48558883Seric 4869339Seric /* if in a child, pop back to our parent */ 4879339Seric if (InChild) 4889339Seric finis(); 48924943Seric 49024943Seric /* clean up a bit */ 49158109Seric gotmail = FALSE; 49255012Seric dropenvelope(e); 49358179Seric CurEnv = e = newenvelope(e, CurEnv); 49455012Seric e->e_flags = BlankEnvelope.e_flags; 4954549Seric break; 4964549Seric 4974549Seric case CMDRSET: /* rset -- reset state */ 49858151Seric message("250 Reset state"); 4999339Seric if (InChild) 5009339Seric finis(); 50158109Seric 50258109Seric /* clean up a bit */ 50358109Seric gotmail = FALSE; 50458109Seric dropenvelope(e); 50558179Seric CurEnv = e = newenvelope(e, CurEnv); 5069339Seric break; 5074549Seric 5084549Seric case CMDVRFY: /* vrfy -- verify address */ 50958092Seric case CMDEXPN: /* expn -- expand address */ 51058092Seric vrfy = c->cmdcode == CMDVRFY; 51158092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 51258092Seric PrivacyFlags)) 51358082Seric { 51458412Seric if (vrfy) 51558412Seric message("252 Who's to say?"); 51658412Seric else 51758412Seric message("502 That's none of your business"); 51858082Seric break; 51958082Seric } 52058082Seric else if (!gothello && 52158092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 52258092Seric PrivacyFlags)) 52358082Seric { 52458151Seric message("503 I demand that you introduce yourself first"); 52558082Seric break; 52658082Seric } 52758092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5289339Seric break; 52925050Seric setproctitle("%s: %s", CurHostName, inp); 53055173Seric #ifdef LOG 53158020Seric if (LogLevel > 5) 53255173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 53355173Seric #endif 5345003Seric vrfyqueue = NULL; 5357762Seric QuickAbort = TRUE; 53658092Seric if (vrfy) 53758092Seric e->e_flags |= EF_VRFYONLY; 53858082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5397762Seric if (Errors != 0) 5409339Seric { 5419339Seric if (InChild) 5429339Seric finis(); 5437762Seric break; 5449339Seric } 5455003Seric while (vrfyqueue != NULL) 5465003Seric { 5475003Seric register ADDRESS *a = vrfyqueue->q_next; 5485003Seric char *code; 5495003Seric 5507685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5515003Seric a = a->q_next; 5525003Seric 5537685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 55458151Seric printvrfyaddr(vrfyqueue, a == NULL); 5555003Seric else if (a == NULL) 55658151Seric message("554 Self destructive alias loop"); 5575003Seric vrfyqueue = a; 5585003Seric } 5599339Seric if (InChild) 5609339Seric finis(); 5614549Seric break; 5624549Seric 5634549Seric case CMDHELP: /* help -- give user info */ 5644577Seric help(p); 5654549Seric break; 5664549Seric 5674549Seric case CMDNOOP: /* noop -- do nothing */ 56858151Seric message("200 OK"); 5694549Seric break; 5704549Seric 5714549Seric case CMDQUIT: /* quit -- leave mail */ 57258151Seric message("221 %s closing connection", MyHostName); 5739339Seric if (InChild) 5749339Seric ExitStat = EX_QUIT; 5754549Seric finis(); 5764549Seric 5778544Seric case CMDVERB: /* set verbose mode */ 5788544Seric Verbose = TRUE; 57958734Seric e->e_sendmode = SM_DELIVER; 58058151Seric message("200 Verbose mode"); 5818544Seric break; 5828544Seric 5839314Seric case CMDONEX: /* doing one transaction only */ 5849378Seric OneXact = TRUE; 58558151Seric message("200 Only one transaction"); 5869314Seric break; 5879314Seric 58836230Skarels # ifdef SMTPDEBUG 5899339Seric case CMDDBGQSHOW: /* show queues */ 5906907Seric printf("Send Queue="); 59155012Seric printaddr(e->e_sendqueue, TRUE); 5925003Seric break; 5937275Seric 5947275Seric case CMDDBGDEBUG: /* set debug mode */ 5957676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5967676Seric tTflag(p); 59758151Seric message("200 Debug set"); 5987275Seric break; 5997275Seric 60036230Skarels # else /* not SMTPDEBUG */ 60124945Seric 60236230Skarels case CMDDBGQSHOW: /* show queues */ 60336230Skarels case CMDDBGDEBUG: /* set debug mode */ 60436233Skarels # ifdef LOG 60558308Seric if (LogLevel > 0) 60636230Skarels syslog(LOG_NOTICE, 60758020Seric "\"%s\" command from %s (%s)", 60836230Skarels c->cmdname, RealHostName, 60958755Seric anynet_ntoa(&RealHostAddr)); 61036233Skarels # endif 61136230Skarels /* FALL THROUGH */ 61236230Skarels # endif /* SMTPDEBUG */ 61336230Skarels 6144549Seric case CMDERROR: /* unknown command */ 61558151Seric message("500 Command unrecognized"); 6164549Seric break; 6174549Seric 6184549Seric default: 61936230Skarels errno = 0; 62058151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6214549Seric break; 6224549Seric } 6234549Seric } 6244549Seric } 6254549Seric /* 6264549Seric ** SKIPWORD -- skip a fixed word. 6274549Seric ** 6284549Seric ** Parameters: 6294549Seric ** p -- place to start looking. 6304549Seric ** w -- word to skip. 6314549Seric ** 6324549Seric ** Returns: 6334549Seric ** p following w. 6344549Seric ** NULL on error. 6354549Seric ** 6364549Seric ** Side Effects: 6374549Seric ** clobbers the p data area. 6384549Seric */ 6394549Seric 6404549Seric static char * 6414549Seric skipword(p, w) 6424549Seric register char *p; 6434549Seric char *w; 6444549Seric { 6454549Seric register char *q; 6464549Seric 6474549Seric /* find beginning of word */ 64858050Seric while (isascii(*p) && isspace(*p)) 6494549Seric p++; 6504549Seric q = p; 6514549Seric 6524549Seric /* find end of word */ 65358050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6544549Seric p++; 65558050Seric while (isascii(*p) && isspace(*p)) 6564549Seric *p++ = '\0'; 6574549Seric if (*p != ':') 6584549Seric { 6594549Seric syntax: 66058151Seric message("501 Syntax error"); 6614549Seric Errors++; 6624549Seric return (NULL); 6634549Seric } 6644549Seric *p++ = '\0'; 66558050Seric while (isascii(*p) && isspace(*p)) 6664549Seric p++; 6674549Seric 6684549Seric /* see if the input word matches desired word */ 66933725Sbostic if (strcasecmp(q, w)) 6704549Seric goto syntax; 6714549Seric 6724549Seric return (p); 6734549Seric } 6744577Seric /* 67558151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 67658151Seric ** 67758151Seric ** Parameters: 67858151Seric ** a -- the address to print 67958151Seric ** last -- set if this is the last one. 68058151Seric ** 68158151Seric ** Returns: 68258151Seric ** none. 68358151Seric ** 68458151Seric ** Side Effects: 68558151Seric ** Prints the appropriate 250 codes. 68658151Seric */ 68758151Seric 68858151Seric printvrfyaddr(a, last) 68958151Seric register ADDRESS *a; 69058151Seric bool last; 69158151Seric { 69258151Seric char fmtbuf[20]; 69358151Seric 69458151Seric strcpy(fmtbuf, "250"); 69558151Seric fmtbuf[3] = last ? ' ' : '-'; 69658151Seric 69758151Seric if (strchr(a->q_paddr, '<') != NULL) 69858151Seric strcpy(&fmtbuf[4], "%s"); 69958151Seric else if (a->q_fullname == NULL) 70058151Seric strcpy(&fmtbuf[4], "<%s>"); 70158151Seric else 70258151Seric { 70358151Seric strcpy(&fmtbuf[4], "%s <%s>"); 70458151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 70558151Seric return; 70658151Seric } 70758151Seric message(fmtbuf, a->q_paddr); 70858151Seric } 70958151Seric /* 7104577Seric ** HELP -- implement the HELP command. 7114577Seric ** 7124577Seric ** Parameters: 7134577Seric ** topic -- the topic we want help for. 7144577Seric ** 7154577Seric ** Returns: 7164577Seric ** none. 7174577Seric ** 7184577Seric ** Side Effects: 7194577Seric ** outputs the help file to message output. 7204577Seric */ 7214577Seric 7224577Seric help(topic) 7234577Seric char *topic; 7244577Seric { 7254577Seric register FILE *hf; 7264577Seric int len; 7274577Seric char buf[MAXLINE]; 7284577Seric bool noinfo; 7294577Seric 7308269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7314577Seric { 7324577Seric /* no help */ 73311931Seric errno = 0; 73458151Seric message("502 HELP not implemented"); 7354577Seric return; 7364577Seric } 7374577Seric 73849669Seric if (topic == NULL || *topic == '\0') 73949669Seric topic = "smtp"; 74049669Seric else 74149669Seric makelower(topic); 74249669Seric 7434577Seric len = strlen(topic); 7444577Seric noinfo = TRUE; 7454577Seric 7464577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7474577Seric { 7484577Seric if (strncmp(buf, topic, len) == 0) 7494577Seric { 7504577Seric register char *p; 7514577Seric 75256795Seric p = strchr(buf, '\t'); 7534577Seric if (p == NULL) 7544577Seric p = buf; 7554577Seric else 7564577Seric p++; 7574577Seric fixcrlf(p, TRUE); 75858151Seric message("214-%s", p); 7594577Seric noinfo = FALSE; 7604577Seric } 7614577Seric } 7624577Seric 7634577Seric if (noinfo) 76458151Seric message("504 HELP topic unknown"); 7654577Seric else 76658151Seric message("214 End of HELP info"); 7674628Seric (void) fclose(hf); 7684577Seric } 7698544Seric /* 7709339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7719339Seric ** 7729339Seric ** Parameters: 7739339Seric ** label -- a string used in error messages 7749339Seric ** 7759339Seric ** Returns: 7769339Seric ** zero in the child 7779339Seric ** one in the parent 7789339Seric ** 7799339Seric ** Side Effects: 7809339Seric ** none. 7819339Seric */ 7828544Seric 78355012Seric runinchild(label, e) 7849339Seric char *label; 78555012Seric register ENVELOPE *e; 7869339Seric { 7879339Seric int childpid; 7889339Seric 78916158Seric if (!OneXact) 7909339Seric { 79116158Seric childpid = dofork(); 79216158Seric if (childpid < 0) 79316158Seric { 79416158Seric syserr("%s: cannot fork", label); 79516158Seric return (1); 79616158Seric } 79716158Seric if (childpid > 0) 79816158Seric { 79916158Seric auto int st; 8009339Seric 80116158Seric /* parent -- wait for child to complete */ 80216158Seric st = waitfor(childpid); 80316158Seric if (st == -1) 80416158Seric syserr("%s: lost child", label); 8059339Seric 80616158Seric /* if we exited on a QUIT command, complete the process */ 80716158Seric if (st == (EX_QUIT << 8)) 80816158Seric finis(); 8099339Seric 81016158Seric return (1); 81116158Seric } 81216158Seric else 81316158Seric { 81416158Seric /* child */ 81516158Seric InChild = TRUE; 81625050Seric QuickAbort = FALSE; 81755012Seric clearenvelope(e, FALSE); 81816158Seric } 8199339Seric } 82015256Seric 82116158Seric /* open alias database */ 82255012Seric initaliases(AliasFile, FALSE, e); 82316158Seric 82416158Seric return (0); 8259339Seric } 8269339Seric 82756795Seric # endif /* SMTP */ 828