Mercurial > hg
comparison mcabber/connwrap/connwrap.c @ 1253:eb38963e082f
Add gnutls suppport
This is based on the patch from Anibal Avelar for center{icq,im}.
author | Mikael Berthe <mikael@lilotux.net> |
---|---|
date | Fri, 22 Jun 2007 19:18:44 +0200 |
parents | 3225a1ba050d |
children | 3bd496b9a9f7 |
comparison
equal
deleted
inserted
replaced
1252:9f7e6c22cd14 | 1253:eb38963e082f |
---|---|
13 | 13 |
14 #define PROXY_TIMEOUT 10 | 14 #define PROXY_TIMEOUT 10 |
15 // HTTP proxy timeout in seconds (for the CONNECT method) | 15 // HTTP proxy timeout in seconds (for the CONNECT method) |
16 | 16 |
17 #ifdef HAVE_OPENSSL | 17 #ifdef HAVE_OPENSSL |
18 | 18 # define OPENSSL_NO_KRB5 1 |
19 #define OPENSSL_NO_KRB5 1 | 19 # include <openssl/ssl.h> |
20 #include <openssl/ssl.h> | 20 # include <openssl/err.h> |
21 #include <openssl/err.h> | 21 # define HAVE_SSL |
22 | 22 # undef HAVE_GNUTLS // Can't use both... |
23 #else | 23 #elif defined HAVE_GNUTLS |
24 # ifdef HAVE_GNUTLS | 24 # include <gnutls/gnutls.h> |
25 # include <gnutls/openssl.h> | 25 # define HAVE_SSL |
26 # define HAVE_OPENSSL | |
27 # endif | |
28 #endif | 26 #endif |
29 | 27 |
30 static int in_http_connect = 0; | 28 static int in_http_connect = 0; |
31 | 29 |
32 #ifdef HAVE_OPENSSL | 30 #ifdef HAVE_OPENSSL |
33 | 31 static SSL_CTX *ctx = NULL; |
34 static SSL_CTX *ctx = 0; | 32 typedef struct { int fd; SSL *ssl; } sslsock; |
33 #elif defined HAVE_GNUTLS | |
34 typedef struct { int fd; gnutls_session_t session; } sslsock; | |
35 #endif | |
36 | |
37 | |
38 #ifdef HAVE_SSL | |
35 | 39 |
36 /* verify > 0 indicates verify depth as well */ | 40 /* verify > 0 indicates verify depth as well */ |
37 static int verify = -1; | 41 static int verify = -1; |
38 static const char *cafile = NULL; | 42 static const char *cafile = NULL; |
39 static const char *capath = NULL; | 43 static const char *capath = NULL; |
40 static const char *cipherlist = NULL; | 44 static const char *cipherlist = NULL; |
41 static const char *peer = NULL; | 45 static const char *peer = NULL; |
42 static const char *sslerror = NULL; | 46 static const char *sslerror = NULL; |
43 | 47 |
48 #ifdef HAVE_OPENSSL | |
44 static int verify_cb(int preverify_ok, X509_STORE_CTX *cx) | 49 static int verify_cb(int preverify_ok, X509_STORE_CTX *cx) |
45 { | 50 { |
46 X509 *cert; | 51 X509 *cert; |
47 X509_NAME *nm; | 52 X509_NAME *nm; |
48 int lastpos; | 53 int lastpos; |
101 } | 106 } |
102 | 107 |
103 sslerror = "server certificate cn mismatch"; | 108 sslerror = "server certificate cn mismatch"; |
104 return 0; | 109 return 0; |
105 } | 110 } |
106 | 111 #endif |
107 static void init(void) { | 112 |
113 static void init(int fd, sslsock *p) { | |
114 #ifdef HAVE_GNUTLS | |
115 gnutls_certificate_credentials_t xcred; | |
116 #endif | |
117 | |
118 #ifdef HAVE_OPENSSL | |
108 if(ctx) | 119 if(ctx) |
109 return; | 120 return; |
110 | |
111 SSL_library_init(); | 121 SSL_library_init(); |
112 SSL_load_error_strings(); | 122 SSL_load_error_strings(); |
113 | 123 |
114 #ifdef HAVE_SSLEAY | 124 #ifdef HAVE_SSLEAY |
115 SSLeay_add_all_algorithms(); | 125 SSLeay_add_all_algorithms(); |
117 OpenSSL_add_all_algorithms(); | 127 OpenSSL_add_all_algorithms(); |
118 #endif | 128 #endif |
119 | 129 |
120 /* May need to use distinct SSLEAY bindings below... */ | 130 /* May need to use distinct SSLEAY bindings below... */ |
121 | 131 |
122 //ctx = SSL_CTX_new(SSLv23_method()); | |
123 ctx = SSL_CTX_new(SSLv23_client_method()); | 132 ctx = SSL_CTX_new(SSLv23_client_method()); |
124 if(cipherlist) | 133 if(cipherlist) |
125 (void)SSL_CTX_set_cipher_list(ctx, cipherlist); | 134 (void)SSL_CTX_set_cipher_list(ctx, cipherlist); |
126 if(cafile || capath) | 135 if(cafile || capath) |
127 (void)SSL_CTX_load_verify_locations(ctx, cafile, capath); | 136 (void)SSL_CTX_load_verify_locations(ctx, cafile, capath); |
129 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); | 138 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); |
130 if(verify > 0) | 139 if(verify > 0) |
131 SSL_CTX_set_verify_depth(ctx, verify); | 140 SSL_CTX_set_verify_depth(ctx, verify); |
132 } else | 141 } else |
133 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); | 142 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); |
134 } | 143 |
135 | 144 p->ssl = SSL_new(ctx); |
136 typedef struct { int fd; SSL *ssl; } sslsock; | 145 SSL_set_fd(p->ssl, p->fd = fd); |
137 | 146 |
138 static sslsock *socks = 0; | 147 #elif defined HAVE_GNUTLS |
148 gnutls_global_init(); | |
149 gnutls_certificate_allocate_credentials(&xcred); | |
150 gnutls_init(&(p->session), GNUTLS_CLIENT); | |
151 gnutls_set_default_priority(p->session); | |
152 gnutls_credentials_set(p->session, GNUTLS_CRD_CERTIFICATE, xcred); | |
153 p->fd = fd; | |
154 gnutls_transport_set_ptr(p->session,(gnutls_transport_ptr_t)fd); | |
155 #endif | |
156 } | |
157 | |
158 static sslsock *socks = NULL; | |
139 static int sockcount = 0; | 159 static int sockcount = 0; |
140 | 160 |
141 static sslsock *getsock(int fd) { | 161 static sslsock *getsock(int fd) { |
142 int i; | 162 int i; |
143 | 163 |
144 for(i = 0; i < sockcount; i++) | 164 for(i = 0; i < sockcount; i++) |
145 if(socks[i].fd == fd) | 165 if(socks[i].fd == fd) |
146 return &socks[i]; | 166 return &socks[i]; |
147 | 167 |
148 return 0; | 168 return NULL; |
149 } | 169 } |
150 | 170 |
151 static sslsock *addsock(int fd) { | 171 static sslsock *addsock(int fd) { |
152 sslsock *p; | 172 sslsock *p; |
153 | 173 |
174 sockcount++; | |
175 | |
154 if (socks) | 176 if (socks) |
155 socks = (sslsock *) realloc(socks, sizeof(sslsock)*++sockcount); | 177 socks = (sslsock *) realloc(socks, sizeof(sslsock)*sockcount); |
156 else | 178 else |
157 socks = (sslsock *) malloc(sizeof(sslsock)*++sockcount); | 179 socks = (sslsock *) malloc(sizeof(sslsock)*sockcount); |
158 | 180 |
159 p = &socks[sockcount-1]; | 181 p = &socks[sockcount-1]; |
160 | 182 |
161 init (); | 183 init(fd, p); |
162 | 184 |
163 p->ssl = SSL_new(ctx); | |
164 SSL_set_fd(p->ssl, p->fd = fd); | |
165 sslerror = NULL; | 185 sslerror = NULL; |
166 | 186 |
167 return p; | 187 return p; |
168 } | 188 } |
169 | 189 |
178 | 198 |
179 for(i = 0; i < sockcount; i++) { | 199 for(i = 0; i < sockcount; i++) { |
180 if(socks[i].fd != fd) { | 200 if(socks[i].fd != fd) { |
181 nsocks[nsockcount++] = socks[i]; | 201 nsocks[nsockcount++] = socks[i]; |
182 } else { | 202 } else { |
203 #ifdef HAVE_OPENSSL | |
183 SSL_free(socks[i].ssl); | 204 SSL_free(socks[i].ssl); |
205 #elif defined HAVE_GNUTLS | |
206 gnutls_bye(socks[i].session, GNUTLS_SHUT_WR); | |
207 gnutls_deinit(socks[i].session); | |
208 #endif | |
184 } | 209 } |
185 } | 210 } |
186 | 211 |
187 } else { | 212 } else { |
213 #ifdef HAVE_OPENSSL | |
188 if (ctx) | 214 if (ctx) |
189 SSL_CTX_free(ctx); | 215 SSL_CTX_free(ctx); |
190 ctx = 0; | 216 ctx = 0; |
191 nsocks = 0; | 217 #endif |
218 nsocks = NULL; | |
192 } | 219 } |
193 | 220 |
194 if (socks) | 221 if (socks) |
195 free(socks); | 222 free(socks); |
196 socks = nsocks; | 223 socks = nsocks; |
197 sockcount = nsockcount; | 224 sockcount = nsockcount; |
198 } | 225 } |
199 | 226 |
200 void cw_set_ssl_options(int sslverify, const char *sslcafile, const char *sslcapath, const char *sslciphers, const char *sslpeer) { | 227 void cw_set_ssl_options(int sslverify, |
228 const char *sslcafile, const char *sslcapath, | |
229 const char *sslciphers, const char *sslpeer) { | |
201 verify = sslverify; | 230 verify = sslverify; |
202 cafile = sslcafile; | 231 cafile = sslcafile; |
203 capath = sslcapath; | 232 capath = sslcapath; |
204 cipherlist = sslciphers; | 233 cipherlist = sslciphers; |
205 peer = sslpeer; | 234 peer = sslpeer; |
207 | 236 |
208 const char *cw_get_ssl_error(void) { | 237 const char *cw_get_ssl_error(void) { |
209 return sslerror; | 238 return sslerror; |
210 } | 239 } |
211 | 240 |
212 #else | 241 #else // HAVE_SSL |
213 | 242 |
214 void cw_set_ssl_options(int sslverify, const char *sslcafile, const char *sslcapath, const char *sslciphers, const char *sslpeer) { } | 243 void cw_set_ssl_options(int sslverify, |
244 const char *sslcafile, const char *sslcapath, | |
245 const char *sslciphers, const char *sslpeer) { } | |
215 | 246 |
216 const char *cw_get_ssl_error(void) { | 247 const char *cw_get_ssl_error(void) { |
217 return NULL; | 248 return NULL; |
218 } | 249 } |
219 | 250 |
220 #endif | 251 #endif // HAVE_SSL |
221 | 252 |
222 static char *bindaddr = 0, *proxyhost = 0, *proxyuser = 0, *proxypass = 0; | 253 static char *bindaddr = 0, *proxyhost = 0, *proxyuser = 0, *proxypass = 0; |
223 static int proxyport = 3128; | 254 static int proxyport = 3128; |
224 static int proxy_ssl = 0; | 255 static int proxy_ssl = 0; |
225 | 256 |
250 fl = fcntl(sockfd, F_GETFL); | 281 fl = fcntl(sockfd, F_GETFL); |
251 fcntl(sockfd, F_SETFL, fl & ~O_NONBLOCK); | 282 fcntl(sockfd, F_SETFL, fl & ~O_NONBLOCK); |
252 | 283 |
253 buf[0] = 0; | 284 buf[0] = 0; |
254 | 285 |
255 err = cw_connect(sockfd, (struct sockaddr *) &paddr, sizeof(paddr), proxy_ssl); | 286 err = cw_connect(sockfd, (struct sockaddr *) &paddr, sizeof(paddr), |
287 proxy_ssl); | |
256 } | 288 } |
257 | 289 |
258 errno = ECONNREFUSED; | 290 errno = ECONNREFUSED; |
259 | 291 |
260 if(!err) { | 292 if(!err) { |
332 in_http_connect = 0; | 364 in_http_connect = 0; |
333 | 365 |
334 return err; | 366 return err; |
335 } | 367 } |
336 | 368 |
337 int cw_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, int ssl) { | 369 int cw_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, |
370 int ssl) { | |
338 int rc; | 371 int rc; |
339 struct sockaddr_in ba; | 372 struct sockaddr_in ba; |
340 | 373 |
341 if(bindaddr) | 374 if(bindaddr) |
342 if(strlen(bindaddr)) { | 375 if(strlen(bindaddr)) { |
356 } | 389 } |
357 | 390 |
358 if(rc) return rc; | 391 if(rc) return rc; |
359 } | 392 } |
360 | 393 |
361 if(proxyhost && !in_http_connect) rc = cw_http_connect(sockfd, serv_addr, addrlen); | 394 if(proxyhost && !in_http_connect) |
362 else rc = connect(sockfd, serv_addr, addrlen); | 395 rc = cw_http_connect(sockfd, serv_addr, addrlen); |
396 else | |
397 rc = connect(sockfd, serv_addr, addrlen); | |
363 | 398 |
364 #ifdef HAVE_OPENSSL | 399 #ifdef HAVE_OPENSSL |
365 if(ssl && !rc) { | 400 if(ssl && !rc) { |
366 sslsock *p = addsock(sockfd); | 401 sslsock *p = addsock(sockfd); |
367 if(SSL_connect(p->ssl) != 1) | 402 if(SSL_connect(p->ssl) != 1) |
368 return -1; | 403 return -1; // XXX "Can't connect to SSL" |
369 } | 404 } |
370 #endif | 405 #endif |
371 | 406 |
372 return rc; | 407 return rc; |
373 } | 408 } |
374 | 409 |
375 int cw_nb_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, int ssl, int *state) { | 410 int cw_nb_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, |
411 int ssl, int *state) { | |
376 int rc = 0; | 412 int rc = 0; |
377 struct sockaddr_in ba; | 413 struct sockaddr_in ba; |
378 | 414 |
379 if(bindaddr) | 415 if(bindaddr) |
380 if(strlen(bindaddr)) { | 416 if(strlen(bindaddr)) { |
394 } | 430 } |
395 | 431 |
396 if(rc) return rc; | 432 if(rc) return rc; |
397 } | 433 } |
398 | 434 |
399 #ifdef HAVE_OPENSSL | 435 #ifdef HAVE_SSL |
400 if(ssl) { | 436 if(ssl) { |
401 if ( !(*state & CW_CONNECT_WANT_SOMETHING)) | 437 if ( !(*state & CW_CONNECT_WANT_SOMETHING)) { |
402 rc = cw_connect(sockfd, serv_addr, addrlen, 0); | 438 rc = cw_connect(sockfd, serv_addr, addrlen, 0); |
403 else{ /* check if the socket is connected correctly */ | 439 } else { /* check if the socket is connected correctly */ |
404 int optlen = sizeof(int), optval; | 440 int optlen = sizeof(int), optval; |
405 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, (socklen_t*)&optlen) || optval) | 441 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, |
406 return -1; | 442 (socklen_t*)&optlen) || optval) |
443 return -1; | |
407 } | 444 } |
408 | 445 |
409 if(!rc) { | 446 if(!rc) { |
447 #ifdef HAVE_GNUTLS | |
448 int ret; | |
449 #endif | |
410 sslsock *p; | 450 sslsock *p; |
411 if (*state & CW_CONNECT_SSL) | 451 if (*state & CW_CONNECT_SSL) |
412 p = getsock(sockfd); | 452 p = getsock(sockfd); |
413 else | 453 else |
414 p = addsock(sockfd); | 454 p = addsock(sockfd); |
415 | 455 |
456 #ifdef HAVE_GNUTLS | |
457 do { | |
458 ret = gnutls_handshake(p->session); | |
459 } while ((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)); | |
460 if (ret < 0) { | |
461 gnutls_deinit(p->session); | |
462 gnutls_perror(ret); | |
463 return -1; | |
464 } | |
465 else{ | |
466 *state = 1; | |
467 return 0; | |
468 } | |
469 #elif defined HAVE_OPENSSL | |
416 rc = SSL_connect(p->ssl); | 470 rc = SSL_connect(p->ssl); |
417 switch(rc){ | 471 switch(rc){ |
418 case 1: | 472 case 1: |
419 *state = 0; | 473 *state = 0; |
420 return 0; | 474 return 0; |
430 return 0; | 484 return 0; |
431 default: | 485 default: |
432 return -1; | 486 return -1; |
433 } | 487 } |
434 } | 488 } |
435 } | 489 #endif |
436 else{ /* catch EINPROGRESS error from the connect call */ | 490 } else { /* catch EINPROGRESS error from the connect call */ |
437 if (errno == EINPROGRESS){ | 491 if (errno == EINPROGRESS){ |
438 *state = CW_CONNECT_STARTED | CW_CONNECT_WANT_WRITE; | 492 *state = CW_CONNECT_STARTED | CW_CONNECT_WANT_WRITE; |
439 return 0; | 493 return 0; |
440 } | 494 } |
441 } | 495 } |
442 | 496 |
443 return rc; | 497 return rc; |
444 } | 498 } |
445 #endif | 499 #endif |
446 if ( !(*state & CW_CONNECT_WANT_SOMETHING)) | 500 if ( !(*state & CW_CONNECT_WANT_SOMETHING)) { |
447 rc = connect(sockfd, serv_addr, addrlen); | 501 rc = connect(sockfd, serv_addr, addrlen); |
448 else{ /* check if the socket is connected correctly */ | 502 } else { /* check if the socket is connected correctly */ |
449 int optlen = sizeof(int), optval; | 503 int optlen = sizeof(int), optval; |
450 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, (socklen_t*)&optlen) || optval) | 504 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, |
505 (socklen_t*)&optlen) || optval) | |
451 return -1; | 506 return -1; |
452 *state = 0; | 507 *state = 0; |
453 return 0; | 508 return 0; |
454 } | 509 } |
455 if (rc) | 510 if (rc) |
469 | 524 |
470 if(!rc) { | 525 if(!rc) { |
471 sslsock *p = addsock(s); | 526 sslsock *p = addsock(s); |
472 if(SSL_accept(p->ssl) != 1) | 527 if(SSL_accept(p->ssl) != 1) |
473 return -1; | 528 return -1; |
474 | 529 } |
475 } | |
476 | |
477 return rc; | 530 return rc; |
478 } | 531 } |
479 #endif | 532 #endif |
480 return accept(s, addr, (socklen_t*)addrlen); | 533 return accept(s, addr, (socklen_t*)addrlen); |
481 } | 534 } |
482 | 535 |
483 int cw_write(int fd, const void *buf, int count, int ssl) { | 536 int cw_write(int fd, const void *buf, int count, int ssl) { |
484 #ifdef HAVE_OPENSSL | 537 #ifdef HAVE_SSL |
485 sslsock *p; | 538 sslsock *p; |
486 | 539 |
487 if(ssl) | 540 if(ssl) { |
488 if((p = getsock(fd)) != NULL) | 541 #ifdef HAVE_GNUTLS |
489 return SSL_write(p->ssl, buf, count); | 542 p = getsock(fd); |
490 #endif | 543 if(p) { |
544 int ret; | |
545 if((ret = gnutls_record_send( p->session, buf, count) < 0)) | |
546 fprintf(stderr, "Can't write to server"); | |
547 return ret; | |
548 } | |
549 #elif defined HAVE_OPENSSL | |
550 if((p = getsock(fd)) != NULL) | |
551 return SSL_write(p->ssl, buf, count); | |
552 #endif | |
553 } | |
554 #endif // HAVE_SSL | |
491 return write(fd, buf, count); | 555 return write(fd, buf, count); |
492 } | 556 } |
493 | 557 |
494 int cw_read(int fd, void *buf, int count, int ssl) { | 558 int cw_read(int fd, void *buf, int count, int ssl) { |
495 #ifdef HAVE_OPENSSL | 559 #ifdef HAVE_SSL |
496 sslsock *p; | 560 sslsock *p; |
497 | 561 |
498 if(ssl) | 562 if(ssl) { |
499 if((p = getsock(fd)) != NULL) | 563 #ifdef HAVE_GNUTLS |
500 return SSL_read(p->ssl, buf, count); | 564 p = getsock(fd); |
501 #endif | 565 if(p) { |
566 int ret; | |
567 do { | |
568 ret = gnutls_record_recv(p->session, buf, count); | |
569 } while (ret < 0 && | |
570 (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)); | |
571 return ret; | |
572 } | |
573 #elif defined HAVE_OPENSSL | |
574 if((p = getsock(fd)) != NULL) | |
575 return SSL_read(p->ssl, buf, count); | |
576 #endif | |
577 } | |
578 #endif // HAVE_SSL | |
502 return read(fd, buf, count); | 579 return read(fd, buf, count); |
503 } | 580 } |
504 | 581 |
505 void cw_close(int fd) { | 582 void cw_close(int fd) { |
506 #ifdef HAVE_OPENSSL | 583 #ifdef HAVE_SSL |
507 delsock(fd); | 584 delsock(fd); |
508 #endif | 585 #endif |
509 close(fd); | 586 close(fd); |
510 } | 587 } |
511 | 588 |
514 void cw_setbind(const char *abindaddr) { | 591 void cw_setbind(const char *abindaddr) { |
515 FREEVAR(bindaddr); | 592 FREEVAR(bindaddr); |
516 bindaddr = strdup(abindaddr); | 593 bindaddr = strdup(abindaddr); |
517 } | 594 } |
518 | 595 |
519 void cw_setproxy(const char *aproxyhost, int aproxyport, const char *aproxyuser, const char *aproxypass) { | 596 void cw_setproxy(const char *aproxyhost, int aproxyport, |
597 const char *aproxyuser, const char *aproxypass) { | |
520 FREEVAR(proxyhost); | 598 FREEVAR(proxyhost); |
521 FREEVAR(proxyuser); | 599 FREEVAR(proxyuser); |
522 FREEVAR(proxypass); | 600 FREEVAR(proxypass); |
523 | 601 |
524 if(aproxyhost && strlen(aproxyhost)) proxyhost = strdup(aproxyhost); | 602 if(aproxyhost && strlen(aproxyhost)) proxyhost = strdup(aproxyhost); |