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