1: /*
2: ** Sendmail
3: ** Copyright (c) 1983 Eric P. Allman
4: ** Berkeley, California
5: **
6: ** Copyright (c) 1983 Regents of the University of California.
7: ** All rights reserved. The Berkeley software License Agreement
8: ** specifies the terms and conditions for redistribution.
9: */
10:
11:
12: # include <ctype.h>
13: # include <sysexits.h>
14: # include <errno.h>
15: # include "sendmail.h"
16:
17: # ifndef SMTP
18: # ifndef lint
19: static char SccsId[] = "@(#)usersmtp.c 5.7 (Berkeley) 4/2/86 (no SMTP)";
20: # endif not lint
21: # else SMTP
22:
23: # ifndef lint
24: static char SccsId[] = "@(#)usersmtp.c 5.7 (Berkeley) 4/2/86";
25: # endif not lint
26:
27:
28:
29: /*
30: ** USERSMTP -- run SMTP protocol from the user end.
31: **
32: ** This protocol is described in RFC821.
33: */
34:
35: #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
36: #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
37: #define SMTPCLOSING 421 /* "Service Shutting Down" */
38:
39: char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
40: char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
41: char SmtpError[MAXLINE] = ""; /* save failure error messages */
42: FILE *SmtpOut; /* output file */
43: FILE *SmtpIn; /* input file */
44: int SmtpPid; /* pid of mailer */
45:
46: /* following represents the state of the SMTP connection */
47: int SmtpState; /* connection state, see below */
48:
49: #define SMTP_CLOSED 0 /* connection is closed */
50: #define SMTP_OPEN 1 /* connection is open for business */
51: #define SMTP_SSD 2 /* service shutting down */
52: /*
53: ** SMTPINIT -- initialize SMTP.
54: **
55: ** Opens the connection and sends the initial protocol.
56: **
57: ** Parameters:
58: ** m -- mailer to create connection to.
59: ** pvp -- pointer to parameter vector to pass to
60: ** the mailer.
61: **
62: ** Returns:
63: ** appropriate exit status -- EX_OK on success.
64: ** If not EX_OK, it should close the connection.
65: **
66: ** Side Effects:
67: ** creates connection and sends initial protocol.
68: */
69:
70: jmp_buf CtxGreeting;
71:
72: smtpinit(m, pvp)
73: struct mailer *m;
74: char **pvp;
75: {
76: register int r;
77: EVENT *gte;
78: char buf[MAXNAME];
79: extern greettimeout();
80:
81: /*
82: ** Open the connection to the mailer.
83: */
84:
85: #ifdef DEBUG
86: if (SmtpState == SMTP_OPEN)
87: syserr("smtpinit: already open");
88: #endif DEBUG
89:
90: SmtpIn = SmtpOut = NULL;
91: SmtpState = SMTP_CLOSED;
92: SmtpError[0] = '\0';
93: SmtpPhase = "user open";
94: SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
95: if (SmtpPid < 0)
96: {
97: # ifdef DEBUG
98: if (tTd(18, 1))
99: printf("smtpinit: cannot open %s: stat %d errno %d\n",
100: pvp[0], ExitStat, errno);
101: # endif DEBUG
102: if (CurEnv->e_xfp != NULL)
103: {
104: register char *p;
105: extern char *errstring();
106: extern char *statstring();
107:
108: if (errno == 0)
109: {
110: p = statstring(ExitStat);
111: fprintf(CurEnv->e_xfp,
112: "%.3s %s.%s... %s\n",
113: p, pvp[1], m->m_name, p);
114: }
115: else
116: {
117: fprintf(CurEnv->e_xfp,
118: "421 %s.%s... Deferred: %s\n",
119: pvp[1], m->m_name, errstring(errno));
120: }
121: }
122: return (ExitStat);
123: }
124: SmtpState = SMTP_OPEN;
125:
126: /*
127: ** Get the greeting message.
128: ** This should appear spontaneously. Give it five minutes to
129: ** happen.
130: */
131:
132: if (setjmp(CtxGreeting) != 0)
133: goto tempfail;
134: gte = setevent((time_t) 300, greettimeout, 0);
135: SmtpPhase = "greeting wait";
136: r = reply(m);
137: clrevent(gte);
138: if (r < 0 || REPLYTYPE(r) != 2)
139: goto tempfail;
140:
141: /*
142: ** Send the HELO command.
143: ** My mother taught me to always introduce myself.
144: */
145:
146: smtpmessage("HELO %s", m, MyHostName);
147: SmtpPhase = "HELO wait";
148: r = reply(m);
149: if (r < 0)
150: goto tempfail;
151: else if (REPLYTYPE(r) == 5)
152: goto unavailable;
153: else if (REPLYTYPE(r) != 2)
154: goto tempfail;
155:
156: /*
157: ** If this is expected to be another sendmail, send some internal
158: ** commands.
159: */
160:
161: if (bitnset(M_INTERNAL, m->m_flags))
162: {
163: /* tell it to be verbose */
164: smtpmessage("VERB", m);
165: r = reply(m);
166: if (r < 0)
167: goto tempfail;
168:
169: /* tell it we will be sending one transaction only */
170: smtpmessage("ONEX", m);
171: r = reply(m);
172: if (r < 0)
173: goto tempfail;
174: }
175:
176: /*
177: ** Send the MAIL command.
178: ** Designates the sender.
179: */
180:
181: expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
182: if (CurEnv->e_from.q_mailer == LocalMailer ||
183: !bitnset(M_FROMPATH, m->m_flags))
184: {
185: smtpmessage("MAIL From:<%s>", m, buf);
186: }
187: else
188: {
189: smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName,
190: buf[0] == '@' ? ',' : ':', buf);
191: }
192: SmtpPhase = "MAIL wait";
193: r = reply(m);
194: if (r < 0 || REPLYTYPE(r) == 4)
195: goto tempfail;
196: else if (r == 250)
197: return (EX_OK);
198: else if (r == 552)
199: goto unavailable;
200:
201: /* protocol error -- close up */
202: smtpquit(m);
203: return (EX_PROTOCOL);
204:
205: /* signal a temporary failure */
206: tempfail:
207: smtpquit(m);
208: return (EX_TEMPFAIL);
209:
210: /* signal service unavailable */
211: unavailable:
212: smtpquit(m);
213: return (EX_UNAVAILABLE);
214: }
215:
216:
217: static
218: greettimeout()
219: {
220: /* timeout reading the greeting message */
221: longjmp(CtxGreeting, 1);
222: }
223: /*
224: ** SMTPRCPT -- designate recipient.
225: **
226: ** Parameters:
227: ** to -- address of recipient.
228: ** m -- the mailer we are sending to.
229: **
230: ** Returns:
231: ** exit status corresponding to recipient status.
232: **
233: ** Side Effects:
234: ** Sends the mail via SMTP.
235: */
236:
237: smtprcpt(to, m)
238: ADDRESS *to;
239: register MAILER *m;
240: {
241: register int r;
242: extern char *remotename();
243:
244: smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));
245:
246: SmtpPhase = "RCPT wait";
247: r = reply(m);
248: if (r < 0 || REPLYTYPE(r) == 4)
249: return (EX_TEMPFAIL);
250: else if (REPLYTYPE(r) == 2)
251: return (EX_OK);
252: else if (r == 550 || r == 551 || r == 553)
253: return (EX_NOUSER);
254: else if (r == 552 || r == 554)
255: return (EX_UNAVAILABLE);
256: return (EX_PROTOCOL);
257: }
258: /*
259: ** SMTPDATA -- send the data and clean up the transaction.
260: **
261: ** Parameters:
262: ** m -- mailer being sent to.
263: ** e -- the envelope for this message.
264: **
265: ** Returns:
266: ** exit status corresponding to DATA command.
267: **
268: ** Side Effects:
269: ** none.
270: */
271:
272: smtpdata(m, e)
273: struct mailer *m;
274: register ENVELOPE *e;
275: {
276: register int r;
277:
278: /*
279: ** Send the data.
280: ** First send the command and check that it is ok.
281: ** Then send the data.
282: ** Follow it up with a dot to terminate.
283: ** Finally get the results of the transaction.
284: */
285:
286: /* send the command and check ok to proceed */
287: smtpmessage("DATA", m);
288: SmtpPhase = "DATA wait";
289: r = reply(m);
290: if (r < 0 || REPLYTYPE(r) == 4)
291: return (EX_TEMPFAIL);
292: else if (r == 554)
293: return (EX_UNAVAILABLE);
294: else if (r != 354)
295: return (EX_PROTOCOL);
296:
297: /* now output the actual message */
298: (*e->e_puthdr)(SmtpOut, m, CurEnv);
299: putline("\n", SmtpOut, m);
300: (*e->e_putbody)(SmtpOut, m, CurEnv);
301:
302: /* terminate the message */
303: fprintf(SmtpOut, ".%s", m->m_eol);
304: if (Verbose && !HoldErrs)
305: nmessage(Arpa_Info, ">>> .");
306:
307: /* check for the results of the transaction */
308: SmtpPhase = "result wait";
309: r = reply(m);
310: if (r < 0 || REPLYTYPE(r) == 4)
311: return (EX_TEMPFAIL);
312: else if (r == 250)
313: return (EX_OK);
314: else if (r == 552 || r == 554)
315: return (EX_UNAVAILABLE);
316: return (EX_PROTOCOL);
317: }
318: /*
319: ** SMTPQUIT -- close the SMTP connection.
320: **
321: ** Parameters:
322: ** m -- a pointer to the mailer.
323: **
324: ** Returns:
325: ** none.
326: **
327: ** Side Effects:
328: ** sends the final protocol and closes the connection.
329: */
330:
331: smtpquit(m)
332: register MAILER *m;
333: {
334: int i;
335:
336: /* if the connection is already closed, don't bother */
337: if (SmtpIn == NULL)
338: return;
339:
340: /* send the quit message if not a forced quit */
341: if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD)
342: {
343: smtpmessage("QUIT", m);
344: (void) reply(m);
345: if (SmtpState == SMTP_CLOSED)
346: return;
347: }
348:
349: /* now actually close the connection */
350: (void) fclose(SmtpIn);
351: (void) fclose(SmtpOut);
352: SmtpIn = SmtpOut = NULL;
353: SmtpState = SMTP_CLOSED;
354:
355: /* and pick up the zombie */
356: i = endmailer(SmtpPid, m->m_argv[0]);
357: if (i != EX_OK)
358: syserr("smtpquit %s: stat %d", m->m_argv[0], i);
359: }
360: /*
361: ** REPLY -- read arpanet reply
362: **
363: ** Parameters:
364: ** m -- the mailer we are reading the reply from.
365: **
366: ** Returns:
367: ** reply code it reads.
368: **
369: ** Side Effects:
370: ** flushes the mail file.
371: */
372:
373: reply(m)
374: MAILER *m;
375: {
376: (void) fflush(SmtpOut);
377:
378: if (tTd(18, 1))
379: printf("reply\n");
380:
381: /*
382: ** Read the input line, being careful not to hang.
383: */
384:
385: for (;;)
386: {
387: register int r;
388: register char *p;
389:
390: /* actually do the read */
391: if (CurEnv->e_xfp != NULL)
392: (void) fflush(CurEnv->e_xfp); /* for debugging */
393:
394: /* if we are in the process of closing just give the code */
395: if (SmtpState == SMTP_CLOSED)
396: return (SMTPCLOSING);
397:
398: /* get the line from the other side */
399: p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn);
400: if (p == NULL)
401: {
402: extern char MsgBuf[]; /* err.c */
403: extern char Arpa_TSyserr[]; /* conf.c */
404:
405: /* if the remote end closed early, fake an error */
406: if (errno == 0)
407: # ifdef ECONNRESET
408: errno = ECONNRESET;
409: # else ECONNRESET
410: errno = EPIPE;
411: # endif ECONNRESET
412:
413: message(Arpa_TSyserr, "reply: read error");
414: # ifdef DEBUG
415: /* if debugging, pause so we can see state */
416: if (tTd(18, 100))
417: pause();
418: # endif DEBUG
419: # ifdef LOG
420: syslog(LOG_ERR, "%s", &MsgBuf[4]);
421: # endif LOG
422: SmtpState = SMTP_CLOSED;
423: smtpquit(m);
424: return (-1);
425: }
426: fixcrlf(SmtpReplyBuffer, TRUE);
427:
428: if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)
429: {
430: /* serious error -- log the previous command */
431: if (SmtpMsgBuffer[0] != '\0')
432: fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer);
433: SmtpMsgBuffer[0] = '\0';
434:
435: /* now log the message as from the other side */
436: fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer);
437: }
438:
439: /* display the input for verbose mode */
440: if (Verbose && !HoldErrs)
441: nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
442:
443: /* if continuation is required, we can go on */
444: if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
445: continue;
446:
447: /* decode the reply code */
448: r = atoi(SmtpReplyBuffer);
449:
450: /* extra semantics: 0xx codes are "informational" */
451: if (r < 100)
452: continue;
453:
454: /* reply code 421 is "Service Shutting Down" */
455: if (r == SMTPCLOSING && SmtpState != SMTP_SSD)
456: {
457: /* send the quit protocol */
458: SmtpState = SMTP_SSD;
459: smtpquit(m);
460: }
461:
462: /* save temporary failure messages for posterity */
463: if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
464: (void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
465:
466: return (r);
467: }
468: }
469: /*
470: ** SMTPMESSAGE -- send message to server
471: **
472: ** Parameters:
473: ** f -- format
474: ** m -- the mailer to control formatting.
475: ** a, b, c -- parameters
476: **
477: ** Returns:
478: ** none.
479: **
480: ** Side Effects:
481: ** writes message to SmtpOut.
482: */
483:
484: /*VARARGS1*/
485: smtpmessage(f, m, a, b, c)
486: char *f;
487: MAILER *m;
488: {
489: (void) sprintf(SmtpMsgBuffer, f, a, b, c);
490: if (tTd(18, 1) || (Verbose && !HoldErrs))
491: nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
492: if (SmtpOut != NULL)
493: fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol);
494: }
495:
496: # endif SMTP