#include "asterisk.h"
#include <signal.h>
#include <sys/signal.h>
#include "asterisk/compat.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/utils.h"
#include "asterisk/strings.h"
#include "asterisk/options.h"
#include "asterisk/manager.h"
#include "asterisk/astobj2.h"

Go to the source code of this file.
Functions | |
| static int | __ssl_setup (struct ast_tls_config *cfg, int client) |
| int | ast_ssl_setup (struct ast_tls_config *cfg) |
| struct ast_tcptls_session_instance * | ast_tcptls_client_create (struct ast_tcptls_session_args *desc) |
| struct ast_tcptls_session_instance * | ast_tcptls_client_start (struct ast_tcptls_session_instance *tcptls_session) |
| attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned. | |
| void | ast_tcptls_close_session_file (struct ast_tcptls_session_instance *tcptls_session) |
| Closes a tcptls session instance's file and/or file descriptor. The tcptls_session will be set to NULL and it's file descriptor will be set to -1 by this function. | |
| HOOK_T | ast_tcptls_server_read (struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count) |
| replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging. | |
| void * | ast_tcptls_server_root (void *data) |
| void | ast_tcptls_server_start (struct ast_tcptls_session_args *desc) |
| This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a thread for handling accept(). | |
| void | ast_tcptls_server_stop (struct ast_tcptls_session_args *desc) |
| Shutdown a running server if there is one. | |
| HOOK_T | ast_tcptls_server_write (struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count) |
| int | ast_tls_read_conf (struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value) |
| Used to parse conf files containing tls/ssl options. | |
| static void * | handle_tcptls_connection (void *data) |
| creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (certificate verification), so we do it in the child thread context. | |
| static void | session_instance_destructor (void *obj) |
Definition in file tcptls.c.
| static int __ssl_setup | ( | struct ast_tls_config * | cfg, | |
| int | client | |||
| ) | [static] |
Definition at line 317 of file tcptls.c.
References ast_debug, AST_SSL_SSLV2_CLIENT, AST_SSL_SSLV3_CLIENT, AST_SSL_TLSV1_CLIENT, ast_strlen_zero(), ast_test_flag, ast_verb, ast_tls_config::cafile, ast_tls_config::capath, ast_tls_config::certfile, ast_tls_config::cipher, ast_tls_config::enabled, ast_tls_config::flags, ast_tls_config::pvtfile, S_OR, and ast_tls_config::ssl_ctx.
Referenced by ast_ssl_setup(), and ast_tcptls_client_start().
00318 { 00319 #ifndef DO_SSL 00320 cfg->enabled = 0; 00321 return 0; 00322 #else 00323 if (!cfg->enabled) { 00324 return 0; 00325 } 00326 00327 SSL_load_error_strings(); 00328 SSLeay_add_ssl_algorithms(); 00329 00330 if (client) { 00331 #ifndef OPENSSL_NO_SSL2 00332 if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) { 00333 cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method()); 00334 } else 00335 #endif 00336 if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) { 00337 cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method()); 00338 } else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) { 00339 cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); 00340 } else { 00341 /* SSLv23_client_method() sends SSLv2, this was the original 00342 * default for ssl clients before the option was given to 00343 * pick what protocol a client should use. In order not 00344 * to break expected behavior it remains the default. */ 00345 cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); 00346 } 00347 } else { 00348 /* SSLv23_server_method() supports TLSv1, SSLv2, and SSLv3 inbound connections. */ 00349 cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); 00350 } 00351 00352 if (!cfg->ssl_ctx) { 00353 ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n"); 00354 cfg->enabled = 0; 00355 return 0; 00356 } 00357 if (!ast_strlen_zero(cfg->certfile)) { 00358 char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile; 00359 if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0) { 00360 if (!client) { 00361 /* Clients don't need a certificate, but if its setup we can use it */ 00362 ast_verb(0, "SSL error loading cert file. <%s>\n", cfg->certfile); 00363 sleep(2); 00364 cfg->enabled = 0; 00365 return 0; 00366 } 00367 } 00368 if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) { 00369 if (!client) { 00370 /* Clients don't need a private key, but if its setup we can use it */ 00371 ast_verb(0, "SSL error loading private key file. <%s>\n", tmpprivate); 00372 sleep(2); 00373 cfg->enabled = 0; 00374 return 0; 00375 } 00376 } 00377 } 00378 if (!ast_strlen_zero(cfg->cipher)) { 00379 if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) { 00380 if (!client) { 00381 ast_verb(0, "SSL cipher error <%s>\n", cfg->cipher); 00382 sleep(2); 00383 cfg->enabled = 0; 00384 return 0; 00385 } 00386 } 00387 } 00388 if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) { 00389 if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) { 00390 ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath); 00391 } 00392 } 00393 00394 ast_verb(0, "SSL certificate ok\n"); 00395 return 1; 00396 #endif 00397 }
| int ast_ssl_setup | ( | struct ast_tls_config * | cfg | ) |
Definition at line 399 of file tcptls.c.
References __ssl_setup().
Referenced by __ast_http_load(), __init_manager(), and reload_config().
00400 { 00401 return __ssl_setup(cfg, 0); 00402 }
| struct ast_tcptls_session_instance* ast_tcptls_client_create | ( | struct ast_tcptls_session_args * | desc | ) | [read] |
Definition at line 441 of file tcptls.c.
References ast_tcptls_session_args::accept_fd, ao2_alloc, ao2_ref, ast_bind(), ast_debug, ast_log(), ast_mutex_init, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), ast_tcptls_session_instance::client, errno, ast_tcptls_session_instance::fd, ast_tcptls_session_args::local_address, ast_tcptls_session_instance::lock, LOG_ERROR, LOG_WARNING, ast_tcptls_session_args::name, ast_tcptls_session_args::old_address, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::remote_address, ast_tcptls_session_args::remote_address, session_instance_destructor(), and ast_tcptls_session_args::worker_fn.
Referenced by app_exec(), and sip_prepare_socket().
00442 { 00443 int x = 1; 00444 struct ast_tcptls_session_instance *tcptls_session = NULL; 00445 00446 /* Do nothing if nothing has changed */ 00447 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { 00448 ast_debug(1, "Nothing changed in %s\n", desc->name); 00449 return NULL; 00450 } 00451 00452 /* If we return early, there is no connection */ 00453 ast_sockaddr_setnull(&desc->old_address); 00454 00455 if (desc->accept_fd != -1) { 00456 close(desc->accept_fd); 00457 } 00458 00459 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? 00460 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); 00461 if (desc->accept_fd < 0) { 00462 ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", 00463 desc->name, strerror(errno)); 00464 return NULL; 00465 } 00466 00467 /* if a local address was specified, bind to it so the connection will 00468 originate from the desired address */ 00469 if (!ast_sockaddr_isnull(&desc->local_address)) { 00470 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00471 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00472 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00473 desc->name, 00474 ast_sockaddr_stringify(&desc->local_address), 00475 strerror(errno)); 00476 goto error; 00477 } 00478 } 00479 00480 if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) { 00481 goto error; 00482 } 00483 00484 ast_mutex_init(&tcptls_session->lock); 00485 tcptls_session->client = 1; 00486 tcptls_session->fd = desc->accept_fd; 00487 tcptls_session->parent = desc; 00488 tcptls_session->parent->worker_fn = NULL; 00489 ast_sockaddr_copy(&tcptls_session->remote_address, 00490 &desc->remote_address); 00491 00492 /* Set current info */ 00493 ast_sockaddr_copy(&desc->old_address, &desc->remote_address); 00494 return tcptls_session; 00495 00496 error: 00497 close(desc->accept_fd); 00498 desc->accept_fd = -1; 00499 if (tcptls_session) { 00500 ao2_ref(tcptls_session, -1); 00501 } 00502 return NULL; 00503 }
| struct ast_tcptls_session_instance* ast_tcptls_client_start | ( | struct ast_tcptls_session_instance * | tcptls_session | ) | [read] |
attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned.
Definition at line 404 of file tcptls.c.
References __ssl_setup(), ast_tcptls_session_args::accept_fd, ao2_ref, ast_connect(), ast_log(), ast_sockaddr_stringify(), desc, ast_tls_config::enabled, errno, handle_tcptls_connection(), LOG_ERROR, ast_tcptls_session_args::name, ast_tcptls_session_instance::parent, ast_tcptls_session_args::remote_address, and ast_tcptls_session_args::tls_cfg.
Referenced by _sip_tcp_helper_thread(), and app_exec().
00405 { 00406 struct ast_tcptls_session_args *desc; 00407 int flags; 00408 00409 if (!(desc = tcptls_session->parent)) { 00410 goto client_start_error; 00411 } 00412 00413 if (ast_connect(desc->accept_fd, &desc->remote_address)) { 00414 ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", 00415 desc->name, 00416 ast_sockaddr_stringify(&desc->remote_address), 00417 strerror(errno)); 00418 goto client_start_error; 00419 } 00420 00421 flags = fcntl(desc->accept_fd, F_GETFL); 00422 fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK); 00423 00424 if (desc->tls_cfg) { 00425 desc->tls_cfg->enabled = 1; 00426 __ssl_setup(desc->tls_cfg, 1); 00427 } 00428 00429 return handle_tcptls_connection(tcptls_session); 00430 00431 client_start_error: 00432 close(desc->accept_fd); 00433 desc->accept_fd = -1; 00434 if (tcptls_session) { 00435 ao2_ref(tcptls_session, -1); 00436 } 00437 return NULL; 00438 00439 }
| void ast_tcptls_close_session_file | ( | struct ast_tcptls_session_instance * | tcptls_session | ) |
Closes a tcptls session instance's file and/or file descriptor. The tcptls_session will be set to NULL and it's file descriptor will be set to -1 by this function.
Definition at line 575 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::f, ast_tcptls_session_instance::fd, and LOG_ERROR.
Referenced by _sip_tcp_helper_thread(), ast_tcptls_server_root(), handle_tcptls_connection(), and sip_prepare_socket().
00576 { 00577 if (tcptls_session->f) { 00578 if (fclose(tcptls_session->f)) { 00579 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); 00580 } 00581 tcptls_session->f = NULL; 00582 tcptls_session->fd = -1; 00583 } else if (tcptls_session->fd != -1) { 00584 if (close(tcptls_session->fd)) { 00585 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00586 } 00587 tcptls_session->fd = -1; 00588 } else { 00589 ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); 00590 } 00591 }
| HOOK_T ast_tcptls_server_read | ( | struct ast_tcptls_session_instance * | tcptls_session, | |
| void * | buf, | |||
| size_t | count | |||
| ) |
replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging.
Definition at line 102 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, and ast_tcptls_session_instance::ssl.
00103 { 00104 if (tcptls_session->fd == -1) { 00105 ast_log(LOG_ERROR, "server_read called with an fd of -1\n"); 00106 errno = EIO; 00107 return -1; 00108 } 00109 00110 #ifdef DO_SSL 00111 if (tcptls_session->ssl) { 00112 return ssl_read(tcptls_session->ssl, buf, count); 00113 } 00114 #endif 00115 return read(tcptls_session->fd, buf, count); 00116 }
| void* ast_tcptls_server_root | ( | void * | data | ) |
Definition at line 263 of file tcptls.c.
References ast_tcptls_session_args::accept_fd, ao2_alloc, ao2_ref, ast_accept(), ast_log(), ast_mutex_init, ast_pthread_create_detached_background, ast_sockaddr_copy(), ast_tcptls_close_session_file(), ast_wait_for_input(), ast_tcptls_session_instance::client, desc, errno, ast_tcptls_session_instance::fd, handle_tcptls_connection(), ast_tcptls_session_instance::lock, LOG_ERROR, LOG_WARNING, ast_tcptls_session_instance::parent, ast_tcptls_session_args::periodic_fn, ast_tcptls_session_args::poll_timeout, ast_tcptls_session_instance::remote_address, and session_instance_destructor().
00264 { 00265 struct ast_tcptls_session_args *desc = data; 00266 int fd; 00267 struct ast_sockaddr addr; 00268 struct ast_tcptls_session_instance *tcptls_session; 00269 pthread_t launched; 00270 00271 for (;;) { 00272 int i, flags; 00273 00274 if (desc->periodic_fn) { 00275 desc->periodic_fn(desc); 00276 } 00277 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); 00278 if (i <= 0) { 00279 continue; 00280 } 00281 fd = ast_accept(desc->accept_fd, &addr); 00282 if (fd < 0) { 00283 if ((errno != EAGAIN) && (errno != EINTR)) { 00284 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); 00285 } 00286 continue; 00287 } 00288 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); 00289 if (!tcptls_session) { 00290 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); 00291 if (close(fd)) { 00292 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00293 } 00294 continue; 00295 } 00296 00297 ast_mutex_init(&tcptls_session->lock); 00298 00299 flags = fcntl(fd, F_GETFL); 00300 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 00301 tcptls_session->fd = fd; 00302 tcptls_session->parent = desc; 00303 ast_sockaddr_copy(&tcptls_session->remote_address, &addr); 00304 00305 tcptls_session->client = 0; 00306 00307 /* This thread is now the only place that controls the single ref to tcptls_session */ 00308 if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { 00309 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno)); 00310 ast_tcptls_close_session_file(tcptls_session); 00311 ao2_ref(tcptls_session, -1); 00312 } 00313 } 00314 return NULL; 00315 }
| void ast_tcptls_server_start | ( | struct ast_tcptls_session_args * | desc | ) |
This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a thread for handling accept().
Definition at line 505 of file tcptls.c.
References ast_tcptls_session_args::accept_fd, ast_tcptls_session_args::accept_fn, ast_bind(), ast_debug, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), errno, ast_tcptls_session_args::local_address, LOG_ERROR, ast_tcptls_session_args::master, ast_tcptls_session_args::name, and ast_tcptls_session_args::old_address.
Referenced by __ast_http_load(), __init_manager(), and reload_config().
00506 { 00507 int flags; 00508 int x = 1; 00509 00510 /* Do nothing if nothing has changed */ 00511 if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { 00512 ast_debug(1, "Nothing changed in %s\n", desc->name); 00513 return; 00514 } 00515 00516 /* If we return early, there is no one listening */ 00517 ast_sockaddr_setnull(&desc->old_address); 00518 00519 /* Shutdown a running server if there is one */ 00520 if (desc->master != AST_PTHREADT_NULL) { 00521 pthread_cancel(desc->master); 00522 pthread_kill(desc->master, SIGURG); 00523 pthread_join(desc->master, NULL); 00524 } 00525 00526 if (desc->accept_fd != -1) { 00527 close(desc->accept_fd); 00528 } 00529 00530 /* If there's no new server, stop here */ 00531 if (ast_sockaddr_isnull(&desc->local_address)) { 00532 ast_debug(2, "Server disabled: %s\n", desc->name); 00533 return; 00534 } 00535 00536 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? 00537 AF_INET6 : AF_INET, SOCK_STREAM, 0); 00538 if (desc->accept_fd < 0) { 00539 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); 00540 return; 00541 } 00542 00543 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00544 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00545 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00546 desc->name, 00547 ast_sockaddr_stringify(&desc->local_address), 00548 strerror(errno)); 00549 goto error; 00550 } 00551 if (listen(desc->accept_fd, 10)) { 00552 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); 00553 goto error; 00554 } 00555 flags = fcntl(desc->accept_fd, F_GETFL); 00556 fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); 00557 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { 00558 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", 00559 desc->name, 00560 ast_sockaddr_stringify(&desc->local_address), 00561 strerror(errno)); 00562 goto error; 00563 } 00564 00565 /* Set current info */ 00566 ast_sockaddr_copy(&desc->old_address, &desc->local_address); 00567 00568 return; 00569 00570 error: 00571 close(desc->accept_fd); 00572 desc->accept_fd = -1; 00573 }
| void ast_tcptls_server_stop | ( | struct ast_tcptls_session_args * | desc | ) |
Shutdown a running server if there is one.
Definition at line 593 of file tcptls.c.
References ast_tcptls_session_args::accept_fd, ast_debug, AST_PTHREADT_NULL, ast_tcptls_session_args::master, and ast_tcptls_session_args::name.
Referenced by __ast_http_load(), __init_manager(), and unload_module().
00594 { 00595 if (desc->master != AST_PTHREADT_NULL) { 00596 pthread_cancel(desc->master); 00597 pthread_kill(desc->master, SIGURG); 00598 pthread_join(desc->master, NULL); 00599 desc->master = AST_PTHREADT_NULL; 00600 } 00601 if (desc->accept_fd != -1) { 00602 close(desc->accept_fd); 00603 } 00604 desc->accept_fd = -1; 00605 ast_debug(2, "Stopped server :: %s\n", desc->name); 00606 }
| HOOK_T ast_tcptls_server_write | ( | struct ast_tcptls_session_instance * | tcptls_session, | |
| const void * | buf, | |||
| size_t | count | |||
| ) |
Definition at line 118 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, and ast_tcptls_session_instance::ssl.
Referenced by _sip_tcp_helper_thread().
00119 { 00120 if (tcptls_session->fd == -1) { 00121 ast_log(LOG_ERROR, "server_write called with an fd of -1\n"); 00122 errno = EIO; 00123 return -1; 00124 } 00125 00126 #ifdef DO_SSL 00127 if (tcptls_session->ssl) { 00128 return ssl_write(tcptls_session->ssl, buf, count); 00129 } 00130 #endif 00131 return write(tcptls_session->fd, buf, count); 00132 }
| int ast_tls_read_conf | ( | struct ast_tls_config * | tls_cfg, | |
| struct ast_tcptls_session_args * | tls_desc, | |||
| const char * | varname, | |||
| const char * | value | |||
| ) |
Used to parse conf files containing tls/ssl options.
Definition at line 608 of file tcptls.c.
References ast_clear_flag, ast_free, ast_log(), ast_parse_arg(), ast_set2_flag, ast_set_flag, AST_SSL_DONT_VERIFY_SERVER, AST_SSL_SSLV2_CLIENT, AST_SSL_SSLV3_CLIENT, AST_SSL_TLSV1_CLIENT, AST_SSL_VERIFY_CLIENT, ast_strdup, ast_true(), ast_tls_config::cafile, ast_tls_config::capath, ast_tls_config::certfile, ast_tls_config::cipher, ast_tls_config::enabled, ast_tls_config::flags, ast_tcptls_session_args::local_address, LOG_WARNING, PARSE_ADDR, and ast_tls_config::pvtfile.
Referenced by __ast_http_load(), __init_manager(), and reload_config().
00609 { 00610 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { 00611 tls_cfg->enabled = ast_true(value) ? 1 : 0; 00612 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { 00613 ast_free(tls_cfg->certfile); 00614 tls_cfg->certfile = ast_strdup(value); 00615 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) { 00616 ast_free(tls_cfg->pvtfile); 00617 tls_cfg->pvtfile = ast_strdup(value); 00618 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) { 00619 ast_free(tls_cfg->cipher); 00620 tls_cfg->cipher = ast_strdup(value); 00621 } else if (!strcasecmp(varname, "tlscafile")) { 00622 ast_free(tls_cfg->cafile); 00623 tls_cfg->cafile = ast_strdup(value); 00624 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) { 00625 ast_free(tls_cfg->capath); 00626 tls_cfg->capath = ast_strdup(value); 00627 } else if (!strcasecmp(varname, "tlsverifyclient")) { 00628 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT); 00629 } else if (!strcasecmp(varname, "tlsdontverifyserver")) { 00630 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); 00631 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { 00632 if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) 00633 ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); 00634 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { 00635 if (!strcasecmp(value, "tlsv1")) { 00636 ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00637 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00638 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00639 } else if (!strcasecmp(value, "sslv3")) { 00640 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00641 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00642 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00643 } else if (!strcasecmp(value, "sslv2")) { 00644 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00645 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00646 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00647 } 00648 } else { 00649 return -1; 00650 } 00651 00652 return 0; 00653 }
| static void* handle_tcptls_connection | ( | void * | data | ) | [static] |
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (certificate verification), so we do it in the child thread context.
Definition at line 147 of file tcptls.c.
References ao2_ref, ast_debug, ast_log(), AST_SSL_DONT_VERIFY_SERVER, AST_SSL_IGNORE_COMMON_NAME, AST_SSL_VERIFY_CLIENT, ast_tcptls_close_session_file(), ast_test_flag, ast_verb, ast_tcptls_session_instance::client, ast_tcptls_session_instance::f, ast_tcptls_session_instance::fd, ast_tls_config::flags, ast_tcptls_session_args::hostname, LOG_ERROR, LOG_WARNING, name, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::ssl, ast_tls_config::ssl_ctx, str, ast_tcptls_session_args::tls_cfg, and ast_tcptls_session_args::worker_fn.
Referenced by ast_tcptls_client_start(), and ast_tcptls_server_root().
00148 { 00149 struct ast_tcptls_session_instance *tcptls_session = data; 00150 #ifdef DO_SSL 00151 int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept; 00152 int ret; 00153 char err[256]; 00154 #endif 00155 00156 /* 00157 * open a FILE * as appropriate. 00158 */ 00159 if (!tcptls_session->parent->tls_cfg) { 00160 if ((tcptls_session->f = fdopen(tcptls_session->fd, "w+"))) { 00161 if(setvbuf(tcptls_session->f, NULL, _IONBF, 0)) { 00162 ast_tcptls_close_session_file(tcptls_session); 00163 } 00164 } 00165 } 00166 #ifdef DO_SSL 00167 else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) { 00168 SSL_set_fd(tcptls_session->ssl, tcptls_session->fd); 00169 if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) { 00170 ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err)); 00171 } else { 00172 #if defined(HAVE_FUNOPEN) /* the BSD interface */ 00173 tcptls_session->f = funopen(tcptls_session->ssl, ssl_read, ssl_write, NULL, ssl_close); 00174 00175 #elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ 00176 static const cookie_io_functions_t cookie_funcs = { 00177 ssl_read, ssl_write, NULL, ssl_close 00178 }; 00179 tcptls_session->f = fopencookie(tcptls_session->ssl, "w+", cookie_funcs); 00180 #else 00181 /* could add other methods here */ 00182 ast_debug(2, "no tcptls_session->f methods attempted!"); 00183 #endif 00184 if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) 00185 || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { 00186 X509 *peer; 00187 long res; 00188 peer = SSL_get_peer_certificate(tcptls_session->ssl); 00189 if (!peer) { 00190 ast_log(LOG_WARNING, "No peer SSL certificate\n"); 00191 } 00192 res = SSL_get_verify_result(tcptls_session->ssl); 00193 if (res != X509_V_OK) { 00194 ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); 00195 } 00196 if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { 00197 ASN1_STRING *str; 00198 unsigned char *str2; 00199 X509_NAME *name = X509_get_subject_name(peer); 00200 int pos = -1; 00201 int found = 0; 00202 00203 for (;;) { 00204 /* Walk the certificate to check all available "Common Name" */ 00205 /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ 00206 pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); 00207 if (pos < 0) { 00208 break; 00209 } 00210 str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); 00211 ASN1_STRING_to_UTF8(&str2, str); 00212 if (str2) { 00213 if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) { 00214 found = 1; 00215 } 00216 ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2); 00217 OPENSSL_free(str2); 00218 } 00219 if (found) { 00220 break; 00221 } 00222 } 00223 if (!found) { 00224 ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); 00225 if (peer) { 00226 X509_free(peer); 00227 } 00228 ast_tcptls_close_session_file(tcptls_session); 00229 ao2_ref(tcptls_session, -1); 00230 return NULL; 00231 } 00232 } 00233 if (peer) { 00234 X509_free(peer); 00235 } 00236 } 00237 } 00238 if (!tcptls_session->f) { /* no success opening descriptor stacking */ 00239 SSL_free(tcptls_session->ssl); 00240 } 00241 } 00242 #endif /* DO_SSL */ 00243 00244 if (!tcptls_session->f) { 00245 ast_tcptls_close_session_file(tcptls_session); 00246 ast_log(LOG_WARNING, "FILE * open failed!\n"); 00247 #ifndef DO_SSL 00248 if (tcptls_session->parent->tls_cfg) { 00249 ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); 00250 } 00251 #endif 00252 ao2_ref(tcptls_session, -1); 00253 return NULL; 00254 } 00255 00256 if (tcptls_session && tcptls_session->parent->worker_fn) { 00257 return tcptls_session->parent->worker_fn(tcptls_session); 00258 } else { 00259 return tcptls_session; 00260 } 00261 }
| static void session_instance_destructor | ( | void * | obj | ) | [static] |
Definition at line 134 of file tcptls.c.
References ast_mutex_destroy, and ast_tcptls_session_instance::lock.
Referenced by ast_tcptls_client_create(), and ast_tcptls_server_root().
00135 { 00136 struct ast_tcptls_session_instance *i = obj; 00137 ast_mutex_destroy(&i->lock); 00138 }
1.5.6