]> Pileus Git - ~andy/fetchmail/blob - smtp.c
Internationalization fix.
[~andy/fetchmail] / smtp.c
1 /*
2  * smtp.c -- code for speaking SMTP to a listener port
3  *
4  * Concept due to Harry Hochheiser.  Implementation by ESR.  Cleanup and
5  * strict RFC821 compliance by Cameron MacPherson.
6  *
7  * Copyright 1997 Eric S. Raymond
8  * For license terms, see the file COPYING in this directory.
9  */
10
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include "fetchmail.h"
15 #include "socket.h"
16 #include "smtp.h"
17 #include "config.h"
18 #include "i18n.h"
19
20 struct opt
21 {
22     const char *name;
23     int value;
24 };
25
26 static struct opt extensions[] =
27 {
28     {"8BITMIME",        ESMTP_8BITMIME},
29     {"SIZE",            ESMTP_SIZE},
30     {"ETRN",            ESMTP_ETRN},
31     {"AUTH ",           ESMTP_AUTH},
32 #ifdef ODMR_ENABLE
33     {"ATRN",            ESMTP_ATRN},
34 #endif /* ODMR_ENABLE */
35     {(char *)NULL, 0},
36 };
37
38 char smtp_response[MSGBUFSIZE];
39
40 static char smtp_mode = 'S';
41
42 void SMTP_setmode(char sl)
43 /* set whether we are speaking SMTP or LMTP */
44 {
45     smtp_mode = sl;
46 }
47
48 int SMTP_helo(int sock,const char *host)
49 /* send a "HELO" message to the SMTP listener */
50 {
51   int ok;
52
53   SockPrintf(sock,"HELO %s\r\n", host);
54   if (outlevel >= O_MONITOR)
55       report(stdout, "SMTP> HELO %s\n", host);
56   ok = SMTP_ok(sock);
57   return ok;
58 }
59
60 static void SMTP_auth(int sock, char *username, char *password, char *buf)
61 /* ESMTP Authentication support for fetchmail by Wojciech Polak */
62 {
63         int c;
64         char *p = 0;
65         char b64buf[512];
66         char tmp[512];
67
68         memset(b64buf, 0, sizeof(b64buf));
69         memset(tmp, 0, sizeof(tmp));
70
71         if (strstr(buf, "CRAM-MD5")) {
72                 unsigned char digest[16];
73                 static char ascii_digest[33];
74                 memset(digest, 0, 16);
75
76                 if (outlevel >= O_MONITOR)
77                         report(stdout, GT_("ESMTP CRAM-MD5 Authentication...\n"));
78                 SockPrintf(sock, "AUTH CRAM-MD5\r\n");
79                 SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
80                 strncpy(tmp, smtp_response, sizeof(tmp));
81
82                 if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
83                         SockPrintf(sock, "*\r\n");
84                         SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
85                         if (outlevel >= O_MONITOR)
86                                 report(stdout, GT_("Server rejected the AUTH command.\n"));
87                         return;
88                 }
89
90                 p = strchr(tmp, ' ');
91                 p++;
92                 from64tobits(b64buf, p, sizeof(b64buf));
93                 if (outlevel >= O_DEBUG)
94                         report(stdout, GT_("Challenge decoded: %s\n"), b64buf);
95                 hmac_md5(password, strlen(password),
96                                  b64buf, strlen(b64buf), digest, sizeof(digest));
97                 for (c = 0; c < 16; c++)
98                         sprintf(ascii_digest + 2 * c, "%02x", digest[c]);
99 #ifdef HAVE_SNPRINTF
100                 snprintf(tmp, sizeof(tmp),
101 #else
102                 sprintf(tmp,
103 #endif /* HAVE_SNPRINTF */
104                 "%s %s", username, ascii_digest);
105
106                 to64frombits(b64buf, tmp, strlen(tmp));
107                 SockPrintf(sock, "%s\r\n", b64buf);
108                 SMTP_ok(sock);
109         }
110         else if (strstr(buf, "PLAIN")) {
111                 int len;
112                 if (outlevel >= O_MONITOR)
113                         report(stdout, GT_("ESMTP PLAIN Authentication...\n"));
114 #ifdef HAVE_SNPRINTF
115                 snprintf(tmp, sizeof(tmp),
116 #else
117                 sprintf(tmp,
118 #endif /* HAVE_SNPRINTF */
119                 "^%s^%s", username, password);
120
121                 len = strlen(tmp);
122                 for (c = len - 1; c >= 0; c--)
123                 {
124                         if (tmp[c] == '^')
125                                 tmp[c] = '\0';
126                 }
127                 to64frombits(b64buf, tmp, len);
128                 SockPrintf(sock, "AUTH PLAIN %s\r\n", b64buf);
129                 SMTP_ok(sock);
130         }
131         else if (strstr(buf, "LOGIN")) {
132                 if (outlevel >= O_MONITOR)
133                         report(stdout, GT_("ESMTP LOGIN Authentication...\n"));
134                 SockPrintf(sock, "AUTH LOGIN\r\n");
135                 SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
136                 strncpy(tmp, smtp_response, sizeof(tmp));
137
138                 if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */
139                         SockPrintf(sock, "*\r\n");
140                         SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
141                         if (outlevel >= O_MONITOR)
142                                 report(stdout, GT_("Server rejected the AUTH command.\n"));
143                         return;
144                 }
145
146                 p = strchr(tmp, ' ');
147                 p++;
148                 from64tobits(b64buf, p, sizeof(b64buf));
149                 to64frombits(b64buf, username, strlen(username));
150                 SockPrintf(sock, "%s\r\n", b64buf);
151                 SockRead(sock, smtp_response, sizeof(smtp_response) - 1);
152                 strncpy(tmp, smtp_response, sizeof(tmp));
153                 p = strchr(tmp, ' ');
154                 p++;
155                 from64tobits(b64buf, p, sizeof(b64buf));
156                 to64frombits(b64buf, password, strlen(password));
157                 SockPrintf(sock, "%s\r\n", b64buf);
158                 SMTP_ok(sock);
159         }
160         return;
161 }
162
163 int SMTP_ehlo(int sock, const char *host, char *name, char *password, int *opt)
164 /* send a "EHLO" message to the SMTP listener, return extension status bits */
165 {
166   struct opt *hp;
167   char auth_response[256];
168
169   SockPrintf(sock,"%cHLO %s\r\n", (smtp_mode == 'S') ? 'E' : smtp_mode, host);
170   if (outlevel >= O_MONITOR)
171       report(stdout, "%cMTP> %cHLO %s\n", 
172             smtp_mode, (smtp_mode == 'S') ? 'E' : smtp_mode, host);
173   
174   *opt = 0;
175   while ((SockRead(sock, smtp_response, sizeof(smtp_response)-1)) != -1)
176   {
177       int  n = strlen(smtp_response);
178
179       if (smtp_response[strlen(smtp_response)-1] == '\n')
180           smtp_response[strlen(smtp_response)-1] = '\0';
181       if (smtp_response[strlen(smtp_response)-1] == '\r')
182           smtp_response[strlen(smtp_response)-1] = '\0';
183       if (n < 4)
184           return SM_ERROR;
185       smtp_response[n] = '\0';
186       if (outlevel >= O_MONITOR)
187           report(stdout, "SMTP< %s\n", smtp_response);
188       for (hp = extensions; hp->name; hp++)
189           if (!strncasecmp(hp->name, smtp_response+4, strlen(hp->name))) {
190               *opt |= hp->value;
191               if (strncmp(hp->name, "AUTH ", 5) == 0)
192                 strncpy(auth_response, smtp_response, sizeof(auth_response));
193           }
194       if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') {
195           if (*opt & ESMTP_AUTH)
196                 SMTP_auth(sock, name, password, auth_response);
197           return SM_OK;
198       }
199       else if (smtp_response[3] != '-')
200           return SM_ERROR;
201   }
202   return SM_UNRECOVERABLE;
203 }
204
205 int SMTP_from(int sock, const char *from, const char *opts)
206 /* send a "MAIL FROM:" message to the SMTP listener */
207 {
208     int ok;
209     char buf[MSGBUFSIZE];
210
211     if (strchr(from, '<'))
212 #ifdef HAVE_SNPRINTF
213         snprintf(buf, sizeof(buf),
214 #else
215         sprintf(buf,
216 #endif /* HAVE_SNPRINTF */
217                 "MAIL FROM: %s", from);
218     else
219 #ifdef HAVE_SNPRINTF
220     snprintf(buf, sizeof(buf),
221 #else
222     sprintf(buf,
223 #endif /* HAVE_SNPRINTF */
224             "MAIL FROM:<%s>", from);
225     if (opts)
226 #ifdef HAVE_SNPRINTF
227         snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", opts);
228 #else
229         strcat(buf, opts);
230 #endif /* HAVE_SNPRINTF */
231     SockPrintf(sock,"%s\r\n", buf);
232     if (outlevel >= O_MONITOR)
233         report(stdout, "%cMTP> %s\n", smtp_mode, buf);
234     ok = SMTP_ok(sock);
235     return ok;
236 }
237
238 int SMTP_rcpt(int sock, const char *to)
239 /* send a "RCPT TO:" message to the SMTP listener */
240 {
241   int ok;
242
243   SockPrintf(sock,"RCPT TO:<%s>\r\n", to);
244   if (outlevel >= O_MONITOR)
245       report(stdout, "%cMTP> RCPT TO:<%s>\n", smtp_mode, to);
246   ok = SMTP_ok(sock);
247   return ok;
248 }
249
250 int SMTP_data(int sock)
251 /* send a "DATA" message to the SMTP listener */
252 {
253   int ok;
254
255   SockPrintf(sock,"DATA\r\n");
256   if (outlevel >= O_MONITOR)
257       report(stdout, "%cMTP> DATA\n", smtp_mode);
258   ok = SMTP_ok(sock);
259   return ok;
260 }
261
262 int SMTP_rset(int sock)
263 /* send a "RSET" message to the SMTP listener */
264 {
265   int ok;
266
267   SockPrintf(sock,"RSET\r\n");
268   if (outlevel >= O_MONITOR)
269       report(stdout, "%cMTP> RSET\n", smtp_mode);
270   ok = SMTP_ok(sock);
271   return ok;
272 }
273
274 int SMTP_quit(int sock)
275 /* send a "QUIT" message to the SMTP listener */
276 {
277   int ok;
278
279   SockPrintf(sock,"QUIT\r\n");
280   if (outlevel >= O_MONITOR)
281       report(stdout, "%cMTP> QUIT\n", smtp_mode);
282   ok = SMTP_ok(sock);
283   return ok;
284 }
285
286 int SMTP_eom(int sock)
287 /* send a message data terminator to the SMTP listener */
288 {
289   int ok;
290
291   SockPrintf(sock,".\r\n");
292   if (outlevel >= O_MONITOR)
293       report(stdout, "%cMTP>. (EOM)\n", smtp_mode);
294
295   /* 
296    * When doing LMTP, must process many of these at the outer level. 
297    */
298   if (smtp_mode == 'S')
299       ok = SMTP_ok(sock);
300   else
301       ok = SM_OK;
302
303   return ok;
304 }
305
306 int SMTP_ok(int sock)
307 /* returns status of SMTP connection */
308 {
309     while ((SockRead(sock, smtp_response, sizeof(smtp_response)-1)) != -1)
310     {
311         int  n = strlen(smtp_response);
312
313         if (smtp_response[strlen(smtp_response)-1] == '\n')
314             smtp_response[strlen(smtp_response)-1] = '\0';
315         if (smtp_response[strlen(smtp_response)-1] == '\r')
316             smtp_response[strlen(smtp_response)-1] = '\0';
317         if (n < 4)
318             return SM_ERROR;
319         smtp_response[n] = '\0';
320         if (outlevel >= O_MONITOR)
321             report(stdout, "%cMTP< %s\n", smtp_mode, smtp_response);
322         if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ')
323             return SM_OK;
324         else if (smtp_response[3] != '-')
325             return SM_ERROR;
326     }
327     return SM_UNRECOVERABLE;
328 }
329
330 /* smtp.c ends here */