14549Seric # include "sendmail.h" 24549Seric 35181Seric # ifndef SMTP 4*7356Seric SCCSID(@(#)srvrsmtp.c 3.21 07/05/82 (no SMTP)); 55181Seric # else SMTP 64556Seric 7*7356Seric SCCSID(@(#)srvrsmtp.c 3.21 07/05/82); 85181Seric 94549Seric /* 104549Seric ** SMTP -- run the SMTP protocol. 114549Seric ** 124549Seric ** Parameters: 134549Seric ** none. 144549Seric ** 154549Seric ** Returns: 164549Seric ** never. 174549Seric ** 184549Seric ** Side Effects: 194549Seric ** Reads commands from the input channel and processes 204549Seric ** them. 214549Seric */ 224549Seric 234549Seric struct cmd 244549Seric { 254549Seric char *cmdname; /* command name */ 264549Seric int cmdcode; /* internal code, see below */ 274549Seric }; 284549Seric 294549Seric /* values for cmdcode */ 304549Seric # define CMDERROR 0 /* bad command */ 314549Seric # define CMDMAIL 1 /* mail -- designate sender */ 324976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 334549Seric # define CMDDATA 3 /* data -- send message text */ 344549Seric # define CMDRSET 5 /* rset -- reset state */ 354549Seric # define CMDVRFY 6 /* vrfy -- verify address */ 364549Seric # define CMDHELP 7 /* help -- give usage info */ 374549Seric # define CMDNOOP 8 /* noop -- do nothing */ 384549Seric # define CMDQUIT 9 /* quit -- close connection and die */ 394577Seric # define CMDMRSQ 10 /* mrsq -- for old mtp compat only */ 404976Seric # define CMDHELO 11 /* helo -- be polite */ 417275Seric # define CMDDBGSHOWQ 12 /* _showq -- show send queue (DEBUG) */ 427275Seric # define CMDDBGDEBUG 13 /* _debug -- set debug mode */ 437275Seric # define CMDDBGVERBOSE 14 /* _verbose -- go into verbose mode */ 447282Seric # define CMDDBGKILL 15 /* _kill -- kill sendmail */ 454549Seric 464549Seric static struct cmd CmdTab[] = 474549Seric { 484549Seric "mail", CMDMAIL, 494976Seric "rcpt", CMDRCPT, 504976Seric "mrcp", CMDRCPT, /* for old MTP compatability */ 514549Seric "data", CMDDATA, 524549Seric "rset", CMDRSET, 534549Seric "vrfy", CMDVRFY, 544549Seric "help", CMDHELP, 554549Seric "noop", CMDNOOP, 564549Seric "quit", CMDQUIT, 574577Seric "mrsq", CMDMRSQ, 584976Seric "helo", CMDHELO, 595003Seric # ifdef DEBUG 607275Seric "_showq", CMDDBGSHOWQ, 617275Seric "_debug", CMDDBGDEBUG, 627275Seric "_verbose", CMDDBGVERBOSE, 637282Seric "_kill", CMDDBGKILL, 645003Seric # endif DEBUG 654549Seric NULL, CMDERROR, 664549Seric }; 674549Seric 684549Seric smtp() 694549Seric { 704549Seric char inp[MAXLINE]; 714549Seric register char *p; 724549Seric struct cmd *c; 734549Seric char *cmd; 744549Seric extern char *skipword(); 754549Seric extern bool sameword(); 764549Seric bool hasmail; /* mail command received */ 774713Seric int rcps; /* number of recipients */ 785003Seric auto ADDRESS *vrfyqueue; 797124Seric extern char Version[]; 80*7356Seric extern tick(); 814549Seric 825003Seric hasmail = FALSE; 834713Seric rcps = 0; 847286Seric (void) close(1); 857286Seric (void) dup(fileno(OutChannel)); 867124Seric message("220", "%s Sendmail version %s at your service", HostName, Version); 87*7356Seric (void) signal(SIGALRM, tick); 884549Seric for (;;) 894549Seric { 90*7356Seric /* setup for the read */ 916907Seric CurEnv->e_to = NULL; 924577Seric Errors = 0; 937275Seric (void) fflush(stdout); 94*7356Seric 95*7356Seric /* arrange a timeout */ 96*7356Seric if (setjmp(TickFrame) != 0) 974549Seric { 98*7356Seric message("421", "%s timed out", HostName); 99*7356Seric finis(); 100*7356Seric } 101*7356Seric (void) alarm(ReadTimeout); 102*7356Seric 103*7356Seric /* read the input line */ 104*7356Seric p = fgets(inp, sizeof inp, InChannel); 105*7356Seric 106*7356Seric /* clear the timeout and handle errors */ 107*7356Seric (void) alarm(0); 108*7356Seric if (p == NULL) 109*7356Seric { 1104549Seric /* end of file, just die */ 1114558Seric message("421", "%s Lost input channel", HostName); 1124549Seric finis(); 1134549Seric } 1144549Seric 1154549Seric /* clean up end of line */ 1164558Seric fixcrlf(inp, TRUE); 1174549Seric 1184713Seric /* echo command to transcript */ 1194713Seric fprintf(Xscript, "*** %s\n", inp); 1204713Seric 1214549Seric /* break off command */ 1224549Seric for (p = inp; isspace(*p); p++) 1234549Seric continue; 1244549Seric cmd = p; 1254549Seric while (*++p != '\0' && !isspace(*p)) 1264549Seric continue; 1274549Seric if (*p != '\0') 1284549Seric *p++ = '\0'; 1294549Seric 1304549Seric /* decode command */ 1314549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1324549Seric { 1334549Seric if (sameword(c->cmdname, cmd)) 1344549Seric break; 1354549Seric } 1364549Seric 1374549Seric /* process command */ 1384549Seric switch (c->cmdcode) 1394549Seric { 1404976Seric case CMDHELO: /* hello -- introduce yourself */ 1415187Seric define('s', newstr(p)); 1424997Seric message("250", "%s Hello %s, pleased to meet you", 1434997Seric HostName, p); 1444976Seric break; 1454976Seric 1464549Seric case CMDMAIL: /* mail -- designate sender */ 1474558Seric if (hasmail) 1484558Seric { 1494558Seric message("503", "Sender already specified"); 1504558Seric break; 1514558Seric } 1524549Seric p = skipword(p, "from"); 1534549Seric if (p == NULL) 1544549Seric break; 1554549Seric if (index(p, ',') != NULL) 1564549Seric { 1574549Seric message("501", "Source routing not implemented"); 1584549Seric Errors++; 1594549Seric break; 1604549Seric } 1614549Seric setsender(p); 1624577Seric if (Errors == 0) 1634549Seric { 1644549Seric message("250", "Sender ok"); 1654549Seric hasmail = TRUE; 1664549Seric } 1674549Seric break; 1684549Seric 1694976Seric case CMDRCPT: /* rcpt -- designate recipient */ 1704549Seric p = skipword(p, "to"); 1714549Seric if (p == NULL) 1724549Seric break; 1734549Seric if (index(p, ',') != NULL) 1744549Seric { 1754549Seric message("501", "Source routing not implemented"); 1764549Seric Errors++; 1774549Seric break; 1784549Seric } 1796907Seric sendto(p, 1, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 1804577Seric if (Errors == 0) 1814549Seric { 1826057Seric message("250", "%s... Recipient ok", p); 1834713Seric rcps++; 1844549Seric } 1854549Seric break; 1864549Seric 1874549Seric case CMDDATA: /* data -- text of mail */ 1884976Seric if (!hasmail) 1894549Seric { 1904976Seric message("503", "Need MAIL command"); 1914976Seric break; 1924549Seric } 1934713Seric else if (rcps <= 0) 1944549Seric { 1954976Seric message("503", "Need RCPT (recipient)"); 1964976Seric break; 1974549Seric } 1984976Seric 1994976Seric /* collect the text of the message */ 2004976Seric collect(TRUE); 2014976Seric if (Errors != 0) 2024976Seric break; 2034976Seric 2044976Seric /* if sending to multiple people, mail back errors */ 2054976Seric if (rcps != 1) 2064976Seric HoldErrs = MailBack = TRUE; 2074976Seric 2084976Seric /* send to all recipients */ 2097046Seric sendall(CurEnv, FALSE); 2104976Seric 2114976Seric /* reset strange modes */ 2124976Seric HoldErrs = FALSE; 2136907Seric CurEnv->e_to = NULL; 2144976Seric 2154976Seric /* issue success if appropriate */ 2164976Seric if (Errors == 0 || rcps != 1) 2174976Seric message("250", "Sent"); 2184549Seric break; 2194549Seric 2204549Seric case CMDRSET: /* rset -- reset state */ 2214549Seric message("250", "Reset state"); 2224549Seric finis(); 2234549Seric 2244549Seric case CMDVRFY: /* vrfy -- verify address */ 2255003Seric vrfyqueue = NULL; 2265003Seric sendto(p, 1, (ADDRESS *) NULL, &vrfyqueue); 2275003Seric while (vrfyqueue != NULL) 2285003Seric { 2295003Seric register ADDRESS *a = vrfyqueue->q_next; 2305003Seric char *code; 2315003Seric 2325003Seric while (a != NULL && bitset(QDONTSEND, a->q_flags)) 2335003Seric a = a->q_next; 2345003Seric 2355003Seric if (!bitset(QDONTSEND, vrfyqueue->q_flags)) 2365003Seric { 2375003Seric if (a != NULL) 2385003Seric code = "250-"; 2395003Seric else 2405003Seric code = "250"; 2415003Seric if (vrfyqueue->q_fullname == NULL) 2425003Seric message(code, "<%s>", vrfyqueue->q_paddr); 2435003Seric else 2445003Seric message(code, "%s <%s>", 2455003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 2465003Seric } 2475003Seric else if (a == NULL) 2485003Seric message("554", "Self destructive alias loop"); 2495003Seric vrfyqueue = a; 2505003Seric } 2514549Seric break; 2524549Seric 2534549Seric case CMDHELP: /* help -- give user info */ 2544577Seric if (*p == '\0') 2554577Seric p = "SMTP"; 2564577Seric help(p); 2574549Seric break; 2584549Seric 2594549Seric case CMDNOOP: /* noop -- do nothing */ 2604549Seric message("200", "OK"); 2614549Seric break; 2624549Seric 2634549Seric case CMDQUIT: /* quit -- leave mail */ 2644549Seric message("221", "%s closing connection", HostName); 2654549Seric finis(); 2664549Seric 2674577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 2684577Seric if (*p == 'R' || *p == 'T') 2694577Seric { 2704577Seric /* recipients first or text first */ 2714577Seric message("200", "%c ok, please continue", *p); 2724577Seric } 2734577Seric else if (*p == '?') 2744577Seric { 2754577Seric /* what do I prefer? anything, anytime */ 2764577Seric message("215", "R Recipients first is my choice"); 2774577Seric } 2784577Seric else if (*p == '\0') 2794577Seric { 2804577Seric /* no meaningful scheme */ 2814577Seric message("200", "okey dokie boobie"); 2824577Seric } 2834577Seric else 2844577Seric { 2854577Seric /* bad argument */ 2864577Seric message("504", "Scheme unknown"); 2874577Seric } 2884577Seric break; 2894577Seric 2905003Seric # ifdef DEBUG 2915003Seric case CMDDBGSHOWQ: /* show queues */ 2926907Seric printf("Send Queue="); 2936907Seric printaddr(CurEnv->e_sendqueue, TRUE); 2945003Seric break; 2957275Seric 2967275Seric case CMDDBGDEBUG: /* set debug mode */ 2977275Seric Debug = atoi(p); 2987275Seric message("200", "Debug = %d", Debug); 2997275Seric break; 3007275Seric 3017275Seric case CMDDBGVERBOSE: /* set verbose mode */ 3027275Seric Verbose = TRUE; 3037275Seric message("200", "Verbose mode"); 3047275Seric break; 3057282Seric 3067282Seric case CMDDBGKILL: /* kill the parent */ 3077282Seric if (kill(MotherPid, SIGTERM) >= 0) 3087282Seric message("200", "Mother is dead"); 3097282Seric else 3107282Seric message("500", "Can't kill Mom"); 3117282Seric break; 3125003Seric # endif DEBUG 3135003Seric 3144549Seric case CMDERROR: /* unknown command */ 3154549Seric message("500", "Command unrecognized"); 3164549Seric break; 3174549Seric 3184549Seric default: 3194549Seric syserr("smtp: unknown code %d", c->cmdcode); 3204549Seric break; 3214549Seric } 3224549Seric } 3234549Seric } 3244549Seric /* 3254549Seric ** SKIPWORD -- skip a fixed word. 3264549Seric ** 3274549Seric ** Parameters: 3284549Seric ** p -- place to start looking. 3294549Seric ** w -- word to skip. 3304549Seric ** 3314549Seric ** Returns: 3324549Seric ** p following w. 3334549Seric ** NULL on error. 3344549Seric ** 3354549Seric ** Side Effects: 3364549Seric ** clobbers the p data area. 3374549Seric */ 3384549Seric 3394549Seric static char * 3404549Seric skipword(p, w) 3414549Seric register char *p; 3424549Seric char *w; 3434549Seric { 3444549Seric register char *q; 3454549Seric extern bool sameword(); 3464549Seric 3474549Seric /* find beginning of word */ 3484549Seric while (isspace(*p)) 3494549Seric p++; 3504549Seric q = p; 3514549Seric 3524549Seric /* find end of word */ 3534549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 3544549Seric p++; 3554549Seric while (isspace(*p)) 3564549Seric *p++ = '\0'; 3574549Seric if (*p != ':') 3584549Seric { 3594549Seric syntax: 3604549Seric message("501", "Syntax error"); 3614549Seric Errors++; 3624549Seric return (NULL); 3634549Seric } 3644549Seric *p++ = '\0'; 3654549Seric while (isspace(*p)) 3664549Seric p++; 3674549Seric 3684549Seric /* see if the input word matches desired word */ 3694549Seric if (!sameword(q, w)) 3704549Seric goto syntax; 3714549Seric 3724549Seric return (p); 3734549Seric } 3744577Seric /* 3754577Seric ** HELP -- implement the HELP command. 3764577Seric ** 3774577Seric ** Parameters: 3784577Seric ** topic -- the topic we want help for. 3794577Seric ** 3804577Seric ** Returns: 3814577Seric ** none. 3824577Seric ** 3834577Seric ** Side Effects: 3844577Seric ** outputs the help file to message output. 3854577Seric */ 3864577Seric 3874577Seric help(topic) 3884577Seric char *topic; 3894577Seric { 3904577Seric register FILE *hf; 3914577Seric int len; 3924577Seric char buf[MAXLINE]; 3934577Seric bool noinfo; 3944582Seric extern char *HelpFile; 3954577Seric 3964582Seric hf = fopen(HelpFile, "r"); 3974577Seric if (hf == NULL) 3984577Seric { 3994577Seric /* no help */ 4004577Seric message("502", "HELP not implemented"); 4014577Seric return; 4024577Seric } 4034577Seric 4044577Seric len = strlen(topic); 4054577Seric makelower(topic); 4064577Seric noinfo = TRUE; 4074577Seric 4084577Seric while (fgets(buf, sizeof buf, hf) != NULL) 4094577Seric { 4104577Seric if (strncmp(buf, topic, len) == 0) 4114577Seric { 4124577Seric register char *p; 4134577Seric 4144577Seric p = index(buf, '\t'); 4154577Seric if (p == NULL) 4164577Seric p = buf; 4174577Seric else 4184577Seric p++; 4194577Seric fixcrlf(p, TRUE); 4204577Seric message("214-", p); 4214577Seric noinfo = FALSE; 4224577Seric } 4234577Seric } 4244577Seric 4254577Seric if (noinfo) 4264577Seric message("504", "HELP topic unknown"); 4274577Seric else 4284577Seric message("214", "End of HELP info"); 4294628Seric (void) fclose(hf); 4304577Seric } 4315181Seric 4325181Seric # endif SMTP 433