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: mailstream_low.c,v 1.27 2011/05/04 16:09:54 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "mailstream_low.h"
41 #include <stdlib.h>
42 
43 #ifdef LIBETPAN_MAILSTREAM_DEBUG
44 
45 #define STREAM_DEBUG
46 
47 #include <stdio.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <string.h>
51 #ifdef HAVE_UNISTD_H
52 #	include <unistd.h>
53 #endif
54 #include "maillock.h"
55 #ifdef WIN32
56 #	include "win_etpan.h"
57 #endif
58 #if defined(ANDROID) || defined(__ANDROID__)
59 #include <sys/select.h>
60 #endif
61 
62 #if USE_POLL && defined(HAVE_SYS_POLL_H)
63 #include <sys/poll.h>
64 #endif
65 
66 #include "mailstream_cfstream.h"
67 #include "mailstream_compress.h"
68 #include "mailstream_cancel.h"
69 
70 #define LOG_FILE "libetpan-stream-debug.log"
71 
72 LIBETPAN_EXPORT
73 int mailstream_debug = 0;
74 
75 LIBETPAN_EXPORT
76 void (* mailstream_logger)(int direction,
77     const char * str, size_t size) = NULL;
78 LIBETPAN_EXPORT
79 void (* mailstream_logger_id)(mailstream_low * s, int is_stream_data, int direction,
80     const char * str, size_t size) = NULL;
81 
82 static inline void mailstream_logger_internal(mailstream_low * s, int is_stream_data, int direction,
83     const char * buffer, size_t size);
84 
85 // Will log a buffer.
86 #define STREAM_LOG_ERROR(low, direction, buf, size) \
87   mailstream_logger_internal(low, 2, direction, buf, size); \
88   if (mailstream_debug) { \
89 	  if (mailstream_logger_id != NULL) { \
90 	    mailstream_logger_id(low, 2, direction, buf, size); \
91 	  } \
92     else if (mailstream_logger != NULL) { \
93       mailstream_logger(direction, buf, size); \
94     } \
95     else { \
96       FILE * f; \
97       mode_t old_mask; \
98       \
99       old_mask = umask(0077); \
100       f = fopen(LOG_FILE, "a"); \
101       umask(old_mask); \
102       if (f != NULL) { \
103         maillock_write_lock(LOG_FILE, fileno(f)); \
104         fwrite((buf), 1, (size), f); \
105         maillock_write_unlock(LOG_FILE, fileno(f)); \
106         fclose(f); \
107       } \
108     } \
109   }
110 
111 // Will log a buffer.
112 #define STREAM_LOG_BUF(low, direction, buf, size) \
113   mailstream_logger_internal(low, 1, direction, buf, size); \
114   if (mailstream_debug) { \
115   	if (mailstream_logger_id != NULL) { \
116   	  mailstream_logger_id(low, 1, direction, buf, size); \
117   	} \
118     else if (mailstream_logger != NULL) { \
119       mailstream_logger(direction, buf, size); \
120     } \
121     else { \
122       FILE * f; \
123       mode_t old_mask; \
124       \
125       old_mask = umask(0077); \
126       f = fopen(LOG_FILE, "a"); \
127       umask(old_mask); \
128       if (f != NULL) { \
129         maillock_write_lock(LOG_FILE, fileno(f)); \
130         fwrite((buf), 1, (size), f); \
131         maillock_write_unlock(LOG_FILE, fileno(f)); \
132         fclose(f); \
133       } \
134     } \
135   }
136 
137 // Will log some log text string.
138 #define STREAM_LOG(low, direction, str) \
139   mailstream_logger_internal(low, 0, direction, str, strlen(str)); \
140   if (mailstream_debug) { \
141   	if (mailstream_logger_id != NULL) { \
142   	  mailstream_logger_id(low, 0, direction, str, strlen(str)); \
143   	} \
144     else if (mailstream_logger != NULL) { \
145       mailstream_logger(direction, str, strlen(str)); \
146     } \
147     else { \
148       FILE * f; \
149       mode_t old_mask; \
150       \
151       old_mask = umask(0077); \
152       f = fopen(LOG_FILE, "a"); \
153       umask(old_mask); \
154       if (f != NULL) { \
155         maillock_write_lock(LOG_FILE, fileno(f)); \
156         fputs((str), f); \
157         maillock_write_unlock(LOG_FILE, fileno(f)); \
158         fclose(f); \
159       } \
160     } \
161   }
162 
163 #else
164 
165 #define STREAM_LOG_ERROR(low, direction, buf, size) do { } while (0)
166 #define STREAM_LOG_BUF(low, direction, buf, size) do { } while (0)
167 #define STREAM_LOG(low, direction, buf) do { } while (0)
168 
169 #endif
170 
171 
172 /* general functions */
173 
mailstream_low_new(void * data,mailstream_low_driver * driver)174 mailstream_low * mailstream_low_new(void * data,
175 				    mailstream_low_driver * driver)
176 {
177   mailstream_low * s;
178 
179   s = malloc(sizeof(* s));
180   if (s == NULL)
181     return NULL;
182 
183   s->data = data;
184   s->driver = driver;
185   s->privacy = 1;
186 	s->identifier = NULL;
187 	s->timeout = 0;
188   s->logger = NULL;
189   s->logger_context = NULL;
190 
191   return s;
192 }
193 
mailstream_low_close(mailstream_low * s)194 int mailstream_low_close(mailstream_low * s)
195 {
196   if (s == NULL)
197     return -1;
198   s->driver->mailstream_close(s);
199 
200   return 0;
201 }
202 
mailstream_low_get_fd(mailstream_low * s)203 int mailstream_low_get_fd(mailstream_low * s)
204 {
205   if (s == NULL)
206     return -1;
207   return s->driver->mailstream_get_fd(s);
208 }
209 
mailstream_low_get_cancel(mailstream_low * s)210 struct mailstream_cancel * mailstream_low_get_cancel(mailstream_low * s)
211 {
212   if (s == NULL)
213     return NULL;
214   if (s->driver->mailstream_get_cancel == NULL)
215     return NULL;
216   return s->driver->mailstream_get_cancel(s);
217 }
218 
mailstream_low_free(mailstream_low * s)219 void mailstream_low_free(mailstream_low * s)
220 {
221 	free(s->identifier);
222 	s->identifier = NULL;
223   s->driver->mailstream_free(s);
224 }
225 
mailstream_low_read(mailstream_low * s,void * buf,size_t count)226 ssize_t mailstream_low_read(mailstream_low * s, void * buf, size_t count)
227 {
228   ssize_t r;
229 
230   if (s == NULL)
231     return -1;
232   r = s->driver->mailstream_read(s, buf, count);
233 
234 #ifdef STREAM_DEBUG
235   if (r > 0) {
236     STREAM_LOG(s, 0, "<<<<<<< read <<<<<<\n");
237     STREAM_LOG_BUF(s, 0, buf, r);
238     STREAM_LOG(s, 0, "\n");
239     STREAM_LOG(s, 0, "<<<<<<< end read <<<<<<\n");
240   }
241 #endif
242 
243   if (r < 0) {
244     STREAM_LOG_ERROR(s, 4, buf, 0);
245   }
246 
247   return r;
248 }
249 
mailstream_low_write(mailstream_low * s,const void * buf,size_t count)250 ssize_t mailstream_low_write(mailstream_low * s,
251     const void * buf, size_t count)
252 {
253   ssize_t r;
254 
255   if (s == NULL)
256     return -1;
257 
258 #ifdef STREAM_DEBUG
259   STREAM_LOG(s, 1, ">>>>>>> send >>>>>>\n");
260   if (s->privacy) {
261     STREAM_LOG_BUF(s, 1, buf, count);
262   }
263   else {
264     STREAM_LOG_BUF(s, 2, buf, count);
265   }
266   STREAM_LOG(s, 1, "\n");
267   STREAM_LOG(s, 1, ">>>>>>> end send >>>>>>\n");
268 #endif
269 
270   r = s->driver->mailstream_write(s, buf, count);
271 
272   if (r < 0) {
273     STREAM_LOG_ERROR(s, 4 | 1, buf, 0);
274   }
275 
276   return r;
277 }
278 
mailstream_low_cancel(mailstream_low * s)279 void mailstream_low_cancel(mailstream_low * s)
280 {
281   if (s == NULL)
282     return;
283 
284   if (s->driver->mailstream_cancel == NULL)
285     return;
286 
287   s->driver->mailstream_cancel(s);
288 }
289 
mailstream_low_log_error(mailstream_low * s,const void * buf,size_t count)290 void mailstream_low_log_error(mailstream_low * s,
291     const void * buf, size_t count)
292 {
293 	STREAM_LOG_ERROR(s, 0, buf, count);
294 }
295 
mailstream_low_set_privacy(mailstream_low * s,int can_be_public)296 void mailstream_low_set_privacy(mailstream_low * s, int can_be_public)
297 {
298   s->privacy = can_be_public;
299 }
300 
mailstream_low_set_identifier(mailstream_low * s,char * identifier)301 int mailstream_low_set_identifier(mailstream_low * s,
302     char * identifier)
303 {
304 	free(s->identifier);
305 	s->identifier = NULL;
306 
307 	if (identifier != NULL) {
308 		s->identifier = identifier;
309   }
310 
311 	return 0;
312 }
313 
mailstream_low_get_identifier(mailstream_low * s)314 const char * mailstream_low_get_identifier(mailstream_low * s)
315 {
316 	return s->identifier;
317 }
318 
mailstream_low_set_timeout(mailstream_low * s,time_t timeout)319 void mailstream_low_set_timeout(mailstream_low * s,
320   time_t timeout)
321 {
322 	s->timeout = timeout;
323 }
324 
mailstream_low_get_timeout(mailstream_low * s)325 time_t mailstream_low_get_timeout(mailstream_low * s)
326 {
327 	return s->timeout;
328 }
329 
mailstream_low_set_logger(mailstream_low * s,void (* logger)(mailstream_low * s,int log_type,const char * str,size_t size,void * context),void * logger_context)330 void mailstream_low_set_logger(mailstream_low * s, void (* logger)(mailstream_low * s, int log_type,
331   const char * str, size_t size, void * context), void * logger_context)
332 {
333   s->logger = logger;
334   s->logger_context = logger_context;
335 }
336 
mailstream_logger_internal(mailstream_low * s,int is_stream_data,int direction,const char * buffer,size_t size)337 static inline void mailstream_logger_internal(mailstream_low * s, int is_stream_data, int direction,
338   const char * buffer, size_t size)
339 {
340   int log_type = -1;
341 
342   if (s->logger == NULL)
343     return;
344 
345   /*
346    stream data:
347   0: log
348   1: buffer
349   2: error
350 
351   direction:
352   4|1: send error
353   4: receive error
354   2: sent private data
355   1: sent data
356   0: received data
357   */
358 
359   switch (is_stream_data) {
360     case 0: {
361       switch (direction) {
362         case 1:
363         case 2:
364         case 4|1:
365           log_type = MAILSTREAM_LOG_TYPE_INFO_SENT;
366           break;
367         case 0:
368         case 4:
369           log_type = MAILSTREAM_LOG_TYPE_INFO_RECEIVED;
370           break;
371       }
372       break;
373     }
374     case 1: {
375       switch (direction) {
376         case 2:
377           log_type = MAILSTREAM_LOG_TYPE_DATA_SENT_PRIVATE;
378           break;
379         case 1:
380         case 4|1:
381           log_type = MAILSTREAM_LOG_TYPE_DATA_SENT;
382           break;
383         case 0:
384         case 4:
385         default:
386           log_type = MAILSTREAM_LOG_TYPE_DATA_RECEIVED;
387           break;
388       }
389       break;
390     }
391     case 2: {
392       switch (direction) {
393         case 2:
394         case 1:
395         case 4|1:
396           log_type = MAILSTREAM_LOG_TYPE_ERROR_SENT;
397           break;
398         case 4:
399           log_type = MAILSTREAM_LOG_TYPE_ERROR_RECEIVED;
400           break;
401         case 0:
402           log_type = MAILSTREAM_LOG_TYPE_ERROR_PARSE;
403           break;
404       }
405       break;
406     }
407   }
408 
409   if (log_type == -1)
410     return;
411 
412   s->logger(s, log_type, buffer, size, s->logger_context);
413 }
414 
mailstream_low_get_certificate_chain(mailstream_low * s)415 carray * mailstream_low_get_certificate_chain(mailstream_low * s)
416 {
417   if (s == NULL)
418     return NULL;
419 
420   if (s->driver->mailstream_get_certificate_chain == NULL)
421     return NULL;
422 
423   return s->driver->mailstream_get_certificate_chain(s);
424 }
425 
mailstream_low_wait_idle(mailstream_low * low,struct mailstream_cancel * idle,int max_idle_delay)426 int mailstream_low_wait_idle(mailstream_low * low, struct mailstream_cancel * idle,
427                              int max_idle_delay)
428 {
429   int fd;
430   int idle_fd;
431   int cancel_fd;
432   int r;
433 #if defined(WIN32)
434   fd_set readfds;
435 #elif USE_POLL
436   struct pollfd pfd[3];
437 #else
438   int maxfd;
439   fd_set readfds;
440 #endif
441 
442   if (low->driver == mailstream_cfstream_driver) {
443     return mailstream_low_cfstream_wait_idle(low, max_idle_delay);
444   }
445   else if (low->driver == mailstream_compress_driver) {
446     return mailstream_low_compress_wait_idle(low, idle, max_idle_delay);
447   }
448 
449   if (idle == NULL) {
450 		return MAILSTREAM_IDLE_ERROR;
451 	}
452   if (mailstream_low_get_cancel(low) == NULL) {
453 		return MAILSTREAM_IDLE_ERROR;
454 	}
455   fd = mailstream_low_get_fd(low);
456   idle_fd = mailstream_cancel_get_fd(idle);
457   cancel_fd = mailstream_cancel_get_fd(mailstream_low_get_cancel(low));
458 
459 #if defined(WIN32)
460   FD_ZERO(&readfds);
461   HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
462   WSAEventSelect(fd, event, FD_READ | FD_CLOSE);
463   FD_SET(event, &readfds);
464   FD_SET(idle_fd, &readfds);
465   FD_SET(cancel_fd, &readfds);
466   r = WaitForMultipleObjects(readfds.fd_count, readfds.fd_array, FALSE, max_idle_delay * 1000);
467   WSAEventSelect(fd, event, 0);
468   CloseHandle(event);
469   if (r == WAIT_TIMEOUT) {
470 	  return MAILSTREAM_IDLE_TIMEOUT;
471   }
472   else if (r == WAIT_OBJECT_0){
473 	  return MAILSTREAM_IDLE_HASDATA;
474   }
475   else if (r == WAIT_OBJECT_0 + 1){
476 	  return MAILSTREAM_IDLE_INTERRUPTED;
477   }
478   else if (r == WAIT_OBJECT_0 + 2){
479 	  return MAILSTREAM_IDLE_CANCELLED;
480   }
481   DWORD i = GetLastError();
482   return MAILSTREAM_IDLE_ERROR;
483 #elif USE_POLL
484   pfd[0].fd = fd;
485   pfd[0].events = POLLIN;
486   pfd[0].revents = 0;
487 
488   pfd[1].fd = idle_fd;
489   pfd[1].events = POLLIN;
490   pfd[1].revents = 0;
491 
492   pfd[2].fd = cancel_fd;
493   pfd[2].events = POLLIN;
494   pfd[2].revents = 0;
495 
496   r = poll(&pfd[0], 3, max_idle_delay * 1000);
497 
498   if (r == 0){
499     // timeout
500     return MAILSTREAM_IDLE_TIMEOUT;
501   }
502   else if (r == -1) {
503     // do nothing
504     return MAILSTREAM_IDLE_ERROR;
505   }
506   else {
507     if (pfd[0].revents & POLLIN) {
508       // has something on socket
509       return MAILSTREAM_IDLE_HASDATA;
510     }
511     if (pfd[1].revents & POLLIN) {
512       // idle interrupted
513       mailstream_cancel_ack(idle);
514       return MAILSTREAM_IDLE_INTERRUPTED;
515     }
516     if (pfd[2].revents & POLLIN) {
517       // idle cancelled
518       mailstream_cancel_ack(mailstream_low_get_cancel(low));
519       return MAILSTREAM_IDLE_CANCELLED;
520     }
521     return MAILSTREAM_IDLE_ERROR;
522   }
523 #else
524   FD_ZERO(&readfds);
525   FD_SET(fd, &readfds);
526   FD_SET(idle_fd, &readfds);
527   FD_SET(cancel_fd, &readfds);
528   maxfd = fd;
529   if (idle_fd > maxfd) {
530     maxfd = idle_fd;
531   }
532   if (cancel_fd > maxfd) {
533     maxfd = cancel_fd;
534   }
535   struct timeval delay;
536   delay.tv_sec = max_idle_delay;
537   delay.tv_usec = 0;
538 
539   r = select(maxfd + 1, &readfds, NULL, NULL, &delay);
540   if (r == 0) {
541     // timeout
542     return MAILSTREAM_IDLE_TIMEOUT;
543   }
544   else if (r == -1) {
545     // do nothing
546     return MAILSTREAM_IDLE_ERROR;
547   }
548   else {
549     if (FD_ISSET(fd, &readfds)) {
550       // has something on socket
551       return MAILSTREAM_IDLE_HASDATA;
552     }
553     if (FD_ISSET(idle_fd, &readfds)) {
554       // idle interrupted
555       mailstream_cancel_ack(idle);
556       return MAILSTREAM_IDLE_INTERRUPTED;
557     }
558     if (FD_ISSET(cancel_fd, &readfds)) {
559       // idle cancelled
560       mailstream_cancel_ack(mailstream_low_get_cancel(low));
561       return MAILSTREAM_IDLE_CANCELLED;
562     }
563     return MAILSTREAM_IDLE_ERROR;
564   }
565 #endif
566 }
567 
mailstream_low_setup_idle(mailstream_low * low)568 int mailstream_low_setup_idle(mailstream_low * low)
569 {
570   if (low->driver->mailstream_setup_idle == NULL)
571     return -1;
572 
573   return low->driver->mailstream_setup_idle(low);
574 }
575 
mailstream_low_unsetup_idle(mailstream_low * low)576 int mailstream_low_unsetup_idle(mailstream_low * low)
577 {
578   if (low->driver->mailstream_unsetup_idle == NULL)
579     return -1;
580 
581   return low->driver->mailstream_unsetup_idle(low);
582 }
583 
mailstream_low_interrupt_idle(mailstream_low * low)584 int mailstream_low_interrupt_idle(mailstream_low * low)
585 {
586   if (low->driver->mailstream_interrupt_idle == NULL)
587     return -1;
588 
589   return low->driver->mailstream_interrupt_idle(low);
590 }
591 
592