diff --git a/configure b/configure index 256efd36..1fa15475 100755 --- a/configure +++ b/configure @@ -3425,7 +3425,7 @@ unrtf="no" have_static_build="no" -antispam_libs="-lz -lm -ldl -lcrypto" +antispam_libs="-lz -lm -ldl -lcrypto -lssl" defs="" objs="" user_obj="" @@ -3684,7 +3684,103 @@ fi fi ac_cv_lib_crypto=ac_cv_lib_crypto_main -if test "$have_crypto" = "no"; then +for ac_header in openssl/ssl.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_ssl_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENSSL_SSL_H 1 +_ACEOF + have_ssl=yes +else + have_ssl=no +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_write in -lssl" >&5 +$as_echo_n "checking for SSL_write in -lssl... " >&6; } +if ${ac_cv_lib_ssl_SSL_write+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char SSL_write (); +int +main () +{ +return SSL_write (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ssl_SSL_write=yes +else + ac_cv_lib_ssl_SSL_write=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_write" >&5 +$as_echo "$ac_cv_lib_ssl_SSL_write" >&6; } +if test "x$ac_cv_lib_ssl_SSL_write" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_write in -lssl" >&5 +$as_echo_n "checking for SSL_write in -lssl... " >&6; } +if ${ac_cv_lib_ssl_SSL_write+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char SSL_write (); +int +main () +{ +return SSL_write (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ssl_SSL_write=yes +else + ac_cv_lib_ssl_SSL_write=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_write" >&5 +$as_echo "$ac_cv_lib_ssl_SSL_write" >&6; } +if test "x$ac_cv_lib_ssl_SSL_write" = xyes; then : + have_ssl=yes +else + echo "libssl is not found"; have_ssl=no +fi + +fi +ac_cv_lib_ssl=ac_cv_lib_ssl_main + +if test "$have_crypto" = "no" || test "$have_ssl" = "no"; then echo "please install openssl developer package" exit 1 fi diff --git a/configure.in b/configure.in index fbba2230..70bd3f6b 100644 --- a/configure.in +++ b/configure.in @@ -51,7 +51,7 @@ unrtf="no" have_static_build="no" -antispam_libs="-lz -lm -ldl -lcrypto" +antispam_libs="-lz -lm -ldl -lcrypto -lssl" defs="" objs="" user_obj="" @@ -109,7 +109,10 @@ dnl openssl library AC_CHECK_HEADERS(openssl/sha.h, have_crypto=yes, have_crypto=no) AC_CHECK_LIB([crypto],[SHA256_Init],[AC_CHECK_LIB(crypto, SHA256_Init, have_crypto=yes, echo "libcrypto is not found"; have_crypto=no)],[],[])ac_cv_lib_crypto=ac_cv_lib_crypto_main -if test "$have_crypto" = "no"; then +AC_CHECK_HEADERS(openssl/ssl.h, have_ssl=yes, have_ssl=no) +AC_CHECK_LIB([ssl],[SSL_write],[AC_CHECK_LIB(ssl, SSL_write, have_ssl=yes, echo "libssl is not found"; have_ssl=no)],[],[])ac_cv_lib_ssl=ac_cv_lib_ssl_main + +if test "$have_crypto" = "no" || test "$have_ssl" = "no"; then echo "please install openssl developer package" exit 1 fi diff --git a/src/config.h b/src/config.h index 6b0f1e72..f8fd96e1 100644 --- a/src/config.h +++ b/src/config.h @@ -13,7 +13,7 @@ #define VERSION "0.1.21" -#define BUILD 717 +#define BUILD 719 #define HOSTID "mailarchiver" diff --git a/src/defs.h b/src/defs.h index 0751f168..2431cdb6 100644 --- a/src/defs.h +++ b/src/defs.h @@ -24,6 +24,7 @@ #endif #include +#include #include "tai.h" #include "config.h" @@ -247,6 +248,8 @@ struct __data { struct memcached_server memc; #endif + SSL_CTX *ctx; + SSL *ssl; }; diff --git a/src/imap.c b/src/imap.c index a5de15ba..fb27bb5e 100644 --- a/src/imap.c +++ b/src/imap.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,9 @@ #include +#define CHK_NULL(x, errmsg) if ((x)==NULL) { printf("error: %s\n", errmsg); return ERR; } +#define CHK_SSL(err, msg) if ((err)==-1) { printf("ssl error: %s\n", msg); return ERR; } + unsigned long resolve_host(char *host){ struct hostent *h; @@ -52,7 +56,8 @@ int get_message_length_from_imap_answer(char *s, int *_1st_line_bytes){ *p = '\0'; - *_1st_line_bytes = strlen(s)+2; + //*_1st_line_bytes = strlen(s)+2; + *_1st_line_bytes = p-s+2; if(*(p-1) == '}') *(p-1) = '\0'; @@ -88,16 +93,16 @@ int is_last_complete_packet(char *s, int len, char *tagok, char *tagbad, int *po } -int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sdata, struct __data *data, struct __config *cfg){ - int rc=ERR, i, n, pos, endpos, messages=0, len, readlen, fd, lastpos, nreads, nwrites, processed_messages=0; +int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sdata, struct __data *data, int use_ssl, struct __config *cfg){ + int rc=ERR, i, n, pos, endpos, messages=0, len, readlen, fd, lastpos, nreads, processed_messages=0; char *p, tag[SMALLBUFSIZE], tagok[SMALLBUFSIZE], tagbad[SMALLBUFSIZE], buf[MAXBUFSIZE], filename[SMALLBUFSIZE]; char aggrbuf[3*MAXBUFSIZE]; snprintf(tag, sizeof(tag)-1, "A%d", *seq); snprintf(tagok, sizeof(tagok)-1, "\r\nA%d OK", (*seq)++); snprintf(buf, sizeof(buf)-1, "%s SELECT \"%s\"\r\n", tag, folder); - send(sd, buf, strlen(buf), 0); - n = recvtimeout(sd, buf, MAXBUFSIZE, 10); + n = write1(sd, buf, use_ssl, data->ssl); + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); if(!strstr(buf, tagok)){ trimBuffer(buf); @@ -139,20 +144,19 @@ int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sda } - send(sd, buf, strlen(buf), 0); + n = write1(sd, buf, use_ssl, data->ssl); readlen = 0; pos = 0; len = 0; nreads = 0; - nwrites = 0; endpos = 0; memset(aggrbuf, 0, sizeof(aggrbuf)); lastpos = 0; - while((n = recvtimeout(sd, buf, sizeof(buf), 15)) > 0){ + while((n = recvtimeoutssl(sd, buf, sizeof(buf), 15, use_ssl, data->ssl)) > 0){ nreads++; readlen += n; @@ -165,45 +169,33 @@ int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sda } } - if(lastpos + n + sizeof(buf) > sizeof(aggrbuf)){ - nwrites++; + if(lastpos + 1 + n < sizeof(aggrbuf)){ - if(nwrites == 1) - write(fd, aggrbuf+pos, lastpos-pos); - else - write(fd, aggrbuf, lastpos); - - memset(aggrbuf, 0, sizeof(aggrbuf)); - lastpos = 0; - } - - memcpy(aggrbuf+lastpos, buf, n); - lastpos += n; - - if(is_last_complete_packet(aggrbuf, lastpos, tagok, tagbad, &endpos) == 1){ - nwrites++; - if(nwrites == 1) - write(fd, aggrbuf+pos, lastpos-(lastpos-endpos)-pos); - else - write(fd, aggrbuf, lastpos-(lastpos-endpos)); - - break; - } - else { - nwrites++; - if(nwrites == 1){ - if(lastpos-n-pos > 0) write(fd, aggrbuf+pos, lastpos-n-pos); else nwrites--; + if(nreads == 1){ + memcpy(aggrbuf+lastpos, buf+pos, n-pos); + lastpos += n-pos; } else { - write(fd, aggrbuf, lastpos-n); + memcpy(aggrbuf+lastpos, buf, n); + lastpos += n; } - - memmove(aggrbuf, aggrbuf+lastpos-n, n); - lastpos = n; - memset(aggrbuf+lastpos, 0, sizeof(aggrbuf)-lastpos); } - } + else { + write(fd, aggrbuf, sizeof(buf)); + memmove(aggrbuf, aggrbuf+sizeof(buf), lastpos-sizeof(buf)); + lastpos -= sizeof(buf); + + memcpy(aggrbuf+lastpos, buf, n); + lastpos += n; + } + + if(is_last_complete_packet(aggrbuf, lastpos, tagok, tagbad, &endpos) == 1){ + write(fd, aggrbuf, lastpos-(lastpos-endpos)); + break; + } + + } close(fd); @@ -218,29 +210,69 @@ int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sda } -int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, char *password){ +int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, char *password, int port, struct __data *data, int use_ssl){ int n, pos=0; char tag[SMALLBUFSIZE], tagok[SMALLBUFSIZE], buf[MAXBUFSIZE]; char auth[2*SMALLBUFSIZE]; unsigned char tmp[SMALLBUFSIZE]; unsigned long host=0; struct sockaddr_in remote_addr; + X509* server_cert; + SSL_METHOD *meth; + char *str; host = resolve_host(imapserver); remote_addr.sin_family = AF_INET; - remote_addr.sin_port = htons(143); + remote_addr.sin_port = htons(port); remote_addr.sin_addr.s_addr = host; bzero(&(remote_addr.sin_zero),8); - if(connect(sd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1){ printf("connect()\n"); return ERR; } - n = recvtimeout(sd, buf, MAXBUFSIZE, 10); + + if(use_ssl == 1){ + + SSLeay_add_ssl_algorithms(); + meth = SSLv3_client_method(); + SSL_load_error_strings(); + + data->ctx = SSL_CTX_new(meth); + CHK_NULL(data->ctx, "internal SSL error"); + + data->ssl = SSL_new(data->ctx); + CHK_NULL(data->ssl, "internal ssl error"); + + SSL_set_fd(data->ssl, sd); + n = SSL_connect(data->ssl); + CHK_SSL(n, "internal ssl error"); + + //printf("Cipher: %s\n", SSL_get_cipher(data->ssl)); + + server_cert = SSL_get_peer_certificate(data->ssl); + CHK_NULL(server_cert, "server cert error"); + + //if(verbose){ + str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0); + CHK_NULL(str, "error in server cert"); + printf("server cert:\n\t subject: %s\n", str); + OPENSSL_free(str); + + str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0); + CHK_NULL(str, "error in server cert"); + printf("\t issuer: %s\n\n", str); + OPENSSL_free(str); + //} + + X509_free(server_cert); + } + + + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); /* @@ -262,8 +294,10 @@ int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, c snprintf(tag, sizeof(tag)-1, "A%d", *seq); snprintf(tagok, sizeof(tagok)-1, "A%d OK", (*seq)++); snprintf(buf, sizeof(buf)-1, "%s AUTHENTICATE PLAIN %s\r\n", tag, auth); - send(sd, buf, strlen(buf), 0); - n = recvtimeout(sd, buf, MAXBUFSIZE, 10); + + write1(sd, buf, use_ssl, data->ssl); + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); + if(strncmp(buf, tagok, strlen(tagok))){ printf("login failed, server reponse: %s\n", buf); return ERR; @@ -273,7 +307,18 @@ int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, c } -int list_folders(int sd, int *seq, char *folders, int foldersize){ +void close_connection(int sd, struct __data *data, int use_ssl){ + close(sd); + + if(use_ssl == 1){ + SSL_shutdown(data->ssl); + SSL_free(data->ssl); + SSL_CTX_free(data->ctx); + } +} + + +int list_folders(int sd, int *seq, char *folders, int foldersize, int use_ssl, struct __data *data){ int n; char *p, *q, tag[SMALLBUFSIZE], tagok[SMALLBUFSIZE], buf[MAXBUFSIZE], puf[MAXBUFSIZE]; @@ -281,9 +326,9 @@ int list_folders(int sd, int *seq, char *folders, int foldersize){ //snprintf(buf, sizeof(buf)-1, "%s LIST \"\" %%\r\n", tag); snprintf(buf, sizeof(buf)-1, "%s LIST \"\" \"*\"\r\n", tag); - send(sd, buf, strlen(buf), 0); + write1(sd, buf, use_ssl, data->ssl); - n = recvtimeout(sd, buf, MAXBUFSIZE, 10); + n = recvtimeoutssl(sd, buf, sizeof(buf), 10, use_ssl, data->ssl); p = &buf[0]; do { diff --git a/src/misc.c b/src/misc.c index 5e444ce1..bc44d5e0 100644 --- a/src/misc.c +++ b/src/misc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "misc.h" #include "smtpcodes.h" #include "errmsg.h" @@ -293,7 +294,7 @@ int recvtimeout(int s, char *buf, int len, int timeout){ int n; struct timeval tv; - memset(buf, 0, MAXBUFSIZE); + memset(buf, 0, len); FD_ZERO(&fds); FD_SET(s, &fds); @@ -309,6 +310,31 @@ int recvtimeout(int s, char *buf, int len, int timeout){ } +int write1(int sd, char *buf, int use_ssl, SSL *ssl){ + int n; + + if(use_ssl == 1) + n = SSL_write(ssl, buf, strlen(buf)); + else + n = send(sd, buf, strlen(buf), 0); + + return n; +} + + +int recvtimeoutssl(int s, char *buf, int len, int timeout, int use_ssl, SSL *ssl){ + + memset(buf, 0, len); + + if(use_ssl == 1){ + return SSL_read(ssl, buf, len-1); + } + else { + return recvtimeout(s, buf, len-1, timeout); + } +} + + /* * is it a valid dotted IPv4 address */ diff --git a/src/misc.h b/src/misc.h index 483b372e..3798a9cc 100644 --- a/src/misc.h +++ b/src/misc.h @@ -5,6 +5,7 @@ #ifndef _MISC_H #define _MISC_H +#include #include #include #include @@ -24,6 +25,8 @@ void create_id(char *id); int get_random_bytes(unsigned char *buf, int len); int readFromEntropyPool(int fd, void *_s, size_t n); int recvtimeout(int s, char *buf, int len, int timeout); +int write1(int sd, char *buf, int use_ssl, SSL *ssl); +int recvtimeoutssl(int s, char *buf, int len, int timeout, int use_ssl, SSL *ssl); void write_pid_file(char *pidfile); int drop_privileges(struct passwd *pwd); diff --git a/src/pilerimport.c b/src/pilerimport.c index ec2d427e..ac606aea 100644 --- a/src/pilerimport.c +++ b/src/pilerimport.c @@ -31,9 +31,10 @@ int quiet=0; int remove_after_successful_import = 0; -int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, char *password); -int list_folders(int sd, int *seq, char *folders, int foldersize); -int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sdata, struct __data *data, struct __config *cfg); +int connect_to_imap_server(int sd, int *seq, char *imapserver, char *username, char *password, int port, struct __data *data, int use_ssl); +void close_connection(int sd, struct __data *data, int use_ssl); +int list_folders(int sd, int *seq, char *folders, int foldersize, int use_ssl, struct __data *data); +int process_imap_folder(int sd, int *seq, char *folder, struct session_data *sdata, struct __data *data, int use_ssl, struct __config *cfg); int import_from_mailbox(char *mailbox, struct session_data *sdata, struct __data *data, struct __config *cfg){ @@ -236,24 +237,28 @@ int import_from_maildir(char *directory, struct session_data *sdata, struct __da } -int import_from_imap_server(char *imapserver, char *username, char *password, struct session_data *sdata, struct __data *data, char *skiplist, struct __config *cfg){ - int rc=ERR, ret=OK, sd, seq=1, skipmatch; +int import_from_imap_server(char *imapserver, char *username, char *password, int port, struct session_data *sdata, struct __data *data, char *skiplist, struct __config *cfg){ + int rc=ERR, ret=OK, sd, seq=1, skipmatch, use_ssl=0; char *p, puf[SMALLBUFSIZE]; char *q, muf[SMALLBUFSIZE]; char folders[MAXBUFSIZE]; + + if(port == 993) use_ssl = 1; + + if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ printf("cannot create socket\n"); return ERR; } - if(connect_to_imap_server(sd, &seq, imapserver, username, password) == ERR){ + if(connect_to_imap_server(sd, &seq, imapserver, username, password, port, data, use_ssl) == ERR){ close(sd); return ERR; } - list_folders(sd, &seq, &folders[0], sizeof(folders)); + list_folders(sd, &seq, &folders[0], sizeof(folders), use_ssl, data); p = &folders[0]; @@ -284,26 +289,26 @@ int import_from_imap_server(char *imapserver, char *username, char *password, st if(quiet == 0) printf("processing folder: %s... ", puf); - rc = process_imap_folder(sd, &seq, puf, sdata, data, cfg); + rc = process_imap_folder(sd, &seq, puf, sdata, data, use_ssl, cfg); if(rc == ERR) ret = ERR; } while(p); - close(sd); + close_connection(sd, data, use_ssl); return ret; } void usage(){ - printf("usage: pilerimport [-c ] -e | -m | -d | -i -u -p [-F ] [-R] [-r] [-q]\n"); + printf("usage: pilerimport [-c ] -e | -m | -d | -i -u -p -P [-F ] [-R] [-r] [-q]\n"); exit(0); } int main(int argc, char **argv){ - int i, c, rc=0, n_mbox=0, tot_msgs=0; + int i, c, rc=0, n_mbox=0, tot_msgs=0, port=143; char *configfile=CONFIG_FILE, *emlfile=NULL, *mboxdir=NULL, *mbox[MBOX_ARGS], *directory=NULL; char *imapserver=NULL, *username=NULL, *password=NULL, *skiplist=SKIPLIST, *folder=NULL; struct session_data sdata; @@ -330,6 +335,7 @@ int main(int argc, char **argv){ {"imapserver", required_argument, 0, 'i' }, {"username", required_argument, 0, 'u' }, {"password", required_argument, 0, 'p' }, + {"port", required_argument, 0, 'P' }, {"skiplist", required_argument, 0, 'x' }, {"folder", required_argument, 0, 'F' }, {"quiet", required_argument, 0, 'q' }, @@ -341,9 +347,9 @@ int main(int argc, char **argv){ int option_index = 0; - c = getopt_long(argc, argv, "c:m:M:e:d:i:u:p:x:F:Rrqh?", long_options, &option_index); + c = getopt_long(argc, argv, "c:m:M:e:d:i:u:p:P:x:F:Rrqh?", long_options, &option_index); #else - c = getopt(argc, argv, "c:m:M:e:d:i:u:p:x:F:Rrqh?"); + c = getopt(argc, argv, "c:m:M:e:d:i:u:p:P:x:F:Rrqh?"); #endif if(c == -1) break; @@ -387,6 +393,10 @@ int main(int argc, char **argv){ password = optarg; break; + case 'P' : + port = atoi(optarg); + break; + case 'x' : skiplist = optarg; break; @@ -470,7 +480,7 @@ int main(int argc, char **argv){ } if(mboxdir) rc = import_mbox_from_dir(mboxdir, &sdata, &data, &tot_msgs, &cfg); if(directory) rc = import_from_maildir(directory, &sdata, &data, &tot_msgs, &cfg); - if(imapserver && username && password) rc = import_from_imap_server(imapserver, username, password, &sdata, &data, skiplist, &cfg); + if(imapserver && username && password) rc = import_from_imap_server(imapserver, username, password, port, &sdata, &data, skiplist, &cfg); free_rule(data.archiving_rules);