1 /*
2  * libEtPan! -- a mail stuff library
3  *
4  * Copyright (C) 2001, 2005 - DINH Viet Hoa
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the libEtPan! project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * $Id: imapstorage.c,v 1.19 2008/02/17 13:13:26 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "imapstorage.h"
41 
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #include "mail.h"
46 #include "imapdriver.h"
47 #include "imapdriver_cached.h"
48 #include "mailstorage_tools.h"
49 #include "maildriver.h"
50 
51 /* imap storage */
52 
53 #define IMAP_DEFAULT_PORT  143
54 #define IMAPS_DEFAULT_PORT 993
55 
56 static int imap_mailstorage_connect(struct mailstorage * storage);
57 static int
58 imap_mailstorage_get_folder_session(struct mailstorage * storage,
59     char * pathname, mailsession ** result);
60 static void imap_mailstorage_uninitialize(struct mailstorage * storage);
61 
62 static mailstorage_driver imap_mailstorage_driver = {
63   /* sto_name               */ "imap",
64   /* sto_connect            */ imap_mailstorage_connect,
65   /* sto_get_folder_session */ imap_mailstorage_get_folder_session,
66   /* sto_uninitialize       */ imap_mailstorage_uninitialize
67 };
68 
69 LIBETPAN_EXPORT
imap_mailstorage_init(struct mailstorage * storage,const char * imap_servername,uint16_t imap_port,const char * imap_command,int imap_connection_type,int imap_auth_type,const char * imap_login,const char * imap_password,int imap_cached,const char * imap_cache_directory)70 int imap_mailstorage_init(struct mailstorage * storage,
71     const char * imap_servername, uint16_t imap_port,
72     const char * imap_command,
73     int imap_connection_type, int imap_auth_type,
74     const char * imap_login, const char * imap_password,
75     int imap_cached, const char * imap_cache_directory)
76 {
77   return imap_mailstorage_init_sasl(storage,
78       imap_servername, imap_port,
79       imap_command,
80       imap_connection_type,
81       NULL,
82       NULL,
83       NULL, NULL,
84       imap_login, imap_login,
85       imap_password, NULL,
86       imap_cached, imap_cache_directory);
87 }
88 
89 LIBETPAN_EXPORT
imap_mailstorage_init_sasl(struct mailstorage * storage,const char * imap_servername,uint16_t imap_port,const char * imap_command,int imap_connection_type,const char * auth_type,const char * server_fqdn,const char * local_ip_port,const char * remote_ip_port,const char * login,const char * auth_name,const char * password,const char * realm,int imap_cached,const char * imap_cache_directory)90 int imap_mailstorage_init_sasl(struct mailstorage * storage,
91     const char * imap_servername, uint16_t imap_port,
92     const char * imap_command,
93     int imap_connection_type,
94     const char * auth_type,
95     const char * server_fqdn,
96     const char * local_ip_port,
97     const char * remote_ip_port,
98     const char * login, const char * auth_name,
99     const char * password, const char * realm,
100     int imap_cached, const char * imap_cache_directory)
101 {
102   return imap_mailstorage_init_sasl_with_local_address(storage,
103       imap_servername, imap_port,
104       NULL, 0,
105       imap_command,
106       imap_connection_type,
107       auth_type,
108       server_fqdn,
109       local_ip_port,
110       remote_ip_port,
111       login, auth_name,
112       password, realm,
113       imap_cached, imap_cache_directory);
114 }
115 
116 LIBETPAN_EXPORT
imap_mailstorage_init_sasl_with_local_address(struct mailstorage * storage,const char * imap_servername,uint16_t imap_port,const char * imap_local_address,uint16_t imap_local_port,const char * imap_command,int imap_connection_type,const char * auth_type,const char * server_fqdn,const char * local_ip_port,const char * remote_ip_port,const char * login,const char * auth_name,const char * password,const char * realm,int imap_cached,const char * imap_cache_directory)117 int imap_mailstorage_init_sasl_with_local_address(struct mailstorage * storage,
118     const char * imap_servername, uint16_t imap_port,
119     const char * imap_local_address, uint16_t imap_local_port,
120     const char * imap_command,
121     int imap_connection_type,
122     const char * auth_type,
123     const char * server_fqdn,
124     const char * local_ip_port,
125     const char * remote_ip_port,
126     const char * login, const char * auth_name,
127     const char * password, const char * realm,
128     int imap_cached, const char * imap_cache_directory)
129 {
130   struct imap_mailstorage * imap_storage;
131 
132   imap_storage = malloc(sizeof(* imap_storage));
133   if (imap_storage == NULL)
134     goto err;
135 
136   if (imap_servername != NULL) {
137     imap_storage->imap_servername = strdup(imap_servername);
138     if (imap_storage->imap_servername == NULL)
139       goto free;
140   }
141   else {
142     imap_storage->imap_servername = NULL;
143   }
144 
145   if (imap_local_address != NULL) {
146     imap_storage->imap_local_address = strdup(imap_local_address);
147     if (imap_storage->imap_local_address == NULL)
148       goto free_servername;
149   }
150   else {
151     imap_storage->imap_local_address = NULL;
152   }
153 
154   imap_storage->imap_local_port = imap_local_port;
155 
156   imap_storage->imap_connection_type = imap_connection_type;
157 
158   if (imap_port == 0) {
159     switch (imap_connection_type) {
160     case CONNECTION_TYPE_PLAIN:
161     case CONNECTION_TYPE_TRY_STARTTLS:
162     case CONNECTION_TYPE_STARTTLS:
163     case CONNECTION_TYPE_COMMAND:
164     case CONNECTION_TYPE_COMMAND_TRY_STARTTLS:
165     case CONNECTION_TYPE_COMMAND_STARTTLS:
166       imap_port = IMAP_DEFAULT_PORT;
167       break;
168 
169     case CONNECTION_TYPE_TLS:
170     case CONNECTION_TYPE_COMMAND_TLS:
171       imap_port = IMAPS_DEFAULT_PORT;
172       break;
173 
174     default:
175       imap_port = IMAP_DEFAULT_PORT;
176       break;
177     }
178   }
179 
180   imap_storage->imap_port = imap_port;
181 
182   if (imap_command != NULL) {
183     imap_storage->imap_command = strdup(imap_command);
184     if (imap_storage->imap_command == NULL)
185       goto free_local_address;
186   }
187   else
188     imap_storage->imap_command = NULL;
189 
190   imap_storage->imap_auth_type = IMAP_AUTH_TYPE_PLAIN;
191 
192   imap_storage->imap_sasl.sasl_enabled = (auth_type != NULL);
193 
194   if (auth_type != NULL) {
195     imap_storage->imap_sasl.sasl_auth_type = strdup(auth_type);
196     if (imap_storage->imap_sasl.sasl_auth_type == NULL)
197       goto free_command;
198   }
199   else
200     imap_storage->imap_sasl.sasl_auth_type = NULL;
201 
202   if (server_fqdn != NULL) {
203     imap_storage->imap_sasl.sasl_server_fqdn = strdup(server_fqdn);
204     if (imap_storage->imap_sasl.sasl_server_fqdn == NULL)
205       goto free_auth_type;
206   }
207   else
208     imap_storage->imap_sasl.sasl_server_fqdn = NULL;
209 
210   if (local_ip_port != NULL) {
211     imap_storage->imap_sasl.sasl_local_ip_port = strdup(local_ip_port);
212     if (imap_storage->imap_sasl.sasl_local_ip_port == NULL)
213       goto free_server_fqdn;
214   }
215   else
216     imap_storage->imap_sasl.sasl_local_ip_port = NULL;
217 
218   if (remote_ip_port != NULL) {
219     imap_storage->imap_sasl.sasl_remote_ip_port = strdup(remote_ip_port);
220     if (imap_storage->imap_sasl.sasl_remote_ip_port == NULL)
221       goto free_local_ip_port;
222   }
223   else
224     imap_storage->imap_sasl.sasl_remote_ip_port = NULL;
225 
226   if (login != NULL) {
227     imap_storage->imap_sasl.sasl_login = strdup(login);
228     if (imap_storage->imap_sasl.sasl_login == NULL)
229       goto free_remote_ip_port;
230   }
231   else
232     imap_storage->imap_sasl.sasl_login = NULL;
233 
234   if (auth_name != NULL) {
235     imap_storage->imap_sasl.sasl_auth_name = strdup(auth_name);
236     if (imap_storage->imap_sasl.sasl_auth_name == NULL)
237       goto free_login;
238   }
239   else
240     imap_storage->imap_sasl.sasl_auth_name = NULL;
241 
242   if (password != NULL) {
243     imap_storage->imap_sasl.sasl_password = strdup(password);
244     if (imap_storage->imap_sasl.sasl_password == NULL)
245       goto free_auth_name;
246   }
247   else
248     imap_storage->imap_sasl.sasl_password = NULL;
249 
250   if (realm != NULL) {
251     imap_storage->imap_sasl.sasl_realm = strdup(realm);
252     if (imap_storage->imap_sasl.sasl_realm == NULL)
253       goto free_password;
254   }
255   else
256     imap_storage->imap_sasl.sasl_realm = NULL;
257 
258   imap_storage->imap_cached = imap_cached;
259 
260   if (imap_cached && (imap_cache_directory != NULL)) {
261     imap_storage->imap_cache_directory = strdup(imap_cache_directory);
262     if (imap_storage->imap_cache_directory == NULL)
263       goto free_realm;
264   }
265   else {
266     imap_storage->imap_cached = FALSE;
267     imap_storage->imap_cache_directory = NULL;
268   }
269 
270   imap_storage->imap_auth_type = imap_storage->imap_auth_type;
271   if (imap_storage->imap_sasl.sasl_login != NULL) {
272     imap_storage->imap_login = strdup(imap_storage->imap_sasl.sasl_login);
273     if (imap_storage->imap_login == NULL)
274       goto free_cache_directory;
275   }
276   else {
277     imap_storage->imap_login = NULL;
278   }
279 
280   if (imap_storage->imap_sasl.sasl_password != NULL) {
281     imap_storage->imap_password = strdup(imap_storage->imap_sasl.sasl_password);
282     if (imap_storage->imap_password == NULL)
283       goto free_copy_login;
284   }
285   else {
286     imap_storage->imap_password = NULL;
287   }
288 
289   storage->sto_data = imap_storage;
290   storage->sto_driver = &imap_mailstorage_driver;
291 
292   return MAIL_NO_ERROR;
293 
294  free_copy_login:
295   free(imap_storage->imap_login);
296  free_cache_directory:
297   free(imap_storage->imap_cache_directory);
298  free_realm:
299   free(imap_storage->imap_sasl.sasl_realm);
300  free_password:
301   free(imap_storage->imap_sasl.sasl_password);
302  free_auth_name:
303   free(imap_storage->imap_sasl.sasl_auth_name);
304  free_login:
305   free(imap_storage->imap_sasl.sasl_login);
306  free_remote_ip_port:
307   free(imap_storage->imap_sasl.sasl_remote_ip_port);
308  free_local_ip_port:
309   free(imap_storage->imap_sasl.sasl_local_ip_port);
310  free_server_fqdn:
311   free(imap_storage->imap_sasl.sasl_server_fqdn);
312  free_auth_type:
313   free(imap_storage->imap_sasl.sasl_auth_type);
314  free_command:
315   free(imap_storage->imap_command);
316  free_local_address:
317   free(imap_storage->imap_local_address);
318  free_servername:
319   free(imap_storage->imap_servername);
320  free:
321   free(imap_storage);
322  err:
323   return MAIL_ERROR_MEMORY;
324 }
325 
imap_mailstorage_uninitialize(struct mailstorage * storage)326 static void imap_mailstorage_uninitialize(struct mailstorage * storage)
327 {
328   struct imap_mailstorage * imap_storage;
329 
330   imap_storage = storage->sto_data;
331 
332   free(imap_storage->imap_password);
333   free(imap_storage->imap_login);
334 
335   free(imap_storage->imap_cache_directory);
336 
337   free(imap_storage->imap_sasl.sasl_realm);
338   free(imap_storage->imap_sasl.sasl_password);
339   free(imap_storage->imap_sasl.sasl_auth_name);
340   free(imap_storage->imap_sasl.sasl_login);
341   free(imap_storage->imap_sasl.sasl_remote_ip_port);
342   free(imap_storage->imap_sasl.sasl_local_ip_port);
343   free(imap_storage->imap_sasl.sasl_server_fqdn);
344   free(imap_storage->imap_sasl.sasl_auth_type);
345 
346   free(imap_storage->imap_command);
347   free(imap_storage->imap_local_address);
348   free(imap_storage->imap_servername);
349   free(imap_storage);
350 
351   storage->sto_data = NULL;
352 }
353 
imap_connect(struct mailstorage * storage,mailsession ** result)354 static int imap_connect(struct mailstorage * storage,
355     mailsession ** result)
356 {
357   struct imap_mailstorage * imap_storage;
358   mailsession_driver * driver;
359   int r;
360   int res;
361   mailsession * session;
362 
363   imap_storage = storage->sto_data;
364 
365   if (imap_storage->imap_cached)
366     driver = imap_cached_session_driver;
367   else
368     driver = imap_session_driver;
369 
370   r = mailstorage_generic_connect_with_local_address(driver,
371       imap_storage->imap_servername,
372       imap_storage->imap_port,
373       imap_storage->imap_local_address,
374       imap_storage->imap_local_port,
375       imap_storage->imap_command,
376       imap_storage->imap_connection_type,
377       IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY,
378       imap_storage->imap_cache_directory,
379       0, NULL,
380       &session);
381   switch (r) {
382   case MAIL_NO_ERROR_NON_AUTHENTICATED:
383   case MAIL_NO_ERROR_AUTHENTICATED:
384   case MAIL_NO_ERROR:
385     break;
386   default:
387     res = r;
388     goto err;
389   }
390 
391   r = mailstorage_generic_auth_sasl(session, r,
392       imap_storage->imap_sasl.sasl_auth_type,
393       imap_storage->imap_sasl.sasl_server_fqdn,
394       imap_storage->imap_sasl.sasl_local_ip_port,
395       imap_storage->imap_sasl.sasl_remote_ip_port,
396       imap_storage->imap_sasl.sasl_login,
397       imap_storage->imap_sasl.sasl_auth_name,
398       imap_storage->imap_sasl.sasl_password,
399       imap_storage->imap_sasl.sasl_realm);
400   if (r != MAIL_NO_ERROR) {
401     res = r;
402     goto free;
403   }
404 
405   * result = session;
406 
407   return MAIL_NO_ERROR;
408 
409  free:
410   mailsession_free(session);
411  err:
412   return res;
413 }
414 
imap_mailstorage_connect(struct mailstorage * storage)415 static int imap_mailstorage_connect(struct mailstorage * storage)
416 {
417   mailsession * session;
418   int r;
419   int res;
420 
421   r = imap_connect(storage, &session);
422   if (r != MAIL_NO_ERROR) {
423     res = r;
424     goto err;
425   }
426 
427   r = mailsession_select_folder(session, "INBOX");
428   if (r != MAIL_NO_ERROR) {
429     mailsession_logout(session);
430     res = r;
431     goto err;
432   }
433 
434   storage->sto_session = session;
435   storage->sto_driver = &imap_mailstorage_driver;
436 
437   return MAIL_NO_ERROR;
438 
439  err:
440   return res;
441 }
442 
443 static int
imap_mailstorage_get_folder_session(struct mailstorage * storage,char * pathname,mailsession ** result)444 imap_mailstorage_get_folder_session(struct mailstorage * storage,
445     char * pathname, mailsession ** result)
446 {
447   mailsession * session;
448   int r;
449   int res;
450 
451   if (strcasecmp(pathname, "INBOX") == 0) {
452     session = storage->sto_session;
453   }
454   else {
455     r = imap_connect(storage, &session);
456     if (r != MAIL_NO_ERROR) {
457       res = r;
458       goto err;
459     }
460 
461     r = mailsession_select_folder(session, pathname);
462     if (r != MAIL_NO_ERROR) {
463       mailsession_logout(session);
464       res = r;
465       goto free;
466     }
467   }
468 
469   * result = session;
470 
471   return MAIL_NO_ERROR;
472 
473  free:
474   mailsession_free(session);
475  err:
476   return res;
477 }
478