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