14549Seric # include "sendmail.h" 24549Seric 35181Seric # ifndef SMTP 4*7282Seric SCCSID(@(#)srvrsmtp.c 3.19 06/26/82 (no SMTP)); 55181Seric # else SMTP 64556Seric 7*7282Seric SCCSID(@(#)srvrsmtp.c 3.19 06/26/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 */ 44*7282Seric # 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, 63*7282Seric "_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[]; 804549Seric 815003Seric hasmail = FALSE; 824713Seric rcps = 0; 837275Seric close(1); 847275Seric dup(fileno(OutChannel)); 857124Seric message("220", "%s Sendmail version %s at your service", HostName, Version); 864549Seric for (;;) 874549Seric { 886907Seric CurEnv->e_to = NULL; 894577Seric Errors = 0; 907275Seric (void) fflush(stdout); 914549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 924549Seric { 934549Seric /* end of file, just die */ 944558Seric message("421", "%s Lost input channel", HostName); 954549Seric finis(); 964549Seric } 974549Seric 984549Seric /* clean up end of line */ 994558Seric fixcrlf(inp, TRUE); 1004549Seric 1014713Seric /* echo command to transcript */ 1024713Seric fprintf(Xscript, "*** %s\n", inp); 1034713Seric 1044549Seric /* break off command */ 1054549Seric for (p = inp; isspace(*p); p++) 1064549Seric continue; 1074549Seric cmd = p; 1084549Seric while (*++p != '\0' && !isspace(*p)) 1094549Seric continue; 1104549Seric if (*p != '\0') 1114549Seric *p++ = '\0'; 1124549Seric 1134549Seric /* decode command */ 1144549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1154549Seric { 1164549Seric if (sameword(c->cmdname, cmd)) 1174549Seric break; 1184549Seric } 1194549Seric 1204549Seric /* process command */ 1214549Seric switch (c->cmdcode) 1224549Seric { 1234976Seric case CMDHELO: /* hello -- introduce yourself */ 1245187Seric define('s', newstr(p)); 1254997Seric message("250", "%s Hello %s, pleased to meet you", 1264997Seric HostName, p); 1274976Seric break; 1284976Seric 1294549Seric case CMDMAIL: /* mail -- designate sender */ 1304558Seric if (hasmail) 1314558Seric { 1324558Seric message("503", "Sender already specified"); 1334558Seric break; 1344558Seric } 1354549Seric p = skipword(p, "from"); 1364549Seric if (p == NULL) 1374549Seric break; 1384549Seric if (index(p, ',') != NULL) 1394549Seric { 1404549Seric message("501", "Source routing not implemented"); 1414549Seric Errors++; 1424549Seric break; 1434549Seric } 1444549Seric setsender(p); 1454577Seric if (Errors == 0) 1464549Seric { 1474549Seric message("250", "Sender ok"); 1484549Seric hasmail = TRUE; 1494549Seric } 1504549Seric break; 1514549Seric 1524976Seric case CMDRCPT: /* rcpt -- designate recipient */ 1534549Seric p = skipword(p, "to"); 1544549Seric if (p == NULL) 1554549Seric break; 1564549Seric if (index(p, ',') != NULL) 1574549Seric { 1584549Seric message("501", "Source routing not implemented"); 1594549Seric Errors++; 1604549Seric break; 1614549Seric } 1626907Seric sendto(p, 1, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 1634577Seric if (Errors == 0) 1644549Seric { 1656057Seric message("250", "%s... Recipient ok", p); 1664713Seric rcps++; 1674549Seric } 1684549Seric break; 1694549Seric 1704549Seric case CMDDATA: /* data -- text of mail */ 1714976Seric if (!hasmail) 1724549Seric { 1734976Seric message("503", "Need MAIL command"); 1744976Seric break; 1754549Seric } 1764713Seric else if (rcps <= 0) 1774549Seric { 1784976Seric message("503", "Need RCPT (recipient)"); 1794976Seric break; 1804549Seric } 1814976Seric 1824976Seric /* collect the text of the message */ 1834976Seric collect(TRUE); 1844976Seric if (Errors != 0) 1854976Seric break; 1864976Seric 1874976Seric /* if sending to multiple people, mail back errors */ 1884976Seric if (rcps != 1) 1894976Seric HoldErrs = MailBack = TRUE; 1904976Seric 1914976Seric /* send to all recipients */ 1927046Seric sendall(CurEnv, FALSE); 1934976Seric 1944976Seric /* reset strange modes */ 1954976Seric HoldErrs = FALSE; 1966907Seric CurEnv->e_to = NULL; 1974976Seric 1984976Seric /* issue success if appropriate */ 1994976Seric if (Errors == 0 || rcps != 1) 2004976Seric message("250", "Sent"); 2014549Seric break; 2024549Seric 2034549Seric case CMDRSET: /* rset -- reset state */ 2044549Seric message("250", "Reset state"); 2054549Seric finis(); 2064549Seric 2074549Seric case CMDVRFY: /* vrfy -- verify address */ 2085003Seric vrfyqueue = NULL; 2095003Seric sendto(p, 1, (ADDRESS *) NULL, &vrfyqueue); 2105003Seric while (vrfyqueue != NULL) 2115003Seric { 2125003Seric register ADDRESS *a = vrfyqueue->q_next; 2135003Seric char *code; 2145003Seric 2155003Seric while (a != NULL && bitset(QDONTSEND, a->q_flags)) 2165003Seric a = a->q_next; 2175003Seric 2185003Seric if (!bitset(QDONTSEND, vrfyqueue->q_flags)) 2195003Seric { 2205003Seric if (a != NULL) 2215003Seric code = "250-"; 2225003Seric else 2235003Seric code = "250"; 2245003Seric if (vrfyqueue->q_fullname == NULL) 2255003Seric message(code, "<%s>", vrfyqueue->q_paddr); 2265003Seric else 2275003Seric message(code, "%s <%s>", 2285003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 2295003Seric } 2305003Seric else if (a == NULL) 2315003Seric message("554", "Self destructive alias loop"); 2325003Seric vrfyqueue = a; 2335003Seric } 2344549Seric break; 2354549Seric 2364549Seric case CMDHELP: /* help -- give user info */ 2374577Seric if (*p == '\0') 2384577Seric p = "SMTP"; 2394577Seric help(p); 2404549Seric break; 2414549Seric 2424549Seric case CMDNOOP: /* noop -- do nothing */ 2434549Seric message("200", "OK"); 2444549Seric break; 2454549Seric 2464549Seric case CMDQUIT: /* quit -- leave mail */ 2474549Seric message("221", "%s closing connection", HostName); 2484549Seric finis(); 2494549Seric 2504577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 2514577Seric if (*p == 'R' || *p == 'T') 2524577Seric { 2534577Seric /* recipients first or text first */ 2544577Seric message("200", "%c ok, please continue", *p); 2554577Seric } 2564577Seric else if (*p == '?') 2574577Seric { 2584577Seric /* what do I prefer? anything, anytime */ 2594577Seric message("215", "R Recipients first is my choice"); 2604577Seric } 2614577Seric else if (*p == '\0') 2624577Seric { 2634577Seric /* no meaningful scheme */ 2644577Seric message("200", "okey dokie boobie"); 2654577Seric } 2664577Seric else 2674577Seric { 2684577Seric /* bad argument */ 2694577Seric message("504", "Scheme unknown"); 2704577Seric } 2714577Seric break; 2724577Seric 2735003Seric # ifdef DEBUG 2745003Seric case CMDDBGSHOWQ: /* show queues */ 2756907Seric printf("Send Queue="); 2766907Seric printaddr(CurEnv->e_sendqueue, TRUE); 2775003Seric break; 2787275Seric 2797275Seric case CMDDBGDEBUG: /* set debug mode */ 2807275Seric Debug = atoi(p); 2817275Seric message("200", "Debug = %d", Debug); 2827275Seric break; 2837275Seric 2847275Seric case CMDDBGVERBOSE: /* set verbose mode */ 2857275Seric Verbose = TRUE; 2867275Seric message("200", "Verbose mode"); 2877275Seric break; 288*7282Seric 289*7282Seric case CMDDBGKILL: /* kill the parent */ 290*7282Seric if (kill(MotherPid, SIGTERM) >= 0) 291*7282Seric message("200", "Mother is dead"); 292*7282Seric else 293*7282Seric message("500", "Can't kill Mom"); 294*7282Seric break; 2955003Seric # endif DEBUG 2965003Seric 2974549Seric case CMDERROR: /* unknown command */ 2984549Seric message("500", "Command unrecognized"); 2994549Seric break; 3004549Seric 3014549Seric default: 3024549Seric syserr("smtp: unknown code %d", c->cmdcode); 3034549Seric break; 3044549Seric } 3054549Seric } 3064549Seric } 3074549Seric /* 3084549Seric ** SKIPWORD -- skip a fixed word. 3094549Seric ** 3104549Seric ** Parameters: 3114549Seric ** p -- place to start looking. 3124549Seric ** w -- word to skip. 3134549Seric ** 3144549Seric ** Returns: 3154549Seric ** p following w. 3164549Seric ** NULL on error. 3174549Seric ** 3184549Seric ** Side Effects: 3194549Seric ** clobbers the p data area. 3204549Seric */ 3214549Seric 3224549Seric static char * 3234549Seric skipword(p, w) 3244549Seric register char *p; 3254549Seric char *w; 3264549Seric { 3274549Seric register char *q; 3284549Seric extern bool sameword(); 3294549Seric 3304549Seric /* find beginning of word */ 3314549Seric while (isspace(*p)) 3324549Seric p++; 3334549Seric q = p; 3344549Seric 3354549Seric /* find end of word */ 3364549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 3374549Seric p++; 3384549Seric while (isspace(*p)) 3394549Seric *p++ = '\0'; 3404549Seric if (*p != ':') 3414549Seric { 3424549Seric syntax: 3434549Seric message("501", "Syntax error"); 3444549Seric Errors++; 3454549Seric return (NULL); 3464549Seric } 3474549Seric *p++ = '\0'; 3484549Seric while (isspace(*p)) 3494549Seric p++; 3504549Seric 3514549Seric /* see if the input word matches desired word */ 3524549Seric if (!sameword(q, w)) 3534549Seric goto syntax; 3544549Seric 3554549Seric return (p); 3564549Seric } 3574577Seric /* 3584577Seric ** HELP -- implement the HELP command. 3594577Seric ** 3604577Seric ** Parameters: 3614577Seric ** topic -- the topic we want help for. 3624577Seric ** 3634577Seric ** Returns: 3644577Seric ** none. 3654577Seric ** 3664577Seric ** Side Effects: 3674577Seric ** outputs the help file to message output. 3684577Seric */ 3694577Seric 3704577Seric help(topic) 3714577Seric char *topic; 3724577Seric { 3734577Seric register FILE *hf; 3744577Seric int len; 3754577Seric char buf[MAXLINE]; 3764577Seric bool noinfo; 3774582Seric extern char *HelpFile; 3784577Seric 3794582Seric hf = fopen(HelpFile, "r"); 3804577Seric if (hf == NULL) 3814577Seric { 3824577Seric /* no help */ 3834577Seric message("502", "HELP not implemented"); 3844577Seric return; 3854577Seric } 3864577Seric 3874577Seric len = strlen(topic); 3884577Seric makelower(topic); 3894577Seric noinfo = TRUE; 3904577Seric 3914577Seric while (fgets(buf, sizeof buf, hf) != NULL) 3924577Seric { 3934577Seric if (strncmp(buf, topic, len) == 0) 3944577Seric { 3954577Seric register char *p; 3964577Seric 3974577Seric p = index(buf, '\t'); 3984577Seric if (p == NULL) 3994577Seric p = buf; 4004577Seric else 4014577Seric p++; 4024577Seric fixcrlf(p, TRUE); 4034577Seric message("214-", p); 4044577Seric noinfo = FALSE; 4054577Seric } 4064577Seric } 4074577Seric 4084577Seric if (noinfo) 4094577Seric message("504", "HELP topic unknown"); 4104577Seric else 4114577Seric message("214", "End of HELP info"); 4124628Seric (void) fclose(hf); 4134577Seric } 4145181Seric 4155181Seric # endif SMTP 416