Wed Jan 8 2020 09:50:21

Asterisk developer's documentation


tcptls.c File Reference

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.

Data Structures

struct  ast_tcptls_stream
 

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. More...
 
void ast_ssl_teardown (struct ast_tls_config *cfg)
 free resources used by an SSL server More...
 
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. More...
 
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. More...
 
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(). More...
 
void ast_tcptls_server_stop (struct ast_tcptls_session_args *desc)
 Shutdown a running server if there is one. More...
 
HOOK_T ast_tcptls_server_write (struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count)
 
void ast_tcptls_stream_set_exclusive_input (struct ast_tcptls_stream *stream, int exclusive_input)
 Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts. More...
 
void ast_tcptls_stream_set_timeout_disable (struct ast_tcptls_stream *stream)
 Disable the TCP/TLS stream timeout timer. More...
 
void ast_tcptls_stream_set_timeout_inactivity (struct ast_tcptls_stream *stream, int timeout)
 Set the TCP/TLS stream inactivity timeout timer. More...
 
void ast_tcptls_stream_set_timeout_sequence (struct ast_tcptls_stream *stream, struct timeval start, int timeout)
 Set the TCP/TLS stream I/O sequence timeout timer. More...
 
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. More...
 
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. More...
 
static void session_instance_destructor (void *obj)
 
static struct ast_tcptls_streamtcptls_stream_alloc (void)
 
static int tcptls_stream_close (void *cookie)
 
static void tcptls_stream_dtor (void *cookie)
 
static FILE * tcptls_stream_fopen (struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout)
 
static HOOK_T tcptls_stream_read (void *cookie, char *buf, LEN_T size)
 
static HOOK_T tcptls_stream_write (void *cookie, const char *buf, LEN_T size)
 

Detailed Description

Code to support TCP and TLS server/client.

Author
Luigi Rizzo
Brett Bryant brett.nosp@m.brya.nosp@m.nt@gm.nosp@m.ail..nosp@m.com

Definition in file tcptls.c.

Function Documentation

static int __ssl_setup ( struct ast_tls_config cfg,
int  client 
)
static

Definition at line 745 of file tcptls.c.

References ast_debug, ast_log(), 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, LOG_WARNING, ast_tls_config::pvtfile, S_OR, and ast_tls_config::ssl_ctx.

Referenced by ast_ssl_setup(), and ast_tcptls_client_start().

746 {
747 #ifndef DO_SSL
748  cfg->enabled = 0;
749  return 0;
750 #else
751  int disable_ssl = 0;
752 
753  if (!cfg->enabled)
754  return 0;
755 
756  /* Get rid of an old SSL_CTX since we're about to
757  * allocate a new one
758  */
759  if (cfg->ssl_ctx) {
760  SSL_CTX_free(cfg->ssl_ctx);
761  cfg->ssl_ctx = NULL;
762  }
763 
764  if (client) {
765 #ifndef OPENSSL_NO_SSL2
767  ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
768  cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
769  } else
770 #endif
772  ast_log(LOG_WARNING, "Usage of SSLv3 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
773  cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
774  } else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
775  cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
776  } else {
777  disable_ssl = 1;
778  cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
779  }
780  } else {
781  disable_ssl = 1;
782  cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
783  }
784 
785  if (!cfg->ssl_ctx) {
786  ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
787  cfg->enabled = 0;
788  return 0;
789  }
790 
791  /* Due to the POODLE vulnerability, completely disable
792  * SSLv2 and SSLv3 if we are not explicitly told to use
793  * them. SSLv23_*_method supports TLSv1+.
794  */
795  if (disable_ssl) {
796  long ssl_opts;
797 
798  ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
799  SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts);
800  }
801 
802  SSL_CTX_set_verify(cfg->ssl_ctx,
803  ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE,
804  NULL);
805 
806  if (!ast_strlen_zero(cfg->certfile)) {
807  char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
808  if (SSL_CTX_use_certificate_chain_file(cfg->ssl_ctx, cfg->certfile) == 0) {
809  if (!client) {
810  /* Clients don't need a certificate, but if its setup we can use it */
811  ast_verb(0, "SSL error loading cert file. <%s>", cfg->certfile);
812  cfg->enabled = 0;
813  SSL_CTX_free(cfg->ssl_ctx);
814  cfg->ssl_ctx = NULL;
815  return 0;
816  }
817  }
818  if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
819  if (!client) {
820  /* Clients don't need a private key, but if its setup we can use it */
821  ast_verb(0, "SSL error loading private key file. <%s>", tmpprivate);
822  cfg->enabled = 0;
823  SSL_CTX_free(cfg->ssl_ctx);
824  cfg->ssl_ctx = NULL;
825  return 0;
826  }
827  }
828  }
829  if (!ast_strlen_zero(cfg->cipher)) {
830  if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
831  if (!client) {
832  ast_verb(0, "SSL cipher error <%s>", cfg->cipher);
833  cfg->enabled = 0;
834  SSL_CTX_free(cfg->ssl_ctx);
835  cfg->ssl_ctx = NULL;
836  return 0;
837  }
838  }
839  }
840  if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
841  if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0)
842  ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
843  }
844 
845  ast_verb(0, "SSL certificate ok\n");
846  return 1;
847 #endif
848 }
char * pvtfile
Definition: tcptls.h:88
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
#define ast_verb(level,...)
Definition: logger.h:243
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
char * cafile
Definition: tcptls.h:90
char * certfile
Definition: tcptls.h:87
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
struct ast_flags flags
Definition: tcptls.h:92
SSL_CTX * ssl_ctx
Definition: tcptls.h:93
char * capath
Definition: tcptls.h:91
char * cipher
Definition: tcptls.h:89
int enabled
Definition: tcptls.h:86
int ast_ssl_setup ( struct ast_tls_config cfg)

Set up an SSL server.

Parameters
cfgConfiguration for the SSL server
Return values
1Success
0Failure

Definition at line 850 of file tcptls.c.

References __ssl_setup().

Referenced by __ast_http_load(), __init_manager(), and reload_config().

851 {
852  return __ssl_setup(cfg, 0);
853 }
static int __ssl_setup(struct ast_tls_config *cfg, int client)
Definition: tcptls.c:745
void ast_ssl_teardown ( struct ast_tls_config cfg)

free resources used by an SSL server

Note
This only needs to be called if ast_ssl_setup() was directly called first.
Parameters
cfgConfiguration for the SSL server

Definition at line 855 of file tcptls.c.

References ast_tls_config::ssl_ctx.

Referenced by sip_tcptls_client_args_destructor(), and unload_module().

856 {
857 #ifdef DO_SSL
858  if (cfg->ssl_ctx) {
859  SSL_CTX_free(cfg->ssl_ctx);
860  cfg->ssl_ctx = NULL;
861  }
862 #endif
863 }
SSL_CTX * ssl_ctx
Definition: tcptls.h:93
struct ast_tcptls_session_instance* ast_tcptls_client_create ( struct ast_tcptls_session_args desc)

Definition at line 902 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, desc, 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_args::remote_address, ast_tcptls_session_instance::remote_address, session_instance_destructor(), and ast_tcptls_session_args::worker_fn.

Referenced by app_exec(), and sip_prepare_socket().

903 {
904  int x = 1;
905  struct ast_tcptls_session_instance *tcptls_session = NULL;
906 
907  /* Do nothing if nothing has changed */
908  if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) {
909  ast_debug(1, "Nothing changed in %s\n", desc->name);
910  return NULL;
911  }
912 
913  /* If we return early, there is no connection */
915 
916  if (desc->accept_fd != -1)
917  close(desc->accept_fd);
918 
919  desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ?
920  AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
921  if (desc->accept_fd < 0) {
922  ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
923  desc->name, strerror(errno));
924  return NULL;
925  }
926 
927  /* if a local address was specified, bind to it so the connection will
928  originate from the desired address */
929  if (!ast_sockaddr_isnull(&desc->local_address)) {
930  setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
931  if (ast_bind(desc->accept_fd, &desc->local_address)) {
932  ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
933  desc->name,
935  strerror(errno));
936  goto error;
937  }
938  }
939 
940  if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor)))
941  goto error;
942 
943  ast_mutex_init(&tcptls_session->lock);
944  tcptls_session->overflow_buf = ast_str_create(128);
945  tcptls_session->client = 1;
946  tcptls_session->fd = desc->accept_fd;
947  tcptls_session->parent = desc;
948  tcptls_session->parent->worker_fn = NULL;
949  ast_sockaddr_copy(&tcptls_session->remote_address,
950  &desc->remote_address);
951 
952  /* Set current info */
954  return tcptls_session;
955 
956 error:
957  close(desc->accept_fd);
958  desc->accept_fd = -1;
959  if (tcptls_session)
960  ao2_ref(tcptls_session, -1);
961  return NULL;
962 }
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition: netsock2.h:121
struct ast_str * overflow_buf
Definition: tcptls.h:216
#define LOG_WARNING
Definition: logger.h:144
struct ast_tcptls_session_args * parent
Definition: tcptls.h:208
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:300
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
Definition: netsock2.c:462
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:106
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. &quot;null&quot; in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:93
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ast_sockaddr remote_address
Definition: tcptls.h:126
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static const char desc[]
Definition: cdr_radius.c:85
#define LOG_ERROR
Definition: logger.h:155
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:210
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
void *(* worker_fn)(void *)
Definition: tcptls.h:135
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
static void session_instance_destructor(void *obj)
Definition: tcptls.c:541
int errno
struct ast_sockaddr old_address
Definition: tcptls.h:125
const char * name
Definition: tcptls.h:136
#define ast_mutex_init(pmutex)
Definition: lock.h:152
struct ast_sockaddr local_address
Definition: tcptls.h:124
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:418
struct ast_sockaddr remote_address
Definition: tcptls.h:207
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.

Definition at line 865 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().

866 {
868  int flags;
869 
870  if (!(desc = tcptls_session->parent)) {
871  goto client_start_error;
872  }
873 
874  if (ast_connect(desc->accept_fd, &desc->remote_address)) {
875  ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n",
876  desc->name,
878  strerror(errno));
879  goto client_start_error;
880  }
881 
882  flags = fcntl(desc->accept_fd, F_GETFL);
883  fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK);
884 
885  if (desc->tls_cfg) {
886  desc->tls_cfg->enabled = 1;
887  __ssl_setup(desc->tls_cfg, 1);
888  }
889 
890  return handle_tcptls_connection(tcptls_session);
891 
892 client_start_error:
893  if (desc) {
894  close(desc->accept_fd);
895  desc->accept_fd = -1;
896  }
897  ao2_ref(tcptls_session, -1);
898  return NULL;
899 
900 }
struct ast_tcptls_session_args * parent
Definition: tcptls.h:208
static void * handle_tcptls_connection(void *data)
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (ce...
Definition: tcptls.c:560
arguments for the accepting thread
Definition: tcptls.h:123
struct ast_sockaddr remote_address
Definition: tcptls.h:126
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static int __ssl_setup(struct ast_tls_config *cfg, int client)
Definition: tcptls.c:745
static const char desc[]
Definition: cdr_radius.c:85
#define LOG_ERROR
Definition: logger.h:155
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:210
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
const char * name
Definition: tcptls.h:136
struct ast_tls_config * tls_cfg
Definition: tcptls.h:128
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition: netsock2.c:467
int enabled
Definition: tcptls.h:86
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 1033 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_http_send(), ast_tcptls_server_root(), handle_tcptls_connection(), httpd_helper_thread(), and sip_prepare_socket().

1034 {
1035  if (tcptls_session->f) {
1036  fflush(tcptls_session->f);
1037  if (fclose(tcptls_session->f)) {
1038  ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
1039  }
1040  tcptls_session->f = NULL;
1041  tcptls_session->fd = -1;
1042  } else if (tcptls_session->fd != -1) {
1043  /*
1044  * Issuing shutdown() is necessary here to avoid a race
1045  * condition where the last data written may not appear
1046  * in the TCP stream. See ASTERISK-23548
1047  */
1048  shutdown(tcptls_session->fd, SHUT_RDWR);
1049  if (close(tcptls_session->fd)) {
1050  ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
1051  }
1052  tcptls_session->fd = -1;
1053  } else {
1054  ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
1055  }
1056 }
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
HOOK_T ast_tcptls_server_read ( struct ast_tcptls_session_instance tcptls_session,
void *  buf,
size_t  count 
)

Definition at line 519 of file tcptls.c.

References ast_log(), errno, ast_tcptls_stream::fd, LOG_ERROR, ast_tcptls_session_instance::stream_cookie, and tcptls_stream_read().

Referenced by sip_tcptls_read().

520 {
521  if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) {
522  ast_log(LOG_ERROR, "TCP/TLS read called on invalid stream.\n");
523  errno = EIO;
524  return -1;
525  }
526 
527  return tcptls_stream_read(tcptls_session->stream_cookie, buf, count);
528 }
static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
Definition: tcptls.c:126
struct ast_tcptls_stream * stream_cookie
Definition: tcptls.h:218
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
int fd
The socket returned by accept().
Definition: tcptls.c:70
void* ast_tcptls_server_root ( void *  data)

Definition at line 693 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().

694 {
695  struct ast_tcptls_session_args *desc = data;
696  int fd;
697  struct ast_sockaddr addr;
698  struct ast_tcptls_session_instance *tcptls_session;
699  pthread_t launched;
700 
701  for (;;) {
702  int i, flags;
703 
704  if (desc->periodic_fn)
705  desc->periodic_fn(desc);
706  i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
707  if (i <= 0)
708  continue;
709  fd = ast_accept(desc->accept_fd, &addr);
710  if (fd < 0) {
711  if ((errno != EAGAIN) && (errno != EINTR))
712  ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
713  continue;
714  }
715  tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
716  if (!tcptls_session) {
717  ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
718  if (close(fd)) {
719  ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
720  }
721  continue;
722  }
723 
724  ast_mutex_init(&tcptls_session->lock);
725  tcptls_session->overflow_buf = ast_str_create(128);
726 
727  flags = fcntl(fd, F_GETFL);
728  fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
729  tcptls_session->fd = fd;
730  tcptls_session->parent = desc;
731  ast_sockaddr_copy(&tcptls_session->remote_address, &addr);
732 
733  tcptls_session->client = 0;
734 
735  /* This thread is now the only place that controls the single ref to tcptls_session */
736  if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) {
737  ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
738  ast_tcptls_close_session_file(tcptls_session);
739  ao2_ref(tcptls_session, -1);
740  }
741  }
742  return NULL;
743 }
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition: netsock2.h:121
struct ast_str * overflow_buf
Definition: tcptls.h:216
#define LOG_WARNING
Definition: logger.h:144
struct ast_tcptls_session_args * parent
Definition: tcptls.h:208
static void * handle_tcptls_connection(void *data)
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (ce...
Definition: tcptls.c:560
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
arguments for the accepting thread
Definition: tcptls.h:123
Socket address structure.
Definition: netsock2.h:63
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:431
int ast_accept(int sockfd, struct ast_sockaddr *addr)
Wrapper around accept(2) that uses struct ast_sockaddr.
Definition: netsock2.c:456
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static const char desc[]
Definition: cdr_radius.c:85
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
static void session_instance_destructor(void *obj)
Definition: tcptls.c:541
int errno
void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session)
Closes a tcptls session instance&#39;s file and/or file descriptor. The tcptls_session will be set to NUL...
Definition: tcptls.c:1033
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1255
#define ast_mutex_init(pmutex)
Definition: lock.h:152
void(* periodic_fn)(void *)
Definition: tcptls.h:134
struct ast_sockaddr remote_address
Definition: tcptls.h:207
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().

Version
1.6.1 changed desc parameter to be of ast_tcptls_session_args type

Definition at line 964 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().

965 {
966  int flags;
967  int x = 1;
968 
969  /* Do nothing if nothing has changed */
970  if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
971  ast_debug(1, "Nothing changed in %s\n", desc->name);
972  return;
973  }
974 
975  /* If we return early, there is no one listening */
977 
978  /* Shutdown a running server if there is one */
979  if (desc->master != AST_PTHREADT_NULL) {
980  pthread_cancel(desc->master);
981  pthread_kill(desc->master, SIGURG);
982  pthread_join(desc->master, NULL);
983  }
984 
985  if (desc->accept_fd != -1)
986  close(desc->accept_fd);
987 
988  /* If there's no new server, stop here */
989  if (ast_sockaddr_isnull(&desc->local_address)) {
990  ast_debug(2, "Server disabled: %s\n", desc->name);
991  return;
992  }
993 
994  desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ?
995  AF_INET6 : AF_INET, SOCK_STREAM, 0);
996  if (desc->accept_fd < 0) {
997  ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
998  return;
999  }
1000 
1001  setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1002  if (ast_bind(desc->accept_fd, &desc->local_address)) {
1003  ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
1004  desc->name,
1006  strerror(errno));
1007  goto error;
1008  }
1009  if (listen(desc->accept_fd, 10)) {
1010  ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
1011  goto error;
1012  }
1013  flags = fcntl(desc->accept_fd, F_GETFL);
1014  fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
1015  if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
1016  ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
1017  desc->name,
1019  strerror(errno));
1020  goto error;
1021  }
1022 
1023  /* Set current info */
1025 
1026  return;
1027 
1028 error:
1029  close(desc->accept_fd);
1030  desc->accept_fd = -1;
1031 }
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition: netsock2.h:121
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:300
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
Definition: netsock2.c:462
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:106
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. &quot;null&quot; in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:93
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define AST_PTHREADT_NULL
Definition: lock.h:65
#define LOG_ERROR
Definition: logger.h:155
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:210
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
struct ast_sockaddr old_address
Definition: tcptls.h:125
const char * name
Definition: tcptls.h:136
struct ast_sockaddr local_address
Definition: tcptls.h:124
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:418
void *(* accept_fn)(void *)
Definition: tcptls.h:133
void ast_tcptls_server_stop ( struct ast_tcptls_session_args desc)

Shutdown a running server if there is one.

Version
1.6.1 changed desc parameter to be of ast_tcptls_session_args type

Definition at line 1058 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().

1059 {
1060  if (desc->master != AST_PTHREADT_NULL) {
1061  pthread_cancel(desc->master);
1062  pthread_kill(desc->master, SIGURG);
1063  pthread_join(desc->master, NULL);
1064  desc->master = AST_PTHREADT_NULL;
1065  }
1066  if (desc->accept_fd != -1)
1067  close(desc->accept_fd);
1068  desc->accept_fd = -1;
1069  ast_debug(2, "Stopped server :: %s\n", desc->name);
1070 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define AST_PTHREADT_NULL
Definition: lock.h:65
const char * name
Definition: tcptls.h:136
HOOK_T ast_tcptls_server_write ( struct ast_tcptls_session_instance tcptls_session,
const void *  buf,
size_t  count 
)

Definition at line 530 of file tcptls.c.

References ast_log(), errno, ast_tcptls_stream::fd, LOG_ERROR, ast_tcptls_session_instance::stream_cookie, and tcptls_stream_write().

Referenced by _sip_tcp_helper_thread().

531 {
532  if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) {
533  ast_log(LOG_ERROR, "TCP/TLS write called on invalid stream.\n");
534  errno = EIO;
535  return -1;
536  }
537 
538  return tcptls_stream_write(tcptls_session->stream_cookie, buf, count);
539 }
struct ast_tcptls_stream * stream_cookie
Definition: tcptls.h:218
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
int fd
The socket returned by accept().
Definition: tcptls.c:70
static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size)
Definition: tcptls.c:250
void ast_tcptls_stream_set_exclusive_input ( struct ast_tcptls_stream stream,
int  exclusive_input 
)

Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts.

Parameters
streamTCP/TLS stream control data.
exclusive_inputTRUE if stream can exclusively wait for fd input. Otherwise, the stream will not wait for fd input. It will wait while trying to send data.
Note
The stream timeouts still need to be set.
Returns
Nothing

Definition at line 107 of file tcptls.c.

References ast_assert, and ast_tcptls_stream::exclusive_input.

Referenced by _sip_tcp_helper_thread(), httpd_helper_thread(), and session_do().

108 {
109  ast_assert(stream != NULL);
110 
111  stream->exclusive_input = exclusive_input;
112 }
#define ast_assert(a)
Definition: utils.h:738
int exclusive_input
Definition: tcptls.c:81
void ast_tcptls_stream_set_timeout_disable ( struct ast_tcptls_stream stream)

Disable the TCP/TLS stream timeout timer.

Parameters
streamTCP/TLS stream control data.
Returns
Nothing

Definition at line 84 of file tcptls.c.

References ast_assert, and ast_tcptls_stream::timeout.

Referenced by _sip_tcp_helper_thread(), and session_do().

85 {
86  ast_assert(stream != NULL);
87 
88  stream->timeout = -1;
89 }
#define ast_assert(a)
Definition: utils.h:738
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
void ast_tcptls_stream_set_timeout_inactivity ( struct ast_tcptls_stream stream,
int  timeout 
)

Set the TCP/TLS stream inactivity timeout timer.

Parameters
streamTCP/TLS stream control data.
timeoutNumber of milliseconds to wait for data transfer with the peer.

This is basically how much time we are willing to spend in an I/O call before we declare the peer unresponsive.

Note
Setting timeout to -1 disables the timeout.
Setting this timeout replaces the I/O sequence timeout timer.
Returns
Nothing

Definition at line 91 of file tcptls.c.

References ast_assert, ast_tcptls_stream::start, and ast_tcptls_stream::timeout.

Referenced by httpd_helper_thread().

92 {
93  ast_assert(stream != NULL);
94 
95  stream->start.tv_sec = 0;
96  stream->timeout = timeout;
97 }
struct timeval start
Start time from when an I/O sequence must complete by struct ast_tcptls_stream.timeout.
Definition: tcptls.c:64
#define ast_assert(a)
Definition: utils.h:738
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
void ast_tcptls_stream_set_timeout_sequence ( struct ast_tcptls_stream stream,
struct timeval  start,
int  timeout 
)

Set the TCP/TLS stream I/O sequence timeout timer.

Parameters
streamTCP/TLS stream control data.
startTime the I/O sequence timer starts.
timeoutNumber of milliseconds from the start time before timeout.

This is how much time are we willing to allow the peer to complete an operation that can take several I/O calls. The main use is as an authentication timer with us.

Note
Setting timeout to -1 disables the timeout.
Setting this timeout replaces the inactivity timeout timer.
Returns
Nothing

Definition at line 99 of file tcptls.c.

References ast_assert, ast_tcptls_stream::start, and ast_tcptls_stream::timeout.

Referenced by _sip_tcp_helper_thread(), and session_do().

100 {
101  ast_assert(stream != NULL);
102 
103  stream->start = start;
104  stream->timeout = timeout;
105 }
struct timeval start
Start time from when an I/O sequence must complete by struct ast_tcptls_stream.timeout.
Definition: tcptls.c:64
#define ast_assert(a)
Definition: utils.h:738
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
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 1072 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().

1073 {
1074  if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
1075  tls_cfg->enabled = ast_true(value) ? 1 : 0;
1076  } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
1077  ast_free(tls_cfg->certfile);
1078  tls_cfg->certfile = ast_strdup(value);
1079  } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
1080  ast_free(tls_cfg->pvtfile);
1081  tls_cfg->pvtfile = ast_strdup(value);
1082  } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
1083  ast_free(tls_cfg->cipher);
1084  tls_cfg->cipher = ast_strdup(value);
1085  } else if (!strcasecmp(varname, "tlscafile")) {
1086  ast_free(tls_cfg->cafile);
1087  tls_cfg->cafile = ast_strdup(value);
1088  } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
1089  ast_free(tls_cfg->capath);
1090  tls_cfg->capath = ast_strdup(value);
1091  } else if (!strcasecmp(varname, "tlsverifyclient")) {
1093  } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
1095  } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
1096  if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address))
1097  ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value);
1098  } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
1099  if (!strcasecmp(value, "tlsv1")) {
1103  } else if (!strcasecmp(value, "sslv3")) {
1107  } else if (!strcasecmp(value, "sslv2")) {
1111  }
1112  } else {
1113  return -1;
1114  }
1115 
1116  return 0;
1117 }
char * pvtfile
Definition: tcptls.h:88
#define ast_strdup(a)
Definition: astmm.h:109
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
int value
Definition: syslog.c:39
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: config.c:2805
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
char * cafile
Definition: tcptls.h:90
#define ast_free(a)
Definition: astmm.h:97
char * certfile
Definition: tcptls.h:87
#define ast_clear_flag(p, flag)
Definition: utils.h:77
struct ast_flags flags
Definition: tcptls.h:92
char * capath
Definition: tcptls.h:91
struct ast_sockaddr local_address
Definition: tcptls.h:124
char * cipher
Definition: tcptls.h:89
int enabled
Definition: tcptls.h:86
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.

Note
must decrement ref count before returning NULL on error

Definition at line 560 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, ast_tls_config::ssl_ctx, str, ast_tcptls_session_instance::stream_cookie, tcptls_stream_alloc(), tcptls_stream_fopen(), ast_tcptls_session_args::tls_cfg, and ast_tcptls_session_args::worker_fn.

Referenced by ast_tcptls_client_start(), and ast_tcptls_server_root().

561 {
562  struct ast_tcptls_session_instance *tcptls_session = data;
563 #ifdef DO_SSL
564  int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept;
565  int ret;
566  char err[256];
567 #endif
568 
569  /* TCP/TLS connections are associated with external protocols, and
570  * should not be allowed to execute 'dangerous' functions. This may
571  * need to be pushed down into the individual protocol handlers, but
572  * this seems like a good general policy.
573  */
575  ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection\n");
576  ast_tcptls_close_session_file(tcptls_session);
577  ao2_ref(tcptls_session, -1);
578  return NULL;
579  }
580 
581  tcptls_session->stream_cookie = tcptls_stream_alloc();
582  if (!tcptls_session->stream_cookie) {
583  ast_tcptls_close_session_file(tcptls_session);
584  ao2_ref(tcptls_session, -1);
585  return NULL;
586  }
587 
588  /*
589  * open a FILE * as appropriate.
590  */
591  if (!tcptls_session->parent->tls_cfg) {
592  tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, NULL,
593  tcptls_session->fd, -1);
594  if (tcptls_session->f) {
595  if (setvbuf(tcptls_session->f, NULL, _IONBF, 0)) {
596  ast_tcptls_close_session_file(tcptls_session);
597  }
598  }
599  }
600 #ifdef DO_SSL
601  else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) {
602  SSL_set_fd(tcptls_session->ssl, tcptls_session->fd);
603  if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) {
604  ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
605  } else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie,
606  tcptls_session->ssl, tcptls_session->fd, -1))) {
607  if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
608  || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
609  X509 *peer;
610  long res;
611  peer = SSL_get_peer_certificate(tcptls_session->ssl);
612  if (!peer) {
613  ast_log(LOG_ERROR, "No peer SSL certificate to verify\n");
614  ast_tcptls_close_session_file(tcptls_session);
615  ao2_ref(tcptls_session, -1);
616  return NULL;
617  }
618 
619  res = SSL_get_verify_result(tcptls_session->ssl);
620  if (res != X509_V_OK) {
621  ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res));
622  X509_free(peer);
623  ast_tcptls_close_session_file(tcptls_session);
624  ao2_ref(tcptls_session, -1);
625  return NULL;
626  }
627  if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) {
628  ASN1_STRING *str;
629  unsigned char *str2;
630  X509_NAME *name = X509_get_subject_name(peer);
631  int pos = -1;
632  int found = 0;
633 
634  for (;;) {
635  /* Walk the certificate to check all available "Common Name" */
636  /* XXX Probably should do a gethostbyname on the hostname and compare that as well */
637  pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
638  if (pos < 0)
639  break;
640  str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
641  ret = ASN1_STRING_to_UTF8(&str2, str);
642  if (ret < 0) {
643  continue;
644  }
645 
646  if (str2) {
647  if (strlen((char *) str2) != ret) {
648  ast_log(LOG_WARNING, "Invalid certificate common name length (contains NULL bytes?)\n");
649  } else if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) {
650  found = 1;
651  }
652  ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2);
653  OPENSSL_free(str2);
654  }
655  if (found)
656  break;
657  }
658  if (!found) {
659  ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname);
660  X509_free(peer);
661  ast_tcptls_close_session_file(tcptls_session);
662  ao2_ref(tcptls_session, -1);
663  return NULL;
664  }
665  }
666  X509_free(peer);
667  }
668  }
669  if (!tcptls_session->f) /* no success opening descriptor stacking */
670  SSL_free(tcptls_session->ssl);
671  }
672 #endif /* DO_SSL */
673 
674  if (!tcptls_session->f) {
675  ast_tcptls_close_session_file(tcptls_session);
676  ast_log(LOG_WARNING, "FILE * open failed!\n");
677 #ifndef DO_SSL
678  if (tcptls_session->parent->tls_cfg) {
679  ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n");
680  }
681 #endif
682  ao2_ref(tcptls_session, -1);
683  return NULL;
684  }
685 
686  if (tcptls_session->parent->worker_fn) {
687  return tcptls_session->parent->worker_fn(tcptls_session);
688  } else {
689  return tcptls_session;
690  }
691 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
struct ast_tcptls_session_args * parent
Definition: tcptls.h:208
const char * str
Definition: app_jack.c:144
static FILE * tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout)
Definition: tcptls.c:478
#define ast_verb(level,...)
Definition: logger.h:243
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ao2_ref(o, delta)
Definition: astobj2.h:472
struct ast_tcptls_stream * stream_cookie
Definition: tcptls.h:218
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
void *(* worker_fn)(void *)
Definition: tcptls.h:135
static const char name[]
static struct ast_tcptls_stream * tcptls_stream_alloc(void)
Definition: tcptls.c:454
void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session)
Closes a tcptls session instance&#39;s file and/or file descriptor. The tcptls_session will be set to NUL...
Definition: tcptls.c:1033
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
Definition: pbx.c:4072
struct ast_flags flags
Definition: tcptls.h:92
SSL_CTX * ssl_ctx
Definition: tcptls.h:93
struct ast_tls_config * tls_cfg
Definition: tcptls.h:128
char hostname[MAXHOSTNAMELEN]
Definition: tcptls.h:127
static void session_instance_destructor ( void *  obj)
static

Definition at line 541 of file tcptls.c.

References ao2_t_ref, ast_free, ast_mutex_destroy, ast_tcptls_session_instance::lock, ast_tcptls_session_instance::overflow_buf, and ast_tcptls_session_instance::stream_cookie.

Referenced by ast_tcptls_client_create(), and ast_tcptls_server_root().

542 {
543  struct ast_tcptls_session_instance *i = obj;
544 
545  if (i->stream_cookie) {
546  ao2_t_ref(i->stream_cookie, -1, "Destroying tcptls session instance");
547  i->stream_cookie = NULL;
548  }
550  ast_mutex_destroy(&i->lock);
551 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:471
struct ast_str * overflow_buf
Definition: tcptls.h:216
struct ast_tcptls_stream * stream_cookie
Definition: tcptls.h:218
#define ast_free(a)
Definition: astmm.h:97
#define ast_mutex_destroy(a)
Definition: lock.h:154
static struct ast_tcptls_stream* tcptls_stream_alloc ( void  )
static

Definition at line 454 of file tcptls.c.

References ao2_alloc, ast_tcptls_stream::fd, tcptls_stream_dtor(), and ast_tcptls_stream::timeout.

Referenced by handle_tcptls_connection().

455 {
456  struct ast_tcptls_stream *stream;
457 
458  stream = ao2_alloc(sizeof(*stream), tcptls_stream_dtor);
459  if (stream) {
460  stream->fd = -1;
461  stream->timeout = -1;
462  }
463  return stream;
464 }
static void tcptls_stream_dtor(void *cookie)
Definition: tcptls.c:435
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
int fd
The socket returned by accept().
Definition: tcptls.c:70
static int tcptls_stream_close ( void *  cookie)
static

Definition at line 373 of file tcptls.c.

References ao2_t_ref, ast_log(), errno, ast_tcptls_stream::fd, LOG_ERROR, and ast_tcptls_stream::ssl.

Referenced by tcptls_stream_fopen().

374 {
375  struct ast_tcptls_stream *stream = cookie;
376 
377  if (!stream) {
378  errno = EBADF;
379  return -1;
380  }
381 
382  if (stream->fd != -1) {
383 #if defined(DO_SSL)
384  if (stream->ssl) {
385  int res;
386 
387  /*
388  * According to the TLS standard, it is acceptable for an
389  * application to only send its shutdown alert and then
390  * close the underlying connection without waiting for
391  * the peer's response (this way resources can be saved,
392  * as the process can already terminate or serve another
393  * connection).
394  */
395  res = SSL_shutdown(stream->ssl);
396  if (res < 0) {
397  ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n",
398  SSL_get_error(stream->ssl, res));
399  }
400 
401  if (!stream->ssl->server) {
402  /* For client threads, ensure that the error stack is cleared */
403  ERR_remove_state(0);
404  }
405 
406  SSL_free(stream->ssl);
407  stream->ssl = NULL;
408  }
409 #endif /* defined(DO_SSL) */
410 
411  /*
412  * Issuing shutdown() is necessary here to avoid a race
413  * condition where the last data written may not appear
414  * in the TCP stream. See ASTERISK-23548
415  */
416  shutdown(stream->fd, SHUT_RDWR);
417  if (close(stream->fd)) {
418  ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
419  }
420  stream->fd = -1;
421  }
422  ao2_t_ref(stream, -1, "Closed tcptls stream cookie");
423 
424  return 0;
425 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:471
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
int fd
The socket returned by accept().
Definition: tcptls.c:70
static void tcptls_stream_dtor ( void *  cookie)
static

Definition at line 435 of file tcptls.c.

References ast_assert, and ast_tcptls_stream::fd.

Referenced by tcptls_stream_alloc().

436 {
437 #ifdef AST_DEVMODE
438  /* Since the ast_assert below is the only one using stream,
439  * and ast_assert is only available with AST_DEVMODE, we
440  * put this in a conditional to avoid compiler warnings. */
441  struct ast_tcptls_stream *stream = cookie;
442 #endif
443 
444  ast_assert(stream->fd == -1);
445 }
#define ast_assert(a)
Definition: utils.h:738
int fd
The socket returned by accept().
Definition: tcptls.c:70
static FILE* tcptls_stream_fopen ( struct ast_tcptls_stream stream,
SSL *  ssl,
int  fd,
int  timeout 
)
static

Definition at line 478 of file tcptls.c.

References ao2_t_ref, ast_debug, ast_tcptls_stream::fd, ast_tcptls_stream::ssl, tcptls_stream_close(), tcptls_stream_read(), tcptls_stream_write(), and ast_tcptls_stream::timeout.

Referenced by handle_tcptls_connection().

479 {
480  FILE *fp;
481 
482 #if defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
483  static const cookie_io_functions_t cookie_funcs = {
486  NULL,
488  };
489 #endif /* defined(HAVE_FOPENCOOKIE) */
490 
491  if (fd == -1) {
492  /* Socket not open. */
493  return NULL;
494  }
495 
496  stream->ssl = ssl;
497  stream->fd = fd;
498  stream->timeout = timeout;
499  ao2_t_ref(stream, +1, "Opening tcptls stream cookie");
500 
501 #if defined(HAVE_FUNOPEN) /* the BSD interface */
502  fp = funopen(stream, tcptls_stream_read, tcptls_stream_write, NULL,
504 #elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
505  fp = fopencookie(stream, "w+", cookie_funcs);
506 #else
507  /* could add other methods here */
508  ast_debug(2, "No stream FILE methods attempted!\n");
509  fp = NULL;
510 #endif
511 
512  if (!fp) {
513  stream->fd = -1;
514  ao2_t_ref(stream, -1, "Failed to open tcptls stream cookie");
515  }
516  return fp;
517 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:471
static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
Definition: tcptls.c:126
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int fd
The socket returned by accept().
Definition: tcptls.c:70
static int tcptls_stream_close(void *cookie)
Definition: tcptls.c:373
static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size)
Definition: tcptls.c:250
static HOOK_T tcptls_stream_read ( void *  cookie,
char *  buf,
LEN_T  size 
)
static

Definition at line 126 of file tcptls.c.

References ast_debug, ast_remaining_ms(), ast_tvnow(), ast_wait_for_input(), ast_wait_for_output(), errno, ast_tcptls_stream::exclusive_input, ast_tcptls_stream::fd, ast_tcptls_stream::ssl, ast_tcptls_stream::start, and ast_tcptls_stream::timeout.

Referenced by ast_tcptls_server_read(), and tcptls_stream_fopen().

127 {
128  struct ast_tcptls_stream *stream = cookie;
129  struct timeval start;
130  int ms;
131  int res;
132 
133  if (!size) {
134  /* You asked for no data you got no data. */
135  return 0;
136  }
137 
138  if (!stream || stream->fd == -1) {
139  errno = EBADF;
140  return -1;
141  }
142 
143  if (stream->start.tv_sec) {
144  start = stream->start;
145  } else {
146  start = ast_tvnow();
147  }
148 
149 #if defined(DO_SSL)
150  if (stream->ssl) {
151  for (;;) {
152  res = SSL_read(stream->ssl, buf, size);
153  if (0 < res) {
154  /* We read some payload data. */
155  return res;
156  }
157  switch (SSL_get_error(stream->ssl, res)) {
158  case SSL_ERROR_ZERO_RETURN:
159  /* Report EOF for a shutdown */
160  ast_debug(1, "TLS clean shutdown alert reading data\n");
161  return 0;
162  case SSL_ERROR_WANT_READ:
163  if (!stream->exclusive_input) {
164  /* We cannot wait for data now. */
165  errno = EAGAIN;
166  return -1;
167  }
168  while ((ms = ast_remaining_ms(start, stream->timeout))) {
169  res = ast_wait_for_input(stream->fd, ms);
170  if (0 < res) {
171  /* Socket is ready to be read. */
172  break;
173  }
174  if (res < 0) {
175  if (errno == EINTR || errno == EAGAIN) {
176  /* Try again. */
177  continue;
178  }
179  ast_debug(1, "TLS socket error waiting for read data: %s\n",
180  strerror(errno));
181  return -1;
182  }
183  }
184  break;
185  case SSL_ERROR_WANT_WRITE:
186  while ((ms = ast_remaining_ms(start, stream->timeout))) {
187  res = ast_wait_for_output(stream->fd, ms);
188  if (0 < res) {
189  /* Socket is ready to be written. */
190  break;
191  }
192  if (res < 0) {
193  if (errno == EINTR || errno == EAGAIN) {
194  /* Try again. */
195  continue;
196  }
197  ast_debug(1, "TLS socket error waiting for write space: %s\n",
198  strerror(errno));
199  return -1;
200  }
201  }
202  break;
203  default:
204  /* Report EOF for an undecoded SSL or transport error. */
205  ast_debug(1, "TLS transport or SSL error reading data\n");
206  return 0;
207  }
208  if (!ms) {
209  /* Report EOF for a timeout */
210  ast_debug(1, "TLS timeout reading data\n");
211  return 0;
212  }
213  }
214  }
215 #endif /* defined(DO_SSL) */
216 
217  for (;;) {
218  res = read(stream->fd, buf, size);
219  if (0 <= res || !stream->exclusive_input) {
220  /* Got data or we cannot wait for it. */
221  return res;
222  }
223  if (errno != EINTR && errno != EAGAIN) {
224  /* Not a retryable error. */
225  ast_debug(1, "TCP socket error reading data: %s\n",
226  strerror(errno));
227  return -1;
228  }
229  ms = ast_remaining_ms(start, stream->timeout);
230  if (!ms) {
231  /* Report EOF for a timeout */
232  ast_debug(1, "TCP timeout reading data\n");
233  return 0;
234  }
235  ast_wait_for_input(stream->fd, ms);
236  }
237 }
struct timeval start
Start time from when an I/O sequence must complete by struct ast_tcptls_stream.timeout.
Definition: tcptls.c:64
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:1615
int errno
int exclusive_input
Definition: tcptls.c:81
int fd
The socket returned by accept().
Definition: tcptls.c:70
int ast_wait_for_output(int fd, int ms)
Definition: utils.c:1265
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1255
static HOOK_T tcptls_stream_write ( void *  cookie,
const char *  buf,
LEN_T  size 
)
static

Definition at line 250 of file tcptls.c.

References ast_debug, ast_remaining_ms(), ast_tvnow(), ast_wait_for_input(), ast_wait_for_output(), errno, ast_tcptls_stream::fd, ast_tcptls_stream::ssl, ast_tcptls_stream::start, and ast_tcptls_stream::timeout.

Referenced by ast_tcptls_server_write(), and tcptls_stream_fopen().

251 {
252  struct ast_tcptls_stream *stream = cookie;
253  struct timeval start;
254  int ms;
255  int res;
256  int written;
257  int remaining;
258 
259  if (!size) {
260  /* You asked to write no data you wrote no data. */
261  return 0;
262  }
263 
264  if (!stream || stream->fd == -1) {
265  errno = EBADF;
266  return -1;
267  }
268 
269  if (stream->start.tv_sec) {
270  start = stream->start;
271  } else {
272  start = ast_tvnow();
273  }
274 
275 #if defined(DO_SSL)
276  if (stream->ssl) {
277  written = 0;
278  remaining = size;
279  for (;;) {
280  res = SSL_write(stream->ssl, buf + written, remaining);
281  if (res == remaining) {
282  /* Everything was written. */
283  return size;
284  }
285  if (0 < res) {
286  /* Successfully wrote part of the buffer. Try to write the rest. */
287  written += res;
288  remaining -= res;
289  continue;
290  }
291  switch (SSL_get_error(stream->ssl, res)) {
292  case SSL_ERROR_ZERO_RETURN:
293  ast_debug(1, "TLS clean shutdown alert writing data\n");
294  if (written) {
295  /* Report partial write. */
296  return written;
297  }
298  errno = EBADF;
299  return -1;
300  case SSL_ERROR_WANT_READ:
301  ms = ast_remaining_ms(start, stream->timeout);
302  if (!ms) {
303  /* Report partial write. */
304  ast_debug(1, "TLS timeout writing data (want read)\n");
305  return written;
306  }
307  ast_wait_for_input(stream->fd, ms);
308  break;
309  case SSL_ERROR_WANT_WRITE:
310  ms = ast_remaining_ms(start, stream->timeout);
311  if (!ms) {
312  /* Report partial write. */
313  ast_debug(1, "TLS timeout writing data (want write)\n");
314  return written;
315  }
316  ast_wait_for_output(stream->fd, ms);
317  break;
318  default:
319  /* Undecoded SSL or transport error. */
320  ast_debug(1, "TLS transport or SSL error writing data\n");
321  if (written) {
322  /* Report partial write. */
323  return written;
324  }
325  errno = EBADF;
326  return -1;
327  }
328  }
329  }
330 #endif /* defined(DO_SSL) */
331 
332  written = 0;
333  remaining = size;
334  for (;;) {
335  res = write(stream->fd, buf + written, remaining);
336  if (res == remaining) {
337  /* Yay everything was written. */
338  return size;
339  }
340  if (0 < res) {
341  /* Successfully wrote part of the buffer. Try to write the rest. */
342  written += res;
343  remaining -= res;
344  continue;
345  }
346  if (errno != EINTR && errno != EAGAIN) {
347  /* Not a retryable error. */
348  ast_debug(1, "TCP socket error writing: %s\n", strerror(errno));
349  if (written) {
350  return written;
351  }
352  return -1;
353  }
354  ms = ast_remaining_ms(start, stream->timeout);
355  if (!ms) {
356  /* Report partial write. */
357  ast_debug(1, "TCP timeout writing data\n");
358  return written;
359  }
360  ast_wait_for_output(stream->fd, ms);
361  }
362 }
struct timeval start
Start time from when an I/O sequence must complete by struct ast_tcptls_stream.timeout.
Definition: tcptls.c:64
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Definition: tcptls.c:79
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:1615
int errno
int fd
The socket returned by accept().
Definition: tcptls.c:70
int ast_wait_for_output(int fd, int ms)
Definition: utils.c:1265
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1255