|
|
1.1 root 1: /*
2: * Do the necessary commands for a smtp transfer. Start by waiting for the
3: * connection to open, then send HELO, MAIL, RCPT, and DATA. Check the
4: * reply codes and give up if needed.
5: *
6: * This code modified from the MIT UNIX TCP implementation:
7: * Copyright 1984 Massachusetts Institute of Technology
8: *
9: * Permission to use, copy, modify, and distribute this file
10: * for any purpose and without fee is hereby granted, provided
11: * that this copyright and permission notice appear on all copies
12: * and supporting documentation, the name of M.I.T. not be used
13: * in advertising or publicity pertaining to distribution of the
14: * program without specific prior permission, and notice be given
15: * in supporting documentation that copying and distribution is
16: * by permission of M.I.T. M.I.T. makes no representations about
17: * the suitability of this software for any purpose. It is provided
18: * "as is" without express or implied warranty.
19: */
20:
21: #include <stdio.h>
22: #include <signal.h>
23: #include <sysexits.h>
24: #include "mail.h"
25: #include "smtp.h"
26: #include "string.h"
27:
28: #define TRUE 1
29: #define FALSE 0
30: #define MINUTES * 60
31: #define HOURS * 60 MINUTES
32: #define DAYS * 24 HOURS
33:
34: char *strcat(), *strcpy();
35:
36: SIGRETURN ignore_signal();
37: SIGRETURN death();
38: char *timemsg;
39: int timelim;
40: int timeerror;
41: long nbytes;
42: extern int debug;
43: FILE *fi;
44: FILE *fo;
45:
46: converse(unixformat, from, rcpts, domain, sfi, sfo, mlfd)
47: char *from; /* from address */
48: namelist *rcpts; /* to addresses */
49: char *domain;
50: FILE *sfi; /* smtp input */
51: FILE *sfo; /* smtp output */
52: FILE *mlfd; /* mail file descriptor */
53: {
54: extern char *helohost;
55: char buf[MAXSTR];
56: namelist *np;
57: extern int kludgepause;
58:
59: fi = sfi; fo = sfo;
60:
61: (void) signal(SIGALRM, death);
62:
63: setalarm(5 MINUTES, "initial handshake", EX_TEMPFAIL);
64: expect(220, sfi, sfo, EX_PROTOCOL); /* expect a service ready msg */
65:
66: /*
67: * This pause is needed when an smtp call gets redialed
68: * (the research version of the Datakit splice.) Because of
69: * a race condition inherent in both features, -inet- must
70: * not be too eager to send HELO until the connection is set up
71: * completely. Unfortunately, the other guy's 220 response
72: * (above) can arrive before the redialed connection
73: * is completely processed locally. Hence, the brief delay.
74: * We can't fix this without changing (read ``fixing'') Datakit
75: * everywhere. This kludge is slightly easier.
76: */
77: if (kludgepause)
78: sleep(kludgepause);
79:
80: sprintf(buf, "HELO %s\n", helohost);
81: csend(buf);
82: expect(250, sfi, sfo, EX_PROTOCOL); /* expect an OK */
83:
84: strcpy(buf, "MAIL FROM:<");
85: strcat(buf, from);
86: strcat(buf, ">\n");
87: csend(buf);
88: setalarm(10 MINUTES, "response to MAIL FROM/RCPT TO", EX_TEMPFAIL);
89: expect(250, sfi, sfo, EX_PROTOCOL); /* expect OK */
90:
91: for (np=rcpts; np!=NULL; np=np->next) {
92: strcpy(buf, "RCPT TO:<");
93: strcat(buf, np->name);
94: strcat(buf, ">\n");
95: csend(buf);
96: expect(250, sfi, sfo, EX_NOUSER); /* expect OK */
97: }
98: setalarm(10 MINUTES, "response to DATA", EX_TEMPFAIL);
99: csend("DATA\n");
100: expect(354, sfi, sfo, EX_PROTOCOL);
101: setalarm(10 MINUTES, "sending mail data", EX_TEMPFAIL);
102: do_data(unixformat, mlfd, sfo, from, rcpts, domain);
103: setalarm(1 HOURS, "expecting delivery ack", EX_TEMPFAIL);
104: expect(250, sfi, sfo, EX_PROTOCOL);
105:
106: setalarm(5 MINUTES, "response to QUIT", 0);
107: csend("QUIT\n");
108: expect(221, sfi, sfo, 0); /* who cares? (Some do)*/
109: exit(0);
110: }
111:
112: /*
113: * escape '.'s at the beginning of lines and turn newlines into
114: * /r/n's.
115: */
116: static char smlastchar;
117:
118: smfputs(str, fp)
119: char *str;
120: FILE *fp;
121: {
122: register char *cp;
123:
124: /*
125: * escape a leading dot
126: */
127: if(smlastchar=='\n' && str[0]=='.') {
128: nbytes++;
129: fputc('.', fp);
130: }
131:
132: /*
133: * output the line
134: */
135: for(cp=str; *cp; cp++){
136: if(*cp=='\n') {
137: nbytes++;
138: putc('\r', fp);
139: }
140: nbytes++;
141: putc(*cp, fp);
142: }
143: if(cp!=str)
144: smlastchar = *(cp-1);
145: }
146:
147:
148: /*
149: * Send the data from the specified mail file out on the current smtp
150: * connection. Do the appropriate netascii conversion and hidden '.'
151: * padding. Send the <CRLF>.<CRLF> at completion.
152: */
153: do_data(unixformat, sfi, sfo, from, rcpts, domain)
154: register FILE *sfi; /* mail file descriptor */
155: register FILE *sfo; /* smtp files */
156: char *from;
157: namelist *rcpts;
158: char *domain;
159: {
160: static string *rcvr;
161: char buf[4096];
162: namelist *p;
163: long nchars;
164:
165: /*
166: * turn rcpts into a , list of receivers
167: */
168: rcvr = s_reset(rcvr);
169: for(p = rcpts; p; p = p->next){
170: s_append(rcvr, p->name);
171: if(p->next)
172: s_append(rcvr, ", ");
173: }
174:
175: /*
176: * send data to output
177: */
178: setalarm(5 MINUTES, "start sending mail data", EX_TEMPFAIL);
179: nbytes = 0;
180: smlastchar = '\n';
181: if(unixformat){
182: nchars = 0;
183: while(fgets(buf, sizeof(buf), sfi)!=NULL) {
184: smfputs(buf, sfo);
185: nchars += strlen(buf)+1;
186: if (nchars>1024) {
187: if (debug)
188: fprintf(stderr, ".");
189: nchars -= 1024;
190: setalarm(5 MINUTES, "sending mail data", EX_TEMPFAIL);
191: }
192: }
193: } else {
194: if(to822(smfputs, sfi, sfo, from, domain, s_to_c(rcvr))<0){
195: Syslog(LOG_INFO, "bad input file to %s\n",
196: s_to_c(rcvr));
197: bomb(EX_DATAERR);
198: }
199: }
200:
201: /*
202: * terminate the DATA command with \r\n.\r\n
203: */
204: if(smlastchar != '\n'){
205: fputs("\r\n", sfo);
206: nbytes += 2;
207: }
208: fputs(".\r\n", sfo);
209: nbytes += 3;
210: Syslog(LOG_INFO, "%s sent %d bytes to %s\n",
211: from, nbytes, s_to_c(rcvr));
212:
213: /*
214: * see if we screwed up
215: */
216: setalarm(30 MINUTES, "finishing data", EX_TEMPFAIL);
217: fflush(sfo);
218: if (ferror(sfo)) {
219: Syslog(LOG_INFO, "write error finishing data to %s",
220: s_to_c(rcvr));
221: bomb(EX_IOERR);
222: }
223: }
224:
225: /*
226: * Expect a reply message with the specified code. If the specified code
227: * is received return TRUE; otherwise print the error message out on the
228: * standard output and give up. Note that the reply can be a multiline
229: * message.
230: */
231: expect(code, sfi, sfo, error)
232: int code;
233: FILE *sfi, *sfo;
234: int error;
235: {
236: int retcd;
237: char cmdbuf[BUFSIZ];
238: char cbuf[6144];
239: extern int debug;
240:
241: cbuf[0] = '\0';
242:
243: /* get whole reply */
244: more:
245: while (tgets(cmdbuf, sizeof cmdbuf, sfi) > 0) {
246: cmdbuf[131] = '\n';
247: cmdbuf[132] = '\0'; /* not too long */
248: Syslog(LOG_DEBUG, "---> %s", cmdbuf);
249: if (cmdbuf[3] != '-') /* continuation line? */
250: break; /* no, last line */
251: else if (strlen(cmdbuf) + strlen(cbuf) + 4 < sizeof(cbuf)) {
252: strcat(cbuf, "<<< ");
253: strcat(cbuf, cmdbuf);
254: }
255: }
256: if (sscanf(cmdbuf, "%d", &retcd) != 1 ){
257: int l=strlen(cmdbuf)-1;
258: if (l>=0 && cmdbuf[l]=='\n')
259: cmdbuf[l]='\0';
260: (void) fprintf(stderr, "non-numeric command reply (%s)\n", cmdbuf);
261: if (error)
262: bomb(EX_PROTOCOL);
263: else
264: return 1;
265: }
266: if (retcd == code) {
267: return 1;
268: }
269: if (retcd/100 == code/100) {
270: return 1;
271: }
272: Syslog(LOG_NOTICE, "Failed, expecting %d, got %d\n", code, retcd);
273: /* print the error line */
274: (void) fprintf(stderr, "%s<<< %s", cbuf, cmdbuf);
275: csend("QUIT\n");
276: if (error)
277: if (retcd/100 == 4)
278: bomb(EX_TEMPFAIL); /* 4xx make temp fails, no matter what*/
279: else
280: bomb(error); /* map smtp errors to mailsys errors */
281: return 1;
282: }
283:
284: setalarm(limit, message, error)
285: char *message;
286: {
287: timelim = limit;
288: timemsg = message;
289: timeerror = error;
290: alarm(limit);
291: }
292:
293: /* Maximum time to live elapsed. Die right now. */
294: SIGRETURN
295: death()
296: {
297: Syslog(LOG_NOTICE, "Timer (%d sec) expired: %s.\n", timelim, timemsg);
298: exit(timeerror);
299: }
300:
301: SIGRETURN
302: ignore_signal(){}
303:
304: csend(buf)
305: char *buf;
306: {
307: Syslog(LOG_DEBUG, "<--- %s", buf);
308: tputs(buf, fo);
309: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.