Generic support for tcp/tls servers in Asterisk. More...
#include "asterisk/netsock2.h"
#include "asterisk/utils.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
Go to the source code of this file.
Data Structures | |
struct | ast_tcptls_session_args |
arguments for the accepting thread More... | |
struct | ast_tcptls_session_instance |
struct | ast_tls_config |
Defines | |
#define | AST_CERTFILE "asterisk.pem" |
#define | DO_SSL |
#define | HOOK_T ssize_t |
#define | LEN_T size_t |
Enumerations | |
enum | ast_ssl_flags { AST_SSL_VERIFY_CLIENT = (1 << 0), AST_SSL_DONT_VERIFY_SERVER = (1 << 1), AST_SSL_IGNORE_COMMON_NAME = (1 << 2), AST_SSL_SSLV2_CLIENT = (1 << 3), AST_SSL_SSLV3_CLIENT = (1 << 4), AST_SSL_TLSV1_CLIENT = (1 << 5) } |
Functions | |
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 *ser, void *buf, size_t count) |
void * | ast_tcptls_server_root (void *) |
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 *ser, 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. |
Generic support for tcp/tls servers in Asterisk.
TLS/SSL support is basically implemented by reading from a config file (currently http.conf and sip.conf) the names of the certificate and cipher to use, and then run ssl_setup() to create an appropriate SSL_CTX (ssl_ctx) If we support multiple domains, presumably we need to read multiple certificates.
When we are requested to open a TLS socket, we run make_file_from_fd() on the socket, to do the necessary setup. At the moment the context's name is hardwired in the function, but we can certainly make it into an extra parameter to the function.
We declare most of ssl support variables unconditionally, because their number is small and this simplifies the code.
Definition in file tcptls.h.
#define AST_CERTFILE "asterisk.pem" |
SSL support
Definition at line 68 of file tcptls.h.
Referenced by __ast_http_load(), __init_manager(), and reload_config().
enum ast_ssl_flags |
AST_SSL_VERIFY_CLIENT |
Verify certificate when acting as server |
AST_SSL_DONT_VERIFY_SERVER |
Don't verify certificate when connecting to a server |
AST_SSL_IGNORE_COMMON_NAME |
Don't compare "Common Name" against IP or hostname |
AST_SSL_SSLV2_CLIENT |
Use SSLv2 for outgoing client connections |
AST_SSL_SSLV3_CLIENT |
Use SSLv3 for outgoing client connections |
AST_SSL_TLSV1_CLIENT |
Use TLSv1 for outgoing client connections |
Definition at line 70 of file tcptls.h.
00070 { 00071 /*! Verify certificate when acting as server */ 00072 AST_SSL_VERIFY_CLIENT = (1 << 0), 00073 /*! Don't verify certificate when connecting to a server */ 00074 AST_SSL_DONT_VERIFY_SERVER = (1 << 1), 00075 /*! Don't compare "Common Name" against IP or hostname */ 00076 AST_SSL_IGNORE_COMMON_NAME = (1 << 2), 00077 /*! Use SSLv2 for outgoing client connections */ 00078 AST_SSL_SSLV2_CLIENT = (1 << 3), 00079 /*! Use SSLv3 for outgoing client connections */ 00080 AST_SSL_SSLV3_CLIENT = (1 << 4), 00081 /*! Use TLSv1 for outgoing client connections */ 00082 AST_SSL_TLSV1_CLIENT = (1 << 5) 00083 };
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 416 of file tcptls.c.
References __ssl_setup().
Referenced by __ast_http_load(), __init_manager(), and reload_config().
00417 { 00418 return __ssl_setup(cfg, 0); 00419 }
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 421 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 468 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().
00469 { 00470 int x = 1; 00471 struct ast_tcptls_session_instance *tcptls_session = NULL; 00472 00473 /* Do nothing if nothing has changed */ 00474 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { 00475 ast_debug(1, "Nothing changed in %s\n", desc->name); 00476 return NULL; 00477 } 00478 00479 /* If we return early, there is no connection */ 00480 ast_sockaddr_setnull(&desc->old_address); 00481 00482 if (desc->accept_fd != -1) 00483 close(desc->accept_fd); 00484 00485 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? 00486 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); 00487 if (desc->accept_fd < 0) { 00488 ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", 00489 desc->name, strerror(errno)); 00490 return NULL; 00491 } 00492 00493 /* if a local address was specified, bind to it so the connection will 00494 originate from the desired address */ 00495 if (!ast_sockaddr_isnull(&desc->local_address)) { 00496 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00497 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00498 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00499 desc->name, 00500 ast_sockaddr_stringify(&desc->local_address), 00501 strerror(errno)); 00502 goto error; 00503 } 00504 } 00505 00506 if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) 00507 goto error; 00508 00509 ast_mutex_init(&tcptls_session->lock); 00510 tcptls_session->overflow_buf = ast_str_create(128); 00511 tcptls_session->client = 1; 00512 tcptls_session->fd = desc->accept_fd; 00513 tcptls_session->parent = desc; 00514 tcptls_session->parent->worker_fn = NULL; 00515 ast_sockaddr_copy(&tcptls_session->remote_address, 00516 &desc->remote_address); 00517 00518 /* Set current info */ 00519 ast_sockaddr_copy(&desc->old_address, &desc->remote_address); 00520 return tcptls_session; 00521 00522 error: 00523 close(desc->accept_fd); 00524 desc->accept_fd = -1; 00525 if (tcptls_session) 00526 ao2_ref(tcptls_session, -1); 00527 return NULL; 00528 }
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 431 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().
00432 { 00433 struct ast_tcptls_session_args *desc; 00434 int flags; 00435 00436 if (!(desc = tcptls_session->parent)) { 00437 goto client_start_error; 00438 } 00439 00440 if (ast_connect(desc->accept_fd, &desc->remote_address)) { 00441 ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", 00442 desc->name, 00443 ast_sockaddr_stringify(&desc->remote_address), 00444 strerror(errno)); 00445 goto client_start_error; 00446 } 00447 00448 flags = fcntl(desc->accept_fd, F_GETFL); 00449 fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK); 00450 00451 if (desc->tls_cfg) { 00452 desc->tls_cfg->enabled = 1; 00453 __ssl_setup(desc->tls_cfg, 1); 00454 } 00455 00456 return handle_tcptls_connection(tcptls_session); 00457 00458 client_start_error: 00459 if (desc) { 00460 close(desc->accept_fd); 00461 desc->accept_fd = -1; 00462 } 00463 ao2_ref(tcptls_session, -1); 00464 return NULL; 00465 00466 }
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 599 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().
00600 { 00601 if (tcptls_session->f) { 00602 if (fclose(tcptls_session->f)) { 00603 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); 00604 } 00605 tcptls_session->f = NULL; 00606 tcptls_session->fd = -1; 00607 } else if (tcptls_session->fd != -1) { 00608 if (close(tcptls_session->fd)) { 00609 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00610 } 00611 tcptls_session->fd = -1; 00612 } else { 00613 ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); 00614 } 00615 }
HOOK_T ast_tcptls_server_read | ( | struct ast_tcptls_session_instance * | ser, | |
void * | buf, | |||
size_t | count | |||
) |
Definition at line 111 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_read().
00112 { 00113 if (tcptls_session->fd == -1) { 00114 ast_log(LOG_ERROR, "server_read called with an fd of -1\n"); 00115 errno = EIO; 00116 return -1; 00117 } 00118 00119 #ifdef DO_SSL 00120 if (tcptls_session->ssl) 00121 return ssl_read(tcptls_session->ssl, buf, count); 00122 #endif 00123 return read(tcptls_session->fd, buf, count); 00124 }
void* ast_tcptls_server_root | ( | void * | ) |
Definition at line 271 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().
00272 { 00273 struct ast_tcptls_session_args *desc = data; 00274 int fd; 00275 struct ast_sockaddr addr; 00276 struct ast_tcptls_session_instance *tcptls_session; 00277 pthread_t launched; 00278 00279 for (;;) { 00280 int i, flags; 00281 00282 if (desc->periodic_fn) 00283 desc->periodic_fn(desc); 00284 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); 00285 if (i <= 0) 00286 continue; 00287 fd = ast_accept(desc->accept_fd, &addr); 00288 if (fd < 0) { 00289 if ((errno != EAGAIN) && (errno != EINTR)) 00290 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); 00291 continue; 00292 } 00293 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); 00294 if (!tcptls_session) { 00295 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); 00296 if (close(fd)) { 00297 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00298 } 00299 continue; 00300 } 00301 00302 ast_mutex_init(&tcptls_session->lock); 00303 tcptls_session->overflow_buf = ast_str_create(128); 00304 00305 flags = fcntl(fd, F_GETFL); 00306 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 00307 tcptls_session->fd = fd; 00308 tcptls_session->parent = desc; 00309 ast_sockaddr_copy(&tcptls_session->remote_address, &addr); 00310 00311 tcptls_session->client = 0; 00312 00313 /* This thread is now the only place that controls the single ref to tcptls_session */ 00314 if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { 00315 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno)); 00316 ast_tcptls_close_session_file(tcptls_session); 00317 ao2_ref(tcptls_session, -1); 00318 } 00319 } 00320 return NULL; 00321 }
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 530 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().
00531 { 00532 int flags; 00533 int x = 1; 00534 00535 /* Do nothing if nothing has changed */ 00536 if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { 00537 ast_debug(1, "Nothing changed in %s\n", desc->name); 00538 return; 00539 } 00540 00541 /* If we return early, there is no one listening */ 00542 ast_sockaddr_setnull(&desc->old_address); 00543 00544 /* Shutdown a running server if there is one */ 00545 if (desc->master != AST_PTHREADT_NULL) { 00546 pthread_cancel(desc->master); 00547 pthread_kill(desc->master, SIGURG); 00548 pthread_join(desc->master, NULL); 00549 } 00550 00551 if (desc->accept_fd != -1) 00552 close(desc->accept_fd); 00553 00554 /* If there's no new server, stop here */ 00555 if (ast_sockaddr_isnull(&desc->local_address)) { 00556 ast_debug(2, "Server disabled: %s\n", desc->name); 00557 return; 00558 } 00559 00560 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? 00561 AF_INET6 : AF_INET, SOCK_STREAM, 0); 00562 if (desc->accept_fd < 0) { 00563 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); 00564 return; 00565 } 00566 00567 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00568 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00569 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00570 desc->name, 00571 ast_sockaddr_stringify(&desc->local_address), 00572 strerror(errno)); 00573 goto error; 00574 } 00575 if (listen(desc->accept_fd, 10)) { 00576 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); 00577 goto error; 00578 } 00579 flags = fcntl(desc->accept_fd, F_GETFL); 00580 fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); 00581 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { 00582 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", 00583 desc->name, 00584 ast_sockaddr_stringify(&desc->local_address), 00585 strerror(errno)); 00586 goto error; 00587 } 00588 00589 /* Set current info */ 00590 ast_sockaddr_copy(&desc->old_address, &desc->local_address); 00591 00592 return; 00593 00594 error: 00595 close(desc->accept_fd); 00596 desc->accept_fd = -1; 00597 }
void ast_tcptls_server_stop | ( | struct ast_tcptls_session_args * | desc | ) |
Shutdown a running server if there is one.
Definition at line 617 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(), manager_shutdown(), and unload_module().
00618 { 00619 if (desc->master != AST_PTHREADT_NULL) { 00620 pthread_cancel(desc->master); 00621 pthread_kill(desc->master, SIGURG); 00622 pthread_join(desc->master, NULL); 00623 desc->master = AST_PTHREADT_NULL; 00624 } 00625 if (desc->accept_fd != -1) 00626 close(desc->accept_fd); 00627 desc->accept_fd = -1; 00628 ast_debug(2, "Stopped server :: %s\n", desc->name); 00629 }
HOOK_T ast_tcptls_server_write | ( | struct ast_tcptls_session_instance * | ser, | |
const void * | buf, | |||
size_t | count | |||
) |
Definition at line 126 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().
00127 { 00128 if (tcptls_session->fd == -1) { 00129 ast_log(LOG_ERROR, "server_write called with an fd of -1\n"); 00130 errno = EIO; 00131 return -1; 00132 } 00133 00134 #ifdef DO_SSL 00135 if (tcptls_session->ssl) 00136 return ssl_write(tcptls_session->ssl, buf, count); 00137 #endif 00138 return write(tcptls_session->fd, buf, count); 00139 }
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 631 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().
00632 { 00633 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { 00634 tls_cfg->enabled = ast_true(value) ? 1 : 0; 00635 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { 00636 ast_free(tls_cfg->certfile); 00637 tls_cfg->certfile = ast_strdup(value); 00638 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) { 00639 ast_free(tls_cfg->pvtfile); 00640 tls_cfg->pvtfile = ast_strdup(value); 00641 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) { 00642 ast_free(tls_cfg->cipher); 00643 tls_cfg->cipher = ast_strdup(value); 00644 } else if (!strcasecmp(varname, "tlscafile")) { 00645 ast_free(tls_cfg->cafile); 00646 tls_cfg->cafile = ast_strdup(value); 00647 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) { 00648 ast_free(tls_cfg->capath); 00649 tls_cfg->capath = ast_strdup(value); 00650 } else if (!strcasecmp(varname, "tlsverifyclient")) { 00651 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT); 00652 } else if (!strcasecmp(varname, "tlsdontverifyserver")) { 00653 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); 00654 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { 00655 if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) 00656 ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); 00657 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { 00658 if (!strcasecmp(value, "tlsv1")) { 00659 ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00660 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00661 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00662 } else if (!strcasecmp(value, "sslv3")) { 00663 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00664 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00665 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00666 } else if (!strcasecmp(value, "sslv2")) { 00667 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00668 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00669 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00670 } 00671 } else { 00672 return -1; 00673 } 00674 00675 return 0; 00676 }