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