2 * smtp.c -- code for speaking SMTP to a listener port
4 * Concept due to Harry Hochheiser. Implementation by ESR. Cleanup and
5 * strict RFC821 compliance by Cameron MacPherson.
7 * Copyright 1997 Eric S. Raymond
8 * For license terms, see the file COPYING in this directory.
12 #include "fetchmail.h"
28 static struct opt extensions[] =
30 {"8BITMIME", ESMTP_8BITMIME},
33 {"AUTH ", ESMTP_AUTH},
36 #endif /* ODMR_ENABLE */
40 char smtp_response[MSGBUFSIZE];
42 int SMTP_helo(int sock, char smtp_mode, const char *host)
43 /* send a "HELO" message to the SMTP listener */
47 SockPrintf(sock,"HELO %s\r\n", host);
48 if (outlevel >= O_MONITOR)
49 report(stdout, "%cMTP> HELO %s\n", smtp_mode, host);
50 ok = SMTP_ok(sock, smtp_mode);
54 static void SMTP_auth_error(int sock, const char *msg)
56 SockPrintf(sock, "*\r\n");
57 SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
58 if (outlevel >= O_MONITOR) report(stdout, msg);
61 static void SMTP_auth(int sock, char smtp_mode, char *username, char *password, char *buf)
62 /* ESMTP Authentication support for fetchmail by Wojciech Polak */
69 if (!username || !password) return;
71 memset(b64buf, 0, sizeof(b64buf));
72 memset(tmp, 0, sizeof(tmp));
74 if (strstr(buf, "CRAM-MD5")) {
75 unsigned char digest[16];
76 memset(digest, 0, sizeof(digest));
78 if (outlevel >= O_MONITOR)
79 report(stdout, GT_("ESMTP CRAM-MD5 Authentication...\n"));
80 SockPrintf(sock, "AUTH CRAM-MD5\r\n");
81 SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
82 strncpy(tmp, smtp_response, sizeof(tmp));
83 tmp[sizeof(tmp)-1] = '\0';
85 if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
86 SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n"));
92 /* (hmh) from64tobits will not NULL-terminate strings! */
93 if (from64tobits(b64buf, p, sizeof(b64buf) - 1) <= 0) {
94 SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
97 if (outlevel >= O_DEBUG)
98 report(stdout, GT_("Challenge decoded: %s\n"), b64buf);
99 hmac_md5(password, strlen(password),
100 b64buf, strlen(b64buf), digest, sizeof(digest));
101 snprintf(tmp, sizeof(tmp),
102 "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
103 username, digest[0], digest[1], digest[2], digest[3],
104 digest[4], digest[5], digest[6], digest[7], digest[8],
105 digest[9], digest[10], digest[11], digest[12], digest[13],
106 digest[14], digest[15]);
108 to64frombits(b64buf, tmp, strlen(tmp));
109 SockPrintf(sock, "%s\r\n", b64buf);
110 SMTP_ok(sock, smtp_mode);
112 else if (strstr(buf, "PLAIN")) {
114 if (outlevel >= O_MONITOR)
115 report(stdout, GT_("ESMTP PLAIN Authentication...\n"));
116 snprintf(tmp, sizeof(tmp), "^%s^%s", username, password);
119 for (c = len - 1; c >= 0; c--)
124 to64frombits(b64buf, tmp, len);
125 SockPrintf(sock, "AUTH PLAIN %s\r\n", b64buf);
126 SMTP_ok(sock, smtp_mode);
128 else if (strstr(buf, "LOGIN")) {
129 if (outlevel >= O_MONITOR)
130 report(stdout, GT_("ESMTP LOGIN Authentication...\n"));
131 SockPrintf(sock, "AUTH LOGIN\r\n");
132 SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
133 strncpy(tmp, smtp_response, sizeof(tmp));
134 tmp[sizeof(tmp)-1] = '\0';
136 if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
137 SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n"));
141 p = strchr(tmp, ' ');
143 if (from64tobits(b64buf, p, sizeof(b64buf) - 1) <= 0) {
144 SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
147 to64frombits(b64buf, username, strlen(username));
148 SockPrintf(sock, "%s\r\n", b64buf);
149 SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
150 strncpy(tmp, smtp_response, sizeof(tmp));
151 tmp[sizeof(tmp)-1] = '\0';
152 p = strchr(tmp, ' ');
154 SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
158 memset(b64buf, 0, sizeof(b64buf));
159 if (from64tobits(b64buf, p, sizeof(b64buf) - 1) <= 0) {
160 SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n"));
163 to64frombits(b64buf, password, strlen(password));
164 SockPrintf(sock, "%s\r\n", b64buf);
165 SMTP_ok(sock, smtp_mode);
170 int SMTP_ehlo(int sock, char smtp_mode, const char *host, char *name, char *password, int *opt)
171 /* send a "EHLO" message to the SMTP listener, return extension status bits */
174 char auth_response[511];
176 SockPrintf(sock,"%cHLO %s\r\n", (smtp_mode == 'S') ? 'E' : smtp_mode, host);
177 if (outlevel >= O_MONITOR)
178 report(stdout, "%cMTP> %cHLO %s\n",
179 smtp_mode, (smtp_mode == 'S') ? 'E' : smtp_mode, host);
182 while ((SockRead(sock, smtp_response, sizeof(smtp_response)-1)) != -1)
184 int n = strlen(smtp_response);
186 if (smtp_response[strlen(smtp_response)-1] == '\n')
187 smtp_response[strlen(smtp_response)-1] = '\0';
188 if (smtp_response[strlen(smtp_response)-1] == '\r')
189 smtp_response[strlen(smtp_response)-1] = '\0';
192 smtp_response[n] = '\0';
193 if (outlevel >= O_MONITOR)
194 report(stdout, "%cMTP< %s\n", smtp_mode, smtp_response);
195 for (hp = extensions; hp->name; hp++)
196 if (!strncasecmp(hp->name, smtp_response+4, strlen(hp->name))) {
198 if (strncmp(hp->name, "AUTH ", 5) == 0)
199 strncpy(auth_response, smtp_response, sizeof(auth_response));
200 auth_response[sizeof(auth_response)-1] = '\0';
202 if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') {
203 if (*opt & ESMTP_AUTH)
204 SMTP_auth(sock, smtp_mode, name, password, auth_response);
207 else if (smtp_response[3] != '-')
210 return SM_UNRECOVERABLE;
213 int SMTP_from(int sock, char smtp_mode, const char *from, const char *opts)
214 /* send a "MAIL FROM:" message to the SMTP listener */
217 char buf[MSGBUFSIZE];
220 snprintf(buf, sizeof(buf), "MAIL FROM:%s", from);
222 snprintf(buf, sizeof(buf), "MAIL FROM:<%s>", from);
224 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", opts);
225 SockPrintf(sock,"%s\r\n", buf);
226 if (outlevel >= O_MONITOR)
227 report(stdout, "%cMTP> %s\n", smtp_mode, buf);
228 ok = SMTP_ok(sock, smtp_mode);
232 int SMTP_rcpt(int sock, char smtp_mode, const char *to)
233 /* send a "RCPT TO:" message to the SMTP listener */
237 SockPrintf(sock,"RCPT TO:<%s>\r\n", to);
238 if (outlevel >= O_MONITOR)
239 report(stdout, "%cMTP> RCPT TO:<%s>\n", smtp_mode, to);
240 ok = SMTP_ok(sock, smtp_mode);
244 int SMTP_data(int sock, char smtp_mode)
245 /* send a "DATA" message to the SMTP listener */
249 SockPrintf(sock,"DATA\r\n");
250 if (outlevel >= O_MONITOR)
251 report(stdout, "%cMTP> DATA\n", smtp_mode);
252 ok = SMTP_ok(sock, smtp_mode);
256 int SMTP_rset(int sock, char smtp_mode)
257 /* send a "RSET" message to the SMTP listener */
261 SockPrintf(sock,"RSET\r\n");
262 if (outlevel >= O_MONITOR)
263 report(stdout, "%cMTP> RSET\n", smtp_mode);
264 ok = SMTP_ok(sock, smtp_mode);
268 int SMTP_quit(int sock, char smtp_mode)
269 /* send a "QUIT" message to the SMTP listener */
273 SockPrintf(sock,"QUIT\r\n");
274 if (outlevel >= O_MONITOR)
275 report(stdout, "%cMTP> QUIT\n", smtp_mode);
276 ok = SMTP_ok(sock, smtp_mode);
280 int SMTP_eom(int sock, char smtp_mode)
281 /* send a message data terminator to the SMTP listener */
285 SockPrintf(sock,".\r\n");
286 if (outlevel >= O_MONITOR)
287 report(stdout, "%cMTP>. (EOM)\n", smtp_mode);
290 * When doing LMTP, must process many of these at the outer level.
292 if (smtp_mode == 'S')
293 ok = SMTP_ok(sock, smtp_mode);
300 time_t last_smtp_ok = 0;
302 int SMTP_ok(int sock, char smtp_mode)
303 /* returns status of SMTP connection */
305 SIGHANDLERTYPE alrmsave;
307 /* set an alarm for smtp ok */
308 alrmsave = set_signal_handler(SIGALRM, null_signal_handler);
309 set_timeout(mytimeout);
311 while ((SockRead(sock, smtp_response, sizeof(smtp_response)-1)) != -1)
317 set_signal_handler(SIGALRM, alrmsave);
319 n = strlen(smtp_response);
320 if (n > 0 && smtp_response[n-1] == '\n')
322 if (n > 0 && smtp_response[n-1] == '\r')
324 smtp_response[n] = '\0';
325 if (outlevel >= O_MONITOR)
326 report(stdout, "%cMTP< %s\n", smtp_mode, smtp_response);
328 (smtp_response[3] != ' ' && smtp_response[3] != '-'))
330 if (outlevel >= O_MONITOR)
331 report(stderr, GT_("smtp listener protocol error\n"));
332 return SM_UNRECOVERABLE;
335 last_smtp_ok = time((time_t *) NULL);
337 if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') &&
338 smtp_response[3] == ' ')
340 else if (smtp_response[3] != '-')
343 /* set an alarm for smtp ok */
344 set_signal_handler(SIGALRM, null_signal_handler);
345 set_timeout(mytimeout);
351 set_signal_handler(SIGALRM, alrmsave);
353 if (outlevel >= O_MONITOR)
354 report(stderr, GT_("smtp listener protocol error\n"));
355 return SM_UNRECOVERABLE;
358 /* smtp.c ends here */