14549Seric # include "sendmail.h" 24549Seric 35181Seric # ifndef SMTP 4*7363Seric SCCSID(@(#)srvrsmtp.c 3.22 07/05/82 (no SMTP)); 55181Seric # else SMTP 64556Seric 7*7363Seric SCCSID(@(#)srvrsmtp.c 3.22 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[]; 807356Seric extern tick(); 814549Seric 825003Seric hasmail = FALSE; 834713Seric rcps = 0; 84*7363Seric if (OutChannel != stdout) 85*7363Seric { 86*7363Seric /* arrange for debugging output to go to remote host */ 87*7363Seric (void) close(1); 88*7363Seric (void) dup(fileno(OutChannel)); 89*7363Seric } 907124Seric message("220", "%s Sendmail version %s at your service", HostName, Version); 917356Seric (void) signal(SIGALRM, tick); 924549Seric for (;;) 934549Seric { 947356Seric /* setup for the read */ 956907Seric CurEnv->e_to = NULL; 964577Seric Errors = 0; 977275Seric (void) fflush(stdout); 987356Seric 997356Seric /* arrange a timeout */ 1007356Seric if (setjmp(TickFrame) != 0) 1014549Seric { 1027356Seric message("421", "%s timed out", HostName); 1037356Seric finis(); 1047356Seric } 1057356Seric (void) alarm(ReadTimeout); 1067356Seric 1077356Seric /* read the input line */ 1087356Seric p = fgets(inp, sizeof inp, InChannel); 1097356Seric 1107356Seric /* clear the timeout and handle errors */ 1117356Seric (void) alarm(0); 1127356Seric if (p == NULL) 1137356Seric { 1144549Seric /* end of file, just die */ 1154558Seric message("421", "%s Lost input channel", HostName); 1164549Seric finis(); 1174549Seric } 1184549Seric 1194549Seric /* clean up end of line */ 1204558Seric fixcrlf(inp, TRUE); 1214549Seric 1224713Seric /* echo command to transcript */ 1234713Seric fprintf(Xscript, "*** %s\n", inp); 1244713Seric 1254549Seric /* break off command */ 1264549Seric for (p = inp; isspace(*p); p++) 1274549Seric continue; 1284549Seric cmd = p; 1294549Seric while (*++p != '\0' && !isspace(*p)) 1304549Seric continue; 1314549Seric if (*p != '\0') 1324549Seric *p++ = '\0'; 1334549Seric 1344549Seric /* decode command */ 1354549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1364549Seric { 1374549Seric if (sameword(c->cmdname, cmd)) 1384549Seric break; 1394549Seric } 1404549Seric 1414549Seric /* process command */ 1424549Seric switch (c->cmdcode) 1434549Seric { 1444976Seric case CMDHELO: /* hello -- introduce yourself */ 1455187Seric define('s', newstr(p)); 1464997Seric message("250", "%s Hello %s, pleased to meet you", 1474997Seric HostName, p); 1484976Seric break; 1494976Seric 1504549Seric case CMDMAIL: /* mail -- designate sender */ 1514558Seric if (hasmail) 1524558Seric { 1534558Seric message("503", "Sender already specified"); 1544558Seric break; 1554558Seric } 1564549Seric p = skipword(p, "from"); 1574549Seric if (p == NULL) 1584549Seric break; 1594549Seric if (index(p, ',') != NULL) 1604549Seric { 1614549Seric message("501", "Source routing not implemented"); 1624549Seric Errors++; 1634549Seric break; 1644549Seric } 1654549Seric setsender(p); 1664577Seric if (Errors == 0) 1674549Seric { 1684549Seric message("250", "Sender ok"); 1694549Seric hasmail = TRUE; 1704549Seric } 1714549Seric break; 1724549Seric 1734976Seric case CMDRCPT: /* rcpt -- designate recipient */ 1744549Seric p = skipword(p, "to"); 1754549Seric if (p == NULL) 1764549Seric break; 1774549Seric if (index(p, ',') != NULL) 1784549Seric { 1794549Seric message("501", "Source routing not implemented"); 1804549Seric Errors++; 1814549Seric break; 1824549Seric } 1836907Seric sendto(p, 1, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 1844577Seric if (Errors == 0) 1854549Seric { 1866057Seric message("250", "%s... Recipient ok", p); 1874713Seric rcps++; 1884549Seric } 1894549Seric break; 1904549Seric 1914549Seric case CMDDATA: /* data -- text of mail */ 1924976Seric if (!hasmail) 1934549Seric { 1944976Seric message("503", "Need MAIL command"); 1954976Seric break; 1964549Seric } 1974713Seric else if (rcps <= 0) 1984549Seric { 1994976Seric message("503", "Need RCPT (recipient)"); 2004976Seric break; 2014549Seric } 2024976Seric 2034976Seric /* collect the text of the message */ 2044976Seric collect(TRUE); 2054976Seric if (Errors != 0) 2064976Seric break; 2074976Seric 2084976Seric /* if sending to multiple people, mail back errors */ 2094976Seric if (rcps != 1) 2104976Seric HoldErrs = MailBack = TRUE; 2114976Seric 2124976Seric /* send to all recipients */ 2137046Seric sendall(CurEnv, FALSE); 2144976Seric 2154976Seric /* reset strange modes */ 2164976Seric HoldErrs = FALSE; 2176907Seric CurEnv->e_to = NULL; 2184976Seric 2194976Seric /* issue success if appropriate */ 2204976Seric if (Errors == 0 || rcps != 1) 2214976Seric message("250", "Sent"); 2224549Seric break; 2234549Seric 2244549Seric case CMDRSET: /* rset -- reset state */ 2254549Seric message("250", "Reset state"); 2264549Seric finis(); 2274549Seric 2284549Seric case CMDVRFY: /* vrfy -- verify address */ 2295003Seric vrfyqueue = NULL; 2305003Seric sendto(p, 1, (ADDRESS *) NULL, &vrfyqueue); 2315003Seric while (vrfyqueue != NULL) 2325003Seric { 2335003Seric register ADDRESS *a = vrfyqueue->q_next; 2345003Seric char *code; 2355003Seric 2365003Seric while (a != NULL && bitset(QDONTSEND, a->q_flags)) 2375003Seric a = a->q_next; 2385003Seric 2395003Seric if (!bitset(QDONTSEND, vrfyqueue->q_flags)) 2405003Seric { 2415003Seric if (a != NULL) 2425003Seric code = "250-"; 2435003Seric else 2445003Seric code = "250"; 2455003Seric if (vrfyqueue->q_fullname == NULL) 2465003Seric message(code, "<%s>", vrfyqueue->q_paddr); 2475003Seric else 2485003Seric message(code, "%s <%s>", 2495003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 2505003Seric } 2515003Seric else if (a == NULL) 2525003Seric message("554", "Self destructive alias loop"); 2535003Seric vrfyqueue = a; 2545003Seric } 2554549Seric break; 2564549Seric 2574549Seric case CMDHELP: /* help -- give user info */ 2584577Seric if (*p == '\0') 2594577Seric p = "SMTP"; 2604577Seric help(p); 2614549Seric break; 2624549Seric 2634549Seric case CMDNOOP: /* noop -- do nothing */ 2644549Seric message("200", "OK"); 2654549Seric break; 2664549Seric 2674549Seric case CMDQUIT: /* quit -- leave mail */ 2684549Seric message("221", "%s closing connection", HostName); 2694549Seric finis(); 2704549Seric 2714577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 2724577Seric if (*p == 'R' || *p == 'T') 2734577Seric { 2744577Seric /* recipients first or text first */ 2754577Seric message("200", "%c ok, please continue", *p); 2764577Seric } 2774577Seric else if (*p == '?') 2784577Seric { 2794577Seric /* what do I prefer? anything, anytime */ 2804577Seric message("215", "R Recipients first is my choice"); 2814577Seric } 2824577Seric else if (*p == '\0') 2834577Seric { 2844577Seric /* no meaningful scheme */ 2854577Seric message("200", "okey dokie boobie"); 2864577Seric } 2874577Seric else 2884577Seric { 2894577Seric /* bad argument */ 2904577Seric message("504", "Scheme unknown"); 2914577Seric } 2924577Seric break; 2934577Seric 2945003Seric # ifdef DEBUG 2955003Seric case CMDDBGSHOWQ: /* show queues */ 2966907Seric printf("Send Queue="); 2976907Seric printaddr(CurEnv->e_sendqueue, TRUE); 2985003Seric break; 2997275Seric 3007275Seric case CMDDBGDEBUG: /* set debug mode */ 3017275Seric Debug = atoi(p); 3027275Seric message("200", "Debug = %d", Debug); 3037275Seric break; 3047275Seric 3057275Seric case CMDDBGVERBOSE: /* set verbose mode */ 3067275Seric Verbose = TRUE; 3077275Seric message("200", "Verbose mode"); 3087275Seric break; 3097282Seric 3107282Seric case CMDDBGKILL: /* kill the parent */ 3117282Seric if (kill(MotherPid, SIGTERM) >= 0) 3127282Seric message("200", "Mother is dead"); 3137282Seric else 3147282Seric message("500", "Can't kill Mom"); 3157282Seric break; 3165003Seric # endif DEBUG 3175003Seric 3184549Seric case CMDERROR: /* unknown command */ 3194549Seric message("500", "Command unrecognized"); 3204549Seric break; 3214549Seric 3224549Seric default: 3234549Seric syserr("smtp: unknown code %d", c->cmdcode); 3244549Seric break; 3254549Seric } 3264549Seric } 3274549Seric } 3284549Seric /* 3294549Seric ** SKIPWORD -- skip a fixed word. 3304549Seric ** 3314549Seric ** Parameters: 3324549Seric ** p -- place to start looking. 3334549Seric ** w -- word to skip. 3344549Seric ** 3354549Seric ** Returns: 3364549Seric ** p following w. 3374549Seric ** NULL on error. 3384549Seric ** 3394549Seric ** Side Effects: 3404549Seric ** clobbers the p data area. 3414549Seric */ 3424549Seric 3434549Seric static char * 3444549Seric skipword(p, w) 3454549Seric register char *p; 3464549Seric char *w; 3474549Seric { 3484549Seric register char *q; 3494549Seric extern bool sameword(); 3504549Seric 3514549Seric /* find beginning of word */ 3524549Seric while (isspace(*p)) 3534549Seric p++; 3544549Seric q = p; 3554549Seric 3564549Seric /* find end of word */ 3574549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 3584549Seric p++; 3594549Seric while (isspace(*p)) 3604549Seric *p++ = '\0'; 3614549Seric if (*p != ':') 3624549Seric { 3634549Seric syntax: 3644549Seric message("501", "Syntax error"); 3654549Seric Errors++; 3664549Seric return (NULL); 3674549Seric } 3684549Seric *p++ = '\0'; 3694549Seric while (isspace(*p)) 3704549Seric p++; 3714549Seric 3724549Seric /* see if the input word matches desired word */ 3734549Seric if (!sameword(q, w)) 3744549Seric goto syntax; 3754549Seric 3764549Seric return (p); 3774549Seric } 3784577Seric /* 3794577Seric ** HELP -- implement the HELP command. 3804577Seric ** 3814577Seric ** Parameters: 3824577Seric ** topic -- the topic we want help for. 3834577Seric ** 3844577Seric ** Returns: 3854577Seric ** none. 3864577Seric ** 3874577Seric ** Side Effects: 3884577Seric ** outputs the help file to message output. 3894577Seric */ 3904577Seric 3914577Seric help(topic) 3924577Seric char *topic; 3934577Seric { 3944577Seric register FILE *hf; 3954577Seric int len; 3964577Seric char buf[MAXLINE]; 3974577Seric bool noinfo; 3984582Seric extern char *HelpFile; 3994577Seric 4004582Seric hf = fopen(HelpFile, "r"); 4014577Seric if (hf == NULL) 4024577Seric { 4034577Seric /* no help */ 4044577Seric message("502", "HELP not implemented"); 4054577Seric return; 4064577Seric } 4074577Seric 4084577Seric len = strlen(topic); 4094577Seric makelower(topic); 4104577Seric noinfo = TRUE; 4114577Seric 4124577Seric while (fgets(buf, sizeof buf, hf) != NULL) 4134577Seric { 4144577Seric if (strncmp(buf, topic, len) == 0) 4154577Seric { 4164577Seric register char *p; 4174577Seric 4184577Seric p = index(buf, '\t'); 4194577Seric if (p == NULL) 4204577Seric p = buf; 4214577Seric else 4224577Seric p++; 4234577Seric fixcrlf(p, TRUE); 4244577Seric message("214-", p); 4254577Seric noinfo = FALSE; 4264577Seric } 4274577Seric } 4284577Seric 4294577Seric if (noinfo) 4304577Seric message("504", "HELP topic unknown"); 4314577Seric else 4324577Seric message("214", "End of HELP info"); 4334628Seric (void) fclose(hf); 4344577Seric } 4355181Seric 4365181Seric # endif SMTP 437