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);