Code to support TCP and TLS server/client. More...
#include "asterisk.h"#include <fcntl.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"#include "asterisk/pbx.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) |
| Set up an SSL server. | |
| void | ast_ssl_teardown (struct ast_tls_config *cfg) |
| free resources used by an SSL server | |
| 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) |
| 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) |
| static int | ssl_close (void *cookie) |
| static HOOK_T | ssl_read (void *cookie, char *buf, LEN_T len) |
| replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging. | |
| static HOOK_T | ssl_write (void *cookie, const char *buf, LEN_T len) |
Code to support TCP and TLS server/client.
Definition in file tcptls.c.
| static int __ssl_setup | ( | struct ast_tls_config * | cfg, | |
| int | client | |||
| ) | [static] |
Definition at line 334 of file tcptls.c.
References ast_debug, AST_SSL_SSLV2_CLIENT, AST_SSL_SSLV3_CLIENT, AST_SSL_TLSV1_CLIENT, AST_SSL_VERIFY_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().
00335 { 00336 #ifndef DO_SSL 00337 cfg->enabled = 0; 00338 return 0; 00339 #else 00340 if (!cfg->enabled) 00341 return 0; 00342 00343 /* Get rid of an old SSL_CTX since we're about to 00344 * allocate a new one 00345 */ 00346 if (cfg->ssl_ctx) { 00347 SSL_CTX_free(cfg->ssl_ctx); 00348 cfg->ssl_ctx = NULL; 00349 } 00350 00351 if (client) { 00352 #ifndef OPENSSL_NO_SSL2 00353 if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) { 00354 cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method()); 00355 } else 00356 #endif 00357 if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) { 00358 cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method()); 00359 } else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) { 00360 cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); 00361 } else { 00362 /* SSLv23_client_method() sends SSLv2, this was the original 00363 * default for ssl clients before the option was given to 00364 * pick what protocol a client should use. In order not 00365 * to break expected behavior it remains the default. */ 00366 cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); 00367 } 00368 } else { 00369 /* SSLv23_server_method() supports TLSv1, SSLv2, and SSLv3 inbound connections. */ 00370 cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); 00371 } 00372 00373 if (!cfg->ssl_ctx) { 00374 ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n"); 00375 cfg->enabled = 0; 00376 return 0; 00377 } 00378 00379 SSL_CTX_set_verify(cfg->ssl_ctx, 00380 ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, 00381 NULL); 00382 00383 if (!ast_strlen_zero(cfg->certfile)) { 00384 char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile; 00385 if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0) { 00386 if (!client) { 00387 /* Clients don't need a certificate, but if its setup we can use it */ 00388 ast_verb(0, "SSL error loading cert file. <%s>", cfg->certfile); 00389 cfg->enabled = 0; 00390 SSL_CTX_free(cfg->ssl_ctx); 00391 cfg->ssl_ctx = NULL; 00392 return 0; 00393 } 00394 } 00395 if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) { 00396 if (!client) { 00397 /* Clients don't need a private key, but if its setup we can use it */ 00398 ast_verb(0, "SSL error loading private key file. <%s>", tmpprivate); 00399 cfg->enabled = 0; 00400 SSL_CTX_free(cfg->ssl_ctx); 00401 cfg->ssl_ctx = NULL; 00402 return 0; 00403 } 00404 } 00405 } 00406 if (!ast_strlen_zero(cfg->cipher)) { 00407 if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) { 00408 if (!client) { 00409 ast_verb(0, "SSL cipher error <%s>", cfg->cipher); 00410 cfg->enabled = 0; 00411 SSL_CTX_free(cfg->ssl_ctx); 00412 cfg->ssl_ctx = NULL; 00413 return 0; 00414 } 00415 } 00416 } 00417 if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) { 00418 if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) 00419 ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath); 00420 } 00421 00422 ast_verb(0, "SSL certificate ok\n"); 00423 return 1; 00424 #endif 00425 }
| int ast_ssl_setup | ( | struct ast_tls_config * | cfg | ) |
Set up an SSL server.
| cfg | Configuration for the SSL server |
| 1 | Success | |
| 0 | Failure |
Definition at line 427 of file tcptls.c.
References __ssl_setup().
Referenced by __ast_http_load(), __init_manager(), and reload_config().
00428 { 00429 return __ssl_setup(cfg, 0); 00430 }
| void ast_ssl_teardown | ( | struct ast_tls_config * | cfg | ) |
free resources used by an SSL server
| cfg | Configuration for the SSL server |
Definition at line 432 of file tcptls.c.
References ast_tls_config::ssl_ctx.
Referenced by sip_tcptls_client_args_destructor(), and unload_module().
| struct ast_tcptls_session_instance* ast_tcptls_client_create | ( | struct ast_tcptls_session_args * | desc | ) | [read] |
Definition at line 479 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_str_create(), 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::overflow_buf, 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().
00480 { 00481 int x = 1; 00482 struct ast_tcptls_session_instance *tcptls_session = NULL; 00483 00484 /* Do nothing if nothing has changed */ 00485 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { 00486 ast_debug(1, "Nothing changed in %s\n", desc->name); 00487 return NULL; 00488 } 00489 00490 /* If we return early, there is no connection */ 00491 ast_sockaddr_setnull(&desc->old_address); 00492 00493 if (desc->accept_fd != -1) 00494 close(desc->accept_fd); 00495 00496 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? 00497 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); 00498 if (desc->accept_fd < 0) { 00499 ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", 00500 desc->name, strerror(errno)); 00501 return NULL; 00502 } 00503 00504 /* if a local address was specified, bind to it so the connection will 00505 originate from the desired address */ 00506 if (!ast_sockaddr_isnull(&desc->local_address)) { 00507 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00508 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00509 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00510 desc->name, 00511 ast_sockaddr_stringify(&desc->local_address), 00512 strerror(errno)); 00513 goto error; 00514 } 00515 } 00516 00517 if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) 00518 goto error; 00519 00520 ast_mutex_init(&tcptls_session->lock); 00521 tcptls_session->overflow_buf = ast_str_create(128); 00522 tcptls_session->client = 1; 00523 tcptls_session->fd = desc->accept_fd; 00524 tcptls_session->parent = desc; 00525 tcptls_session->parent->worker_fn = NULL; 00526 ast_sockaddr_copy(&tcptls_session->remote_address, 00527 &desc->remote_address); 00528 00529 /* Set current info */ 00530 ast_sockaddr_copy(&desc->old_address, &desc->remote_address); 00531 return tcptls_session; 00532 00533 error: 00534 close(desc->accept_fd); 00535 desc->accept_fd = -1; 00536 if (tcptls_session) 00537 ao2_ref(tcptls_session, -1); 00538 return NULL; 00539 }
| 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 442 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().
00443 { 00444 struct ast_tcptls_session_args *desc; 00445 int flags; 00446 00447 if (!(desc = tcptls_session->parent)) { 00448 goto client_start_error; 00449 } 00450 00451 if (ast_connect(desc->accept_fd, &desc->remote_address)) { 00452 ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", 00453 desc->name, 00454 ast_sockaddr_stringify(&desc->remote_address), 00455 strerror(errno)); 00456 goto client_start_error; 00457 } 00458 00459 flags = fcntl(desc->accept_fd, F_GETFL); 00460 fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK); 00461 00462 if (desc->tls_cfg) { 00463 desc->tls_cfg->enabled = 1; 00464 __ssl_setup(desc->tls_cfg, 1); 00465 } 00466 00467 return handle_tcptls_connection(tcptls_session); 00468 00469 client_start_error: 00470 if (desc) { 00471 close(desc->accept_fd); 00472 desc->accept_fd = -1; 00473 } 00474 ao2_ref(tcptls_session, -1); 00475 return NULL; 00476 00477 }
| 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 610 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().
00611 { 00612 if (tcptls_session->f) { 00613 if (fclose(tcptls_session->f)) { 00614 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); 00615 } 00616 tcptls_session->f = NULL; 00617 tcptls_session->fd = -1; 00618 } else if (tcptls_session->fd != -1) { 00619 if (close(tcptls_session->fd)) { 00620 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00621 } 00622 tcptls_session->fd = -1; 00623 } else { 00624 ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); 00625 } 00626 }
| HOOK_T ast_tcptls_server_read | ( | struct ast_tcptls_session_instance * | tcptls_session, | |
| void * | buf, | |||
| size_t | count | |||
| ) |
Definition at line 112 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_read().
00113 { 00114 if (tcptls_session->fd == -1) { 00115 ast_log(LOG_ERROR, "server_read called with an fd of -1\n"); 00116 errno = EIO; 00117 return -1; 00118 } 00119 00120 #ifdef DO_SSL 00121 if (tcptls_session->ssl) 00122 return ssl_read(tcptls_session->ssl, buf, count); 00123 #endif 00124 return read(tcptls_session->fd, buf, count); 00125 }
| void* ast_tcptls_server_root | ( | void * | data | ) |
Definition at line 282 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_str_create(), 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::overflow_buf, 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().
00283 { 00284 struct ast_tcptls_session_args *desc = data; 00285 int fd; 00286 struct ast_sockaddr addr; 00287 struct ast_tcptls_session_instance *tcptls_session; 00288 pthread_t launched; 00289 00290 for (;;) { 00291 int i, flags; 00292 00293 if (desc->periodic_fn) 00294 desc->periodic_fn(desc); 00295 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); 00296 if (i <= 0) 00297 continue; 00298 fd = ast_accept(desc->accept_fd, &addr); 00299 if (fd < 0) { 00300 if ((errno != EAGAIN) && (errno != EINTR)) 00301 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); 00302 continue; 00303 } 00304 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); 00305 if (!tcptls_session) { 00306 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); 00307 if (close(fd)) { 00308 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00309 } 00310 continue; 00311 } 00312 00313 ast_mutex_init(&tcptls_session->lock); 00314 tcptls_session->overflow_buf = ast_str_create(128); 00315 00316 flags = fcntl(fd, F_GETFL); 00317 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 00318 tcptls_session->fd = fd; 00319 tcptls_session->parent = desc; 00320 ast_sockaddr_copy(&tcptls_session->remote_address, &addr); 00321 00322 tcptls_session->client = 0; 00323 00324 /* This thread is now the only place that controls the single ref to tcptls_session */ 00325 if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { 00326 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno)); 00327 ast_tcptls_close_session_file(tcptls_session); 00328 ao2_ref(tcptls_session, -1); 00329 } 00330 } 00331 return NULL; 00332 }
| 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 541 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().
00542 { 00543 int flags; 00544 int x = 1; 00545 00546 /* Do nothing if nothing has changed */ 00547 if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { 00548 ast_debug(1, "Nothing changed in %s\n", desc->name); 00549 return; 00550 } 00551 00552 /* If we return early, there is no one listening */ 00553 ast_sockaddr_setnull(&desc->old_address); 00554 00555 /* Shutdown a running server if there is one */ 00556 if (desc->master != AST_PTHREADT_NULL) { 00557 pthread_cancel(desc->master); 00558 pthread_kill(desc->master, SIGURG); 00559 pthread_join(desc->master, NULL); 00560 } 00561 00562 if (desc->accept_fd != -1) 00563 close(desc->accept_fd); 00564 00565 /* If there's no new server, stop here */ 00566 if (ast_sockaddr_isnull(&desc->local_address)) { 00567 ast_debug(2, "Server disabled: %s\n", desc->name); 00568 return; 00569 } 00570 00571 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? 00572 AF_INET6 : AF_INET, SOCK_STREAM, 0); 00573 if (desc->accept_fd < 0) { 00574 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); 00575 return; 00576 } 00577 00578 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00579 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00580 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00581 desc->name, 00582 ast_sockaddr_stringify(&desc->local_address), 00583 strerror(errno)); 00584 goto error; 00585 } 00586 if (listen(desc->accept_fd, 10)) { 00587 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); 00588 goto error; 00589 } 00590 flags = fcntl(desc->accept_fd, F_GETFL); 00591 fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); 00592 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { 00593 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", 00594 desc->name, 00595 ast_sockaddr_stringify(&desc->local_address), 00596 strerror(errno)); 00597 goto error; 00598 } 00599 00600 /* Set current info */ 00601 ast_sockaddr_copy(&desc->old_address, &desc->local_address); 00602 00603 return; 00604 00605 error: 00606 close(desc->accept_fd); 00607 desc->accept_fd = -1; 00608 }
| void ast_tcptls_server_stop | ( | struct ast_tcptls_session_args * | desc | ) |
Shutdown a running server if there is one.
Definition at line 628 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(), http_shutdown(), manager_shutdown(), and unload_module().
00629 { 00630 if (desc->master != AST_PTHREADT_NULL) { 00631 pthread_cancel(desc->master); 00632 pthread_kill(desc->master, SIGURG); 00633 pthread_join(desc->master, NULL); 00634 desc->master = AST_PTHREADT_NULL; 00635 } 00636 if (desc->accept_fd != -1) 00637 close(desc->accept_fd); 00638 desc->accept_fd = -1; 00639 ast_debug(2, "Stopped server :: %s\n", desc->name); 00640 }
| HOOK_T ast_tcptls_server_write | ( | struct ast_tcptls_session_instance * | tcptls_session, | |
| const void * | buf, | |||
| size_t | count | |||
| ) |
Definition at line 127 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_write().
Referenced by _sip_tcp_helper_thread().
00128 { 00129 if (tcptls_session->fd == -1) { 00130 ast_log(LOG_ERROR, "server_write called with an fd of -1\n"); 00131 errno = EIO; 00132 return -1; 00133 } 00134 00135 #ifdef DO_SSL 00136 if (tcptls_session->ssl) 00137 return ssl_write(tcptls_session->ssl, buf, count); 00138 #endif 00139 return write(tcptls_session->fd, buf, count); 00140 }
| 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 642 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().
00643 { 00644 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { 00645 tls_cfg->enabled = ast_true(value) ? 1 : 0; 00646 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { 00647 ast_free(tls_cfg->certfile); 00648 tls_cfg->certfile = ast_strdup(value); 00649 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) { 00650 ast_free(tls_cfg->pvtfile); 00651 tls_cfg->pvtfile = ast_strdup(value); 00652 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) { 00653 ast_free(tls_cfg->cipher); 00654 tls_cfg->cipher = ast_strdup(value); 00655 } else if (!strcasecmp(varname, "tlscafile")) { 00656 ast_free(tls_cfg->cafile); 00657 tls_cfg->cafile = ast_strdup(value); 00658 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) { 00659 ast_free(tls_cfg->capath); 00660 tls_cfg->capath = ast_strdup(value); 00661 } else if (!strcasecmp(varname, "tlsverifyclient")) { 00662 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT); 00663 } else if (!strcasecmp(varname, "tlsdontverifyserver")) { 00664 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); 00665 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { 00666 if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) 00667 ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); 00668 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { 00669 if (!strcasecmp(value, "tlsv1")) { 00670 ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00671 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00672 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00673 } else if (!strcasecmp(value, "sslv3")) { 00674 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00675 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00676 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00677 } else if (!strcasecmp(value, "sslv2")) { 00678 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00679 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00680 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00681 } 00682 } else { 00683 return -1; 00684 } 00685 00686 return 0; 00687 }
| 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 156 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_thread_inhibit_escalations(), 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, ssl_close(), ast_tls_config::ssl_ctx, ssl_read(), ssl_write(), 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().
00157 { 00158 struct ast_tcptls_session_instance *tcptls_session = data; 00159 #ifdef DO_SSL 00160 int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept; 00161 int ret; 00162 char err[256]; 00163 #endif 00164 00165 /* TCP/TLS connections are associated with external protocols, and 00166 * should not be allowed to execute 'dangerous' functions. This may 00167 * need to be pushed down into the individual protocol handlers, but 00168 * this seems like a good general policy. 00169 */ 00170 if (ast_thread_inhibit_escalations()) { 00171 ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection\n"); 00172 return NULL; 00173 } 00174 00175 /* 00176 * open a FILE * as appropriate. 00177 */ 00178 if (!tcptls_session->parent->tls_cfg) { 00179 if ((tcptls_session->f = fdopen(tcptls_session->fd, "w+"))) { 00180 if(setvbuf(tcptls_session->f, NULL, _IONBF, 0)) { 00181 ast_tcptls_close_session_file(tcptls_session); 00182 } 00183 } 00184 } 00185 #ifdef DO_SSL 00186 else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) { 00187 SSL_set_fd(tcptls_session->ssl, tcptls_session->fd); 00188 if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) { 00189 ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err)); 00190 } else { 00191 #if defined(HAVE_FUNOPEN) /* the BSD interface */ 00192 tcptls_session->f = funopen(tcptls_session->ssl, ssl_read, ssl_write, NULL, ssl_close); 00193 00194 #elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ 00195 static const cookie_io_functions_t cookie_funcs = { 00196 ssl_read, ssl_write, NULL, ssl_close 00197 }; 00198 tcptls_session->f = fopencookie(tcptls_session->ssl, "w+", cookie_funcs); 00199 #else 00200 /* could add other methods here */ 00201 ast_debug(2, "no tcptls_session->f methods attempted!\n"); 00202 #endif 00203 if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) 00204 || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { 00205 X509 *peer; 00206 long res; 00207 peer = SSL_get_peer_certificate(tcptls_session->ssl); 00208 if (!peer) { 00209 ast_log(LOG_ERROR, "No peer SSL certificate to verify\n"); 00210 ast_tcptls_close_session_file(tcptls_session); 00211 ao2_ref(tcptls_session, -1); 00212 return NULL; 00213 } 00214 00215 res = SSL_get_verify_result(tcptls_session->ssl); 00216 if (res != X509_V_OK) { 00217 ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); 00218 X509_free(peer); 00219 ast_tcptls_close_session_file(tcptls_session); 00220 ao2_ref(tcptls_session, -1); 00221 return NULL; 00222 } 00223 if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { 00224 ASN1_STRING *str; 00225 unsigned char *str2; 00226 X509_NAME *name = X509_get_subject_name(peer); 00227 int pos = -1; 00228 int found = 0; 00229 00230 for (;;) { 00231 /* Walk the certificate to check all available "Common Name" */ 00232 /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ 00233 pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); 00234 if (pos < 0) 00235 break; 00236 str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); 00237 ASN1_STRING_to_UTF8(&str2, str); 00238 if (str2) { 00239 if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) 00240 found = 1; 00241 ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2); 00242 OPENSSL_free(str2); 00243 } 00244 if (found) 00245 break; 00246 } 00247 if (!found) { 00248 ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); 00249 X509_free(peer); 00250 ast_tcptls_close_session_file(tcptls_session); 00251 ao2_ref(tcptls_session, -1); 00252 return NULL; 00253 } 00254 } 00255 X509_free(peer); 00256 } 00257 } 00258 if (!tcptls_session->f) /* no success opening descriptor stacking */ 00259 SSL_free(tcptls_session->ssl); 00260 } 00261 #endif /* DO_SSL */ 00262 00263 if (!tcptls_session->f) { 00264 ast_tcptls_close_session_file(tcptls_session); 00265 ast_log(LOG_WARNING, "FILE * open failed!\n"); 00266 #ifndef DO_SSL 00267 if (tcptls_session->parent->tls_cfg) { 00268 ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); 00269 } 00270 #endif 00271 ao2_ref(tcptls_session, -1); 00272 return NULL; 00273 } 00274 00275 if (tcptls_session->parent->worker_fn) { 00276 return tcptls_session->parent->worker_fn(tcptls_session); 00277 } else { 00278 return tcptls_session; 00279 } 00280 }
| static void session_instance_destructor | ( | void * | obj | ) | [static] |
Definition at line 142 of file tcptls.c.
References ast_free, ast_mutex_destroy, ast_tcptls_session_instance::lock, and ast_tcptls_session_instance::overflow_buf.
Referenced by ast_tcptls_client_create(), and ast_tcptls_server_root().
00143 { 00144 struct ast_tcptls_session_instance *i = obj; 00145 ast_free(i->overflow_buf); 00146 ast_mutex_destroy(&i->lock); 00147 }
| static int ssl_close | ( | void * | cookie | ) | [static] |
Definition at line 82 of file tcptls.c.
References ast_log(), errno, and LOG_ERROR.
Referenced by handle_tcptls_connection().
00083 { 00084 int cookie_fd = SSL_get_fd(cookie); 00085 int ret; 00086 00087 if (cookie_fd > -1) { 00088 /* 00089 * According to the TLS standard, it is acceptable for an application to only send its shutdown 00090 * alert and then close the underlying connection without waiting for the peer's response (this 00091 * way resources can be saved, as the process can already terminate or serve another connection). 00092 */ 00093 if ((ret = SSL_shutdown(cookie)) < 0) { 00094 ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n", SSL_get_error(cookie, ret)); 00095 } 00096 00097 if (!((SSL*)cookie)->server) { 00098 /* For client threads, ensure that the error stack is cleared */ 00099 ERR_remove_state(0); 00100 } 00101 00102 SSL_free(cookie); 00103 /* adding shutdown(2) here has no added benefit */ 00104 if (close(cookie_fd)) { 00105 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00106 } 00107 } 00108 return 0; 00109 }
| static HOOK_T ssl_read | ( | void * | cookie, | |
| char * | buf, | |||
| LEN_T | len | |||
| ) | [static] |
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 60 of file tcptls.c.
References ast_verb.
Referenced by ast_tcptls_server_read(), and handle_tcptls_connection().
| static HOOK_T ssl_write | ( | void * | cookie, | |
| const char * | buf, | |||
| LEN_T | len | |||
| ) | [static] |
Definition at line 71 of file tcptls.c.
References ast_alloca, and ast_verb.
Referenced by ast_tcptls_server_write(), and handle_tcptls_connection().
1.6.1