Commit 93322974 933229747445853b2238047c88170d96aaf7727c by Sergey Poznyakoff

Implemented client side TLS

1 parent e7e40e7a
...@@ -48,6 +48,8 @@ ...@@ -48,6 +48,8 @@
48 #include <mailutils/header.h> 48 #include <mailutils/header.h>
49 #include <mailutils/observer.h> 49 #include <mailutils/observer.h>
50 #include <mailutils/stream.h> 50 #include <mailutils/stream.h>
51 #include <mailutils/argcv.h>
52 #include <mailutils/tls.h>
51 53
52 /* For dbg purposes set to one to see different level of traffic. */ 54 /* For dbg purposes set to one to see different level of traffic. */
53 /* Print to stderr the command sent to the IMAP server. */ 55 /* Print to stderr the command sent to the IMAP server. */
...@@ -171,8 +173,8 @@ folder_imap_destroy (folder_t folder) ...@@ -171,8 +173,8 @@ folder_imap_destroy (folder_t folder)
171 f_imap_t f_imap = folder->data; 173 f_imap_t f_imap = folder->data;
172 if (f_imap->buffer) 174 if (f_imap->buffer)
173 free (f_imap->buffer); 175 free (f_imap->buffer);
174 if (f_imap->capa) 176 if (f_imap->capav)
175 free (f_imap->capa); 177 argcv_free (f_imap->capac, f_imap->capav);
176 free (f_imap); 178 free (f_imap);
177 folder->data = NULL; 179 folder->data = NULL;
178 } 180 }
...@@ -212,6 +214,66 @@ folder_imap_get_authority (folder_t folder, authority_t *pauth) ...@@ -212,6 +214,66 @@ folder_imap_get_authority (folder_t folder, authority_t *pauth)
212 return status; 214 return status;
213 } 215 }
214 216
217 static int
218 parse_capa (f_imap_t f_imap, char *str)
219 {
220 if (f_imap->capav)
221 argcv_free (f_imap->capac, f_imap->capav);
222 return argcv_get (str, "", NULL, &f_imap->capac, &f_imap->capav);
223 }
224
225 static int
226 check_capa (f_imap_t f_imap, char *capa)
227 {
228 int i;
229
230 if (!f_imap->capav)
231 {
232 int status;
233 status = imap_writeline (f_imap, "g%u CAPABILITY\r\n",
234 f_imap->seq++);
235 status = imap_send (f_imap);
236 status = imap_parse (f_imap);
237 }
238 for (i = 0; i < f_imap->capac; i++)
239 if (strcasecmp (f_imap->capav[i], capa) == 0)
240 return 0;
241 return 1;
242 }
243
244 static int
245 tls (folder_t folder)
246 {
247 #ifdef WITH_TLS
248 int status;
249 f_imap_t f_imap = folder->data;
250
251 if (!mu_tls_enable || check_capa (f_imap, "STARTTLS"))
252 return -1;
253
254 status = imap_writeline (f_imap, "g%u STARTTLS\r\n",
255 f_imap->seq, f_imap->user, f_imap->passwd);
256 CHECK_ERROR (f_imap, status);
257 status = imap_send (f_imap);
258 CHECK_ERROR (f_imap, status);
259 status = imap_parse (f_imap);
260 if (status == 0)
261 {
262 stream_t str;
263 status = tls_stream_create_client_from_tcp (&str, folder->stream, 0);
264 CHECK_ERROR (f_imap, status);
265 status = stream_open (str);
266 if (status == 0)
267 folder->stream = str;
268 FOLDER_DEBUG1 (folder, MU_DEBUG_PROT, "TLS negotiation %s\n",
269 status == 0 ? "succeeded" : "failed");
270 }
271 return status;
272 #else
273 return -1;
274 #endif
275 }
276
215 /* Simple User/pass authentication for imap. */ 277 /* Simple User/pass authentication for imap. */
216 static int 278 static int
217 authenticate_imap_login (authority_t auth) 279 authenticate_imap_login (authority_t auth)
...@@ -486,8 +548,8 @@ folder_imap_open (folder_t folder, int flags) ...@@ -486,8 +548,8 @@ folder_imap_open (folder_t folder, int flags)
486 CHECK_EAGAIN (f_imap, status); 548 CHECK_EAGAIN (f_imap, status);
487 f_imap->ptr = f_imap->buffer; 549 f_imap->ptr = f_imap->buffer;
488 FOLDER_DEBUG0 (folder, MU_DEBUG_PROT, f_imap->buffer); 550 FOLDER_DEBUG0 (folder, MU_DEBUG_PROT, f_imap->buffer);
489 /* Are they open for business ? The server send an untag response 551 /* Are they open for business ? The server send an untagged response
490 for greeting. Thenically it can be OK/PREAUTH/BYE. The BYE is 552 for greeting. Tecnically it can be OK/PREAUTH/BYE. The BYE is
491 the one that we do not want, server being unfriendly. */ 553 the one that we do not want, server being unfriendly. */
492 if (strncasecmp (f_imap->buffer, "* PREAUTH", 9) == 0) 554 if (strncasecmp (f_imap->buffer, "* PREAUTH", 9) == 0)
493 { 555 {
...@@ -500,7 +562,8 @@ folder_imap_open (folder_t folder, int flags) ...@@ -500,7 +562,8 @@ folder_imap_open (folder_t folder, int flags)
500 f_imap->state = IMAP_AUTH; 562 f_imap->state = IMAP_AUTH;
501 } 563 }
502 } 564 }
503 565 tls(folder);
566
504 case IMAP_AUTH: 567 case IMAP_AUTH:
505 case IMAP_LOGIN: 568 case IMAP_LOGIN:
506 case IMAP_LOGIN_ACK: 569 case IMAP_LOGIN_ACK:
...@@ -979,7 +1042,7 @@ imap_literal_string (f_imap_t f_imap, char **ptr) ...@@ -979,7 +1042,7 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
979 } 1042 }
980 1043
981 /* The (len + 1) in the for is to count the strip '\r' by imap_readline. */ 1044 /* The (len + 1) in the for is to count the strip '\r' by imap_readline. */
982 for (len0 = len = total = 0; total < f_imap->string.nleft; total += (len + 1)) 1045 for (len0 = len = total = 0; total < f_imap->string.nleft; total += len + 1)
983 { 1046 {
984 status = imap_readline (f_imap); 1047 status = imap_readline (f_imap);
985 if (DEBUG_SHOW_DATA) 1048 if (DEBUG_SHOW_DATA)
...@@ -1948,7 +2011,8 @@ imap_readline (f_imap_t f_imap) ...@@ -1948,7 +2011,8 @@ imap_readline (f_imap_t f_imap)
1948 while (f_imap->nl == NULL); 2011 while (f_imap->nl == NULL);
1949 2012
1950 /* Conversion \r\n --> \n\0 */ 2013 /* Conversion \r\n --> \n\0 */
1951 if (f_imap->nl > f_imap->buffer) 2014 /* FIXME: This should be done transparently by the TCP stream */
2015 if (f_imap->nl > f_imap->buffer && f_imap->nl[-1] == '\r')
1952 { 2016 {
1953 *(f_imap->nl - 1) = '\n'; 2017 *(f_imap->nl - 1) = '\n';
1954 *(f_imap->nl) = '\0'; 2018 *(f_imap->nl) = '\0';
...@@ -2100,9 +2164,7 @@ imap_parse (f_imap_t f_imap) ...@@ -2100,9 +2164,7 @@ imap_parse (f_imap_t f_imap)
2100 initial capabilities list. This makes it unnecessary 2164 initial capabilities list. This makes it unnecessary
2101 for a client to send a separate CAPABILITY command if 2165 for a client to send a separate CAPABILITY command if
2102 it recognizes this response. */ 2166 it recognizes this response. */
2103 if (f_imap->capa) 2167 parse_capa (f_imap, cruft);
2104 free (f_imap->capa);
2105 f_imap->capa = strdup (cruft);
2106 } 2168 }
2107 else if (strcasecmp (subtag, "NEWNAME") == 0) 2169 else if (strcasecmp (subtag, "NEWNAME") == 0)
2108 { 2170 {
...@@ -2222,15 +2284,13 @@ imap_parse (f_imap_t f_imap) ...@@ -2222,15 +2284,13 @@ imap_parse (f_imap_t f_imap)
2222 } 2284 }
2223 else if (strcasecmp (response, "CAPABILITY") == 0) 2285 else if (strcasecmp (response, "CAPABILITY") == 0)
2224 { 2286 {
2225 if (f_imap->capa) 2287 parse_capa (f_imap, remainder);
2226 free (f_imap->capa);
2227 f_imap->capa = strdup (remainder);
2228 } 2288 }
2229 else if (strcasecmp (remainder, "EXISTS") == 0) 2289 else if (strcasecmp (remainder, "EXISTS") == 0)
2230 { 2290 {
2231 f_imap->selected->messages_count = strtol (response, NULL, 10); 2291 f_imap->selected->messages_count = strtol (response, NULL, 10);
2232 } 2292 }
2233 else if (strcasecmp (remainder, "EXPUNGE") == 0) 2293 else if (strcasecmp (remainder, "EXPUNGED") == 0)
2234 { 2294 {
2235 unsigned int msgno = strtol (response, NULL, 10); 2295 unsigned int msgno = strtol (response, NULL, 10);
2236 status = imap_expunge (f_imap, msgno); 2296 status = imap_expunge (f_imap, msgno);
......