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*59747Seric static char sccsid[] = "@(#)srvrsmtp.c 6.52 (Berkeley) 05/05/93 (with SMTP)"; 1433731Sbostic #else 15*59747Seric static char sccsid[] = "@(#)srvrsmtp.c 6.52 (Berkeley) 05/05/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; 110*59747Seric int nrcpts; /* number of RCPT commands */ 1118544Seric char inp[MAXLINE]; 11257232Seric char cmdbuf[MAXLINE]; 1137124Seric extern char Version[]; 11411151Seric extern char *macvalue(); 11512612Seric extern ADDRESS *recipient(); 11624943Seric extern ENVELOPE BlankEnvelope; 11724943Seric extern ENVELOPE *newenvelope(); 11858755Seric extern char *anynet_ntoa(); 1194549Seric 12059066Seric if (fileno(OutChannel) != fileno(stdout)) 1217363Seric { 1227363Seric /* arrange for debugging output to go to remote host */ 12359066Seric (void) dup2(fileno(OutChannel), fileno(stdout)); 1247363Seric } 12555012Seric settime(e); 12657642Seric CurHostName = RealHostName; 12759060Seric setproctitle("srvrsmtp %s startup", CurHostName); 12858050Seric expand("\201e", inp, &inp[sizeof inp], e); 12958151Seric message("220 %s", inp); 13058330Seric protocol = NULL; 13159016Seric sendinghost = macvalue('s', e); 13258082Seric gothello = FALSE; 13358330Seric gotmail = FALSE; 1344549Seric for (;;) 1354549Seric { 13612612Seric /* arrange for backout */ 13712612Seric if (setjmp(TopFrame) > 0 && InChild) 13859058Seric { 13959058Seric QuickAbort = FALSE; 14059058Seric SuprErrs = TRUE; 14112612Seric finis(); 14259058Seric } 14312612Seric QuickAbort = FALSE; 14412612Seric HoldErrs = FALSE; 14551951Seric LogUsrErrs = FALSE; 14658092Seric e->e_flags &= ~EF_VRFYONLY; 14712612Seric 1487356Seric /* setup for the read */ 14955012Seric e->e_to = NULL; 1504577Seric Errors = 0; 1517275Seric (void) fflush(stdout); 1527356Seric 1537356Seric /* read the input line */ 15459060Seric SmtpPhase = "srvrsmtp cmd read"; 15559060Seric setproctitle("srvrsmtp %s cmd read", CurHostName); 15658109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1577356Seric 1587685Seric /* handle errors */ 1597356Seric if (p == NULL) 1607356Seric { 1614549Seric /* end of file, just die */ 16258151Seric message("421 %s Lost input channel from %s", 16325050Seric MyHostName, CurHostName); 16455464Seric #ifdef LOG 16558020Seric if (LogLevel > 1) 16655464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16755464Seric CurHostName); 16855464Seric #endif 16958069Seric if (InChild) 17058069Seric ExitStat = EX_QUIT; 1714549Seric finis(); 1724549Seric } 1734549Seric 1744549Seric /* clean up end of line */ 1754558Seric fixcrlf(inp, TRUE); 1764549Seric 1774713Seric /* echo command to transcript */ 17855012Seric if (e->e_xfp != NULL) 17955012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1804713Seric 18159060Seric if (e->e_id == NULL) 18259060Seric setproctitle("%s: %s", CurHostName, inp); 18359060Seric else 18459060Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 18559060Seric 1864549Seric /* break off command */ 18758050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1884549Seric continue; 18957232Seric cmd = cmdbuf; 19058050Seric while (*p != '\0' && 19158050Seric !(isascii(*p) && isspace(*p)) && 19258050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 19324981Seric *cmd++ = *p++; 19424981Seric *cmd = '\0'; 1954549Seric 19625691Seric /* throw away leading whitespace */ 19758050Seric while (isascii(*p) && isspace(*p)) 19825691Seric p++; 19925691Seric 2004549Seric /* decode command */ 2014549Seric for (c = CmdTab; c->cmdname != NULL; c++) 2024549Seric { 20333725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 2044549Seric break; 2054549Seric } 2064549Seric 20751954Seric /* reset errors */ 20851954Seric errno = 0; 20951954Seric 2104549Seric /* process command */ 2114549Seric switch (c->cmdcode) 2124549Seric { 2134976Seric case CMDHELO: /* hello -- introduce yourself */ 21458323Seric case CMDEHLO: /* extended hello */ 21558323Seric if (c->cmdcode == CMDEHLO) 21658323Seric { 21758323Seric protocol = "ESMTP"; 21858323Seric SmtpPhase = "EHLO"; 21958323Seric } 22058323Seric else 22158323Seric { 22258323Seric protocol = "SMTP"; 22358323Seric SmtpPhase = "HELO"; 22458323Seric } 22559016Seric sendinghost = newstr(p); 22658308Seric if (strcasecmp(p, RealHostName) != 0) 22711146Seric { 22858789Seric auth_warning(e, "Host %s claimed to be %s", 22958789Seric RealHostName, p); 23011146Seric } 23158957Seric p = macvalue('_', e); 23258957Seric if (p == NULL) 23359016Seric p = RealHostName; 23458323Seric 23558323Seric /* send ext. message -- old systems must ignore */ 23658323Seric message("250-%s Hello %s, pleased to meet you", 23758957Seric MyHostName, p); 23858323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 23958323Seric message("250-EXPN"); 24059271Seric if (MaxMessageSize > 0) 24159271Seric message("250-SIZE %ld", MaxMessageSize); 24259271Seric else 24359271Seric message("250-SIZE"); 24458323Seric message("250 HELP"); 24558082Seric gothello = TRUE; 2464976Seric break; 2474976Seric 2484549Seric case CMDMAIL: /* mail -- designate sender */ 24924943Seric SmtpPhase = "MAIL"; 25024943Seric 2519314Seric /* check for validity of this command */ 25258789Seric if (!gothello) 25358082Seric { 25458957Seric /* set sending host to our known value */ 25559016Seric if (sendinghost == NULL) 25659016Seric sendinghost = RealHostName; 25758957Seric 25858789Seric if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25958821Seric { 26058789Seric message("503 Polite people say HELO first"); 26158821Seric break; 26258821Seric } 26358789Seric else 26458821Seric { 26558789Seric auth_warning(e, 26658789Seric "Host %s didn't use HELO protocol", 26758789Seric RealHostName); 26858821Seric } 26958082Seric } 27058109Seric if (gotmail) 2714558Seric { 27258151Seric message("503 Sender already specified"); 2734558Seric break; 2744558Seric } 2759339Seric if (InChild) 2769339Seric { 27736230Skarels errno = 0; 27858151Seric syserr("503 Nested MAIL command: MAIL %s", p); 27958069Seric finis(); 2809339Seric } 2819339Seric 2829339Seric /* fork a subprocess to process this command */ 28355012Seric if (runinchild("SMTP-MAIL", e) > 0) 2849339Seric break; 28558323Seric if (protocol == NULL) 28658323Seric protocol = "SMTP"; 28758323Seric define('r', protocol, e); 28859016Seric define('s', sendinghost, e); 28955012Seric initsys(e); 290*59747Seric nrcpts = 0; 29157389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2929339Seric 2939339Seric /* child -- go do the processing */ 2944549Seric p = skipword(p, "from"); 2954549Seric if (p == NULL) 2964549Seric break; 29757977Seric if (setjmp(TopFrame) > 0) 29858147Seric { 29958147Seric /* this failed -- undo work */ 30058147Seric if (InChild) 30159058Seric { 30259058Seric QuickAbort = FALSE; 30359058Seric SuprErrs = TRUE; 30458147Seric finis(); 30559058Seric } 30657977Seric break; 30758147Seric } 30857977Seric QuickAbort = TRUE; 30958333Seric 31058333Seric /* must parse sender first */ 31158333Seric delimptr = NULL; 31258704Seric setsender(p, e, &delimptr, FALSE); 31358333Seric p = delimptr; 31458333Seric if (p != NULL && *p != '\0') 31558333Seric *p++ = '\0'; 31658333Seric 31758333Seric /* now parse ESMTP arguments */ 31858333Seric msize = 0; 31958333Seric for (; p != NULL && *p != '\0'; p++) 32058333Seric { 32158333Seric char *kp; 32258333Seric char *vp; 32358333Seric 32458333Seric /* locate the beginning of the keyword */ 32558333Seric while (isascii(*p) && isspace(*p)) 32658333Seric p++; 32758333Seric if (*p == '\0') 32858333Seric break; 32958333Seric kp = p; 33058333Seric 33158333Seric /* skip to the value portion */ 33258333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 33358333Seric p++; 33458333Seric if (*p == '=') 33558333Seric { 33658333Seric *p++ = '\0'; 33758333Seric vp = p; 33858333Seric 33958333Seric /* skip to the end of the value */ 34058333Seric while (*p != '\0' && *p != ' ' && 34158333Seric !(isascii(*p) && iscntrl(*p)) && 34258333Seric *p != '=') 34358333Seric p++; 34458333Seric } 34558333Seric 34658333Seric if (*p != '\0') 34758333Seric *p++ = '\0'; 34858333Seric 34958333Seric if (tTd(19, 1)) 35058333Seric printf("MAIL: got arg %s=%s\n", kp, 35158333Seric vp == NULL ? "<null>" : vp); 35258333Seric 35358333Seric if (strcasecmp(kp, "size") == 0) 35458333Seric { 35559093Seric if (vp == NULL) 35658333Seric { 35758333Seric usrerr("501 SIZE requires a value"); 35858333Seric /* NOTREACHED */ 35958333Seric } 36058333Seric msize = atol(vp); 36158333Seric } 36259093Seric else if (strcasecmp(kp, "body") == 0) 36359093Seric { 36459093Seric if (vp == NULL) 36559093Seric { 36659093Seric usrerr("501 BODY requires a value"); 36759093Seric /* NOTREACHED */ 36859093Seric } 36959093Seric # ifdef MIME 37059093Seric if (strcasecmp(vp, "8bitmime") == 0) 37159093Seric { 37259093Seric e->e_bodytype = "8BITMIME"; 37359709Seric SevenBit = FALSE; 37459093Seric } 37559093Seric else if (strcasecmp(vp, "7bit") == 0) 37659093Seric { 37759093Seric e->e_bodytype = "7BIT"; 37859709Seric SevenBit = TRUE; 37959093Seric } 38059093Seric else 38159093Seric { 38259093Seric usrerr("501 Unknown BODY type %s", 38359093Seric vp); 38459093Seric } 38559093Seric # endif 38659093Seric } 38758333Seric else 38858333Seric { 38958333Seric usrerr("501 %s parameter unrecognized", kp); 39058333Seric /* NOTREACHED */ 39158333Seric } 39258333Seric } 39359284Seric 39459284Seric if (MaxMessageSize > 0 && msize > MaxMessageSize) 39559284Seric { 39659284Seric usrerr("552 Message size exceeds fixed maximum message size (%ld)", 39759284Seric MaxMessageSize); 39859284Seric /* NOTREACHED */ 39959284Seric } 40058333Seric 40158333Seric if (!enoughspace(msize)) 40258333Seric { 40358333Seric message("452 Insufficient disk space; try again later"); 40458333Seric break; 40558333Seric } 40658151Seric message("250 Sender ok"); 40758147Seric gotmail = TRUE; 4084549Seric break; 4094549Seric 4104976Seric case CMDRCPT: /* rcpt -- designate recipient */ 41158850Seric if (!gotmail) 41258850Seric { 41358850Seric usrerr("503 Need MAIL before RCPT"); 41458850Seric break; 41558850Seric } 41624943Seric SmtpPhase = "RCPT"; 41712612Seric if (setjmp(TopFrame) > 0) 41814785Seric { 41955012Seric e->e_flags &= ~EF_FATALERRS; 42012612Seric break; 42114785Seric } 42212612Seric QuickAbort = TRUE; 42351951Seric LogUsrErrs = TRUE; 42458093Seric 42559699Seric if (e->e_sendmode != SM_DELIVER) 42659699Seric e->e_flags |= EF_VRFYONLY; 42758919Seric 4284549Seric p = skipword(p, "to"); 4294549Seric if (p == NULL) 4304549Seric break; 43158333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 43212612Seric if (a == NULL) 43312612Seric break; 43416886Seric a->q_flags |= QPRIMARY; 43555012Seric a = recipient(a, &e->e_sendqueue, e); 43612612Seric if (Errors != 0) 43712612Seric break; 43812612Seric 43912612Seric /* no errors during parsing, but might be a duplicate */ 44055012Seric e->e_to = p; 44112612Seric if (!bitset(QBADADDR, a->q_flags)) 442*59747Seric { 44358151Seric message("250 Recipient ok"); 444*59747Seric nrcpts++; 445*59747Seric } 44612612Seric else 4474549Seric { 44812612Seric /* punt -- should keep message in ADDRESS.... */ 44958151Seric message("550 Addressee unknown"); 4504549Seric } 45155012Seric e->e_to = NULL; 4524549Seric break; 4534549Seric 4544549Seric case CMDDATA: /* data -- text of mail */ 45524943Seric SmtpPhase = "DATA"; 45658109Seric if (!gotmail) 4574549Seric { 45858151Seric message("503 Need MAIL command"); 4594976Seric break; 4604549Seric } 46155012Seric else if (e->e_nrcpts <= 0) 4624549Seric { 46358151Seric message("503 Need RCPT (recipient)"); 4644976Seric break; 4654549Seric } 4664976Seric 46758929Seric /* check to see if we need to re-expand aliases */ 46858929Seric for (a = e->e_sendqueue; a != NULL; a = a->q_next) 46958929Seric { 47058929Seric if (bitset(QVERIFIED, a->q_flags)) 47158929Seric break; 47258929Seric } 47358929Seric 4744976Seric /* collect the text of the message */ 47524943Seric SmtpPhase = "collect"; 47658929Seric collect(TRUE, a != NULL, e); 47759730Seric e->e_flags &= ~EF_FATALERRS; 4784976Seric if (Errors != 0) 479*59747Seric goto abortmessage; 4804976Seric 4818238Seric /* 4828238Seric ** Arrange to send to everyone. 4838238Seric ** If sending to multiple people, mail back 4848238Seric ** errors rather than reporting directly. 4858238Seric ** In any case, don't mail back errors for 4868238Seric ** anything that has happened up to 4878238Seric ** now (the other end will do this). 48810197Seric ** Truncate our transcript -- the mail has gotten 48910197Seric ** to us successfully, and if we have 49010197Seric ** to mail this back, it will be easier 49110197Seric ** on the reader. 4928238Seric ** Then send to everyone. 4938238Seric ** Finally give a reply code. If an error has 4948238Seric ** already been given, don't mail a 4958238Seric ** message back. 4969339Seric ** We goose error returns by clearing error bit. 4978238Seric */ 4988238Seric 49924943Seric SmtpPhase = "delivery"; 500*59747Seric if (nrcpts != 1 && a == NULL) 5019378Seric { 5029378Seric HoldErrs = TRUE; 50358734Seric e->e_errormode = EM_MAIL; 5049378Seric } 50555012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 50658714Seric id = e->e_id; 5074976Seric 5084976Seric /* send to all recipients */ 50958919Seric sendall(e, a == NULL ? SM_DEFAULT : SM_QUEUE); 51055012Seric e->e_to = NULL; 5114976Seric 51223516Seric /* save statistics */ 51355012Seric markstats(e, (ADDRESS *) NULL); 51423516Seric 5158238Seric /* issue success if appropriate and reset */ 5168238Seric if (Errors == 0 || HoldErrs) 51758855Seric message("250 %s Message accepted for delivery", id); 518*59747Seric 519*59747Seric if (bitset(EF_FATALERRS, e->e_flags) && !HoldErrs) 52059730Seric { 52159730Seric /* avoid sending back an extra message */ 52259730Seric e->e_flags &= ~EF_FATALERRS; 523*59747Seric e->e_flags |= EF_CLRQUEUE; 52459730Seric } 5258238Seric else 52658919Seric { 527*59747Seric /* from now on, we have to operate silently */ 528*59747Seric HoldErrs = TRUE; 529*59747Seric e->e_errormode = EM_MAIL; 530*59747Seric 53159730Seric /* if we just queued, poke it */ 53259730Seric if (a != NULL && e->e_sendmode != SM_QUEUE) 53359730Seric { 53459730Seric unlockqueue(e); 53559730Seric dowork(id, TRUE, TRUE, e); 53659730Seric e->e_id = NULL; 53759730Seric } 53858919Seric } 53958883Seric 540*59747Seric abortmessage: 5419339Seric /* if in a child, pop back to our parent */ 5429339Seric if (InChild) 5439339Seric finis(); 54424943Seric 54524943Seric /* clean up a bit */ 54658109Seric gotmail = FALSE; 54755012Seric dropenvelope(e); 54858179Seric CurEnv = e = newenvelope(e, CurEnv); 54955012Seric e->e_flags = BlankEnvelope.e_flags; 5504549Seric break; 5514549Seric 5524549Seric case CMDRSET: /* rset -- reset state */ 55358151Seric message("250 Reset state"); 5549339Seric if (InChild) 5559339Seric finis(); 55658109Seric 55758109Seric /* clean up a bit */ 55858109Seric gotmail = FALSE; 55958109Seric dropenvelope(e); 56058179Seric CurEnv = e = newenvelope(e, CurEnv); 5619339Seric break; 5624549Seric 5634549Seric case CMDVRFY: /* vrfy -- verify address */ 56458092Seric case CMDEXPN: /* expn -- expand address */ 56558092Seric vrfy = c->cmdcode == CMDVRFY; 56658092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 56758092Seric PrivacyFlags)) 56858082Seric { 56958412Seric if (vrfy) 57058412Seric message("252 Who's to say?"); 57158412Seric else 57258412Seric message("502 That's none of your business"); 57358082Seric break; 57458082Seric } 57558082Seric else if (!gothello && 57658092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 57758092Seric PrivacyFlags)) 57858082Seric { 57958151Seric message("503 I demand that you introduce yourself first"); 58058082Seric break; 58158082Seric } 58258092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5839339Seric break; 58455173Seric #ifdef LOG 58558020Seric if (LogLevel > 5) 58655173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 58755173Seric #endif 5885003Seric vrfyqueue = NULL; 5897762Seric QuickAbort = TRUE; 59058092Seric if (vrfy) 59158092Seric e->e_flags |= EF_VRFYONLY; 59258082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5937762Seric if (Errors != 0) 5949339Seric { 5959339Seric if (InChild) 5969339Seric finis(); 5977762Seric break; 5989339Seric } 5995003Seric while (vrfyqueue != NULL) 6005003Seric { 6015003Seric register ADDRESS *a = vrfyqueue->q_next; 6025003Seric char *code; 6035003Seric 6047685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 6055003Seric a = a->q_next; 6065003Seric 6077685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 60858151Seric printvrfyaddr(vrfyqueue, a == NULL); 6095003Seric else if (a == NULL) 61058151Seric message("554 Self destructive alias loop"); 6115003Seric vrfyqueue = a; 6125003Seric } 6139339Seric if (InChild) 6149339Seric finis(); 6154549Seric break; 6164549Seric 6174549Seric case CMDHELP: /* help -- give user info */ 6184577Seric help(p); 6194549Seric break; 6204549Seric 6214549Seric case CMDNOOP: /* noop -- do nothing */ 62258151Seric message("200 OK"); 6234549Seric break; 6244549Seric 6254549Seric case CMDQUIT: /* quit -- leave mail */ 62658151Seric message("221 %s closing connection", MyHostName); 6279339Seric if (InChild) 6289339Seric ExitStat = EX_QUIT; 6294549Seric finis(); 6304549Seric 6318544Seric case CMDVERB: /* set verbose mode */ 6328544Seric Verbose = TRUE; 63358734Seric e->e_sendmode = SM_DELIVER; 63458151Seric message("200 Verbose mode"); 6358544Seric break; 6368544Seric 6379314Seric case CMDONEX: /* doing one transaction only */ 6389378Seric OneXact = TRUE; 63958151Seric message("200 Only one transaction"); 6409314Seric break; 6419314Seric 64236230Skarels # ifdef SMTPDEBUG 6439339Seric case CMDDBGQSHOW: /* show queues */ 6446907Seric printf("Send Queue="); 64555012Seric printaddr(e->e_sendqueue, TRUE); 6465003Seric break; 6477275Seric 6487275Seric case CMDDBGDEBUG: /* set debug mode */ 6497676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 6507676Seric tTflag(p); 65158151Seric message("200 Debug set"); 6527275Seric break; 6537275Seric 65436230Skarels # else /* not SMTPDEBUG */ 65524945Seric 65636230Skarels case CMDDBGQSHOW: /* show queues */ 65736230Skarels case CMDDBGDEBUG: /* set debug mode */ 65836233Skarels # ifdef LOG 65958308Seric if (LogLevel > 0) 66036230Skarels syslog(LOG_NOTICE, 66158020Seric "\"%s\" command from %s (%s)", 66236230Skarels c->cmdname, RealHostName, 66358755Seric anynet_ntoa(&RealHostAddr)); 66436233Skarels # endif 66536230Skarels /* FALL THROUGH */ 66636230Skarels # endif /* SMTPDEBUG */ 66736230Skarels 6684549Seric case CMDERROR: /* unknown command */ 66958151Seric message("500 Command unrecognized"); 6704549Seric break; 6714549Seric 6724549Seric default: 67336230Skarels errno = 0; 67458151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6754549Seric break; 6764549Seric } 6774549Seric } 6784549Seric } 6794549Seric /* 6804549Seric ** SKIPWORD -- skip a fixed word. 6814549Seric ** 6824549Seric ** Parameters: 6834549Seric ** p -- place to start looking. 6844549Seric ** w -- word to skip. 6854549Seric ** 6864549Seric ** Returns: 6874549Seric ** p following w. 6884549Seric ** NULL on error. 6894549Seric ** 6904549Seric ** Side Effects: 6914549Seric ** clobbers the p data area. 6924549Seric */ 6934549Seric 6944549Seric static char * 6954549Seric skipword(p, w) 6964549Seric register char *p; 6974549Seric char *w; 6984549Seric { 6994549Seric register char *q; 7004549Seric 7014549Seric /* find beginning of word */ 70258050Seric while (isascii(*p) && isspace(*p)) 7034549Seric p++; 7044549Seric q = p; 7054549Seric 7064549Seric /* find end of word */ 70758050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 7084549Seric p++; 70958050Seric while (isascii(*p) && isspace(*p)) 7104549Seric *p++ = '\0'; 7114549Seric if (*p != ':') 7124549Seric { 7134549Seric syntax: 71458151Seric message("501 Syntax error"); 7154549Seric Errors++; 7164549Seric return (NULL); 7174549Seric } 7184549Seric *p++ = '\0'; 71958050Seric while (isascii(*p) && isspace(*p)) 7204549Seric p++; 7214549Seric 7224549Seric /* see if the input word matches desired word */ 72333725Sbostic if (strcasecmp(q, w)) 7244549Seric goto syntax; 7254549Seric 7264549Seric return (p); 7274549Seric } 7284577Seric /* 72958151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 73058151Seric ** 73158151Seric ** Parameters: 73258151Seric ** a -- the address to print 73358151Seric ** last -- set if this is the last one. 73458151Seric ** 73558151Seric ** Returns: 73658151Seric ** none. 73758151Seric ** 73858151Seric ** Side Effects: 73958151Seric ** Prints the appropriate 250 codes. 74058151Seric */ 74158151Seric 74258151Seric printvrfyaddr(a, last) 74358151Seric register ADDRESS *a; 74458151Seric bool last; 74558151Seric { 74658151Seric char fmtbuf[20]; 74758151Seric 74858151Seric strcpy(fmtbuf, "250"); 74958151Seric fmtbuf[3] = last ? ' ' : '-'; 75058151Seric 75159746Seric if (a->q_fullname == NULL) 75259746Seric { 75359746Seric if (strchr(a->q_user, '@') == NULL) 75459746Seric strcpy(&fmtbuf[4], "<%s@%s>"); 75559746Seric else 75659746Seric strcpy(&fmtbuf[4], "<%s>"); 75759746Seric message(fmtbuf, a->q_user, MyHostName); 75859746Seric } 75958151Seric else 76058151Seric { 76159746Seric if (strchr(a->q_user, '@') == NULL) 76259746Seric strcpy(&fmtbuf[4], "%s <%s@%s>"); 76359746Seric else 76459746Seric strcpy(&fmtbuf[4], "%s <%s>"); 76559746Seric message(fmtbuf, a->q_fullname, a->q_user, MyHostName); 76658151Seric } 76758151Seric } 76858151Seric /* 7694577Seric ** HELP -- implement the HELP command. 7704577Seric ** 7714577Seric ** Parameters: 7724577Seric ** topic -- the topic we want help for. 7734577Seric ** 7744577Seric ** Returns: 7754577Seric ** none. 7764577Seric ** 7774577Seric ** Side Effects: 7784577Seric ** outputs the help file to message output. 7794577Seric */ 7804577Seric 7814577Seric help(topic) 7824577Seric char *topic; 7834577Seric { 7844577Seric register FILE *hf; 7854577Seric int len; 7864577Seric char buf[MAXLINE]; 7874577Seric bool noinfo; 7884577Seric 7898269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7904577Seric { 7914577Seric /* no help */ 79211931Seric errno = 0; 79358151Seric message("502 HELP not implemented"); 7944577Seric return; 7954577Seric } 7964577Seric 79749669Seric if (topic == NULL || *topic == '\0') 79849669Seric topic = "smtp"; 79949669Seric else 80049669Seric makelower(topic); 80149669Seric 8024577Seric len = strlen(topic); 8034577Seric noinfo = TRUE; 8044577Seric 8054577Seric while (fgets(buf, sizeof buf, hf) != NULL) 8064577Seric { 8074577Seric if (strncmp(buf, topic, len) == 0) 8084577Seric { 8094577Seric register char *p; 8104577Seric 81156795Seric p = strchr(buf, '\t'); 8124577Seric if (p == NULL) 8134577Seric p = buf; 8144577Seric else 8154577Seric p++; 8164577Seric fixcrlf(p, TRUE); 81758151Seric message("214-%s", p); 8184577Seric noinfo = FALSE; 8194577Seric } 8204577Seric } 8214577Seric 8224577Seric if (noinfo) 82358151Seric message("504 HELP topic unknown"); 8244577Seric else 82558151Seric message("214 End of HELP info"); 8264628Seric (void) fclose(hf); 8274577Seric } 8288544Seric /* 8299339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 8309339Seric ** 8319339Seric ** Parameters: 8329339Seric ** label -- a string used in error messages 8339339Seric ** 8349339Seric ** Returns: 8359339Seric ** zero in the child 8369339Seric ** one in the parent 8379339Seric ** 8389339Seric ** Side Effects: 8399339Seric ** none. 8409339Seric */ 8418544Seric 84255012Seric runinchild(label, e) 8439339Seric char *label; 84455012Seric register ENVELOPE *e; 8459339Seric { 8469339Seric int childpid; 8479339Seric 84816158Seric if (!OneXact) 8499339Seric { 85016158Seric childpid = dofork(); 85116158Seric if (childpid < 0) 85216158Seric { 85316158Seric syserr("%s: cannot fork", label); 85416158Seric return (1); 85516158Seric } 85616158Seric if (childpid > 0) 85716158Seric { 85816158Seric auto int st; 8599339Seric 86016158Seric /* parent -- wait for child to complete */ 86159060Seric setproctitle("srvrsmtp %s child wait", CurHostName); 86216158Seric st = waitfor(childpid); 86316158Seric if (st == -1) 86416158Seric syserr("%s: lost child", label); 8659339Seric 86616158Seric /* if we exited on a QUIT command, complete the process */ 86716158Seric if (st == (EX_QUIT << 8)) 86816158Seric finis(); 8699339Seric 87016158Seric return (1); 87116158Seric } 87216158Seric else 87316158Seric { 87416158Seric /* child */ 87516158Seric InChild = TRUE; 87625050Seric QuickAbort = FALSE; 87755012Seric clearenvelope(e, FALSE); 87816158Seric } 8799339Seric } 88015256Seric 88116158Seric /* open alias database */ 88259672Seric initaliases(FALSE, e); 88316158Seric 88416158Seric return (0); 8859339Seric } 8869339Seric 88756795Seric # endif /* SMTP */ 888