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