mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
- Generalize the function ssl_setup() so that the certificate info
are passed as an argument. - Update the code in main/http.c to use the new interface (the diff is large but mostly mechanical, due to the name change of several variables); - And since now it is trivial, implement "AMI over TLS", and document the possible options in manager.conf - And since the test client (openssl s_client -connect host:port ) does not generate \r\n as a line terminator, make get_input() also accept just a \n as a line terminator (Mac users: do you also need the \r-only version ?) The option parsing in manager.conf is not very efficient, and needs to be cleaned up and made similar to what we have in http.conf git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48351 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -26,6 +26,18 @@ enabled = no
|
||||
port = 5038
|
||||
;httptimeout = 60
|
||||
bindaddr = 0.0.0.0
|
||||
|
||||
; Parameters that control AMI over TLS. ("enabled" must be set too).
|
||||
; You can open a connection to this socket with e.g.
|
||||
;
|
||||
; openssl s_client -connect my_host:5039
|
||||
;
|
||||
; sslenable=no ; set to YES to enable it
|
||||
; sslbindport=5039 ; the port to bind to
|
||||
; sslbindaddr=0.0.0.0 ; address to bind to, default to bindaddr
|
||||
; sslcert=/tmp/asterisk.pem ; path to the certificate.
|
||||
|
||||
|
||||
;displayconnects = yes
|
||||
;
|
||||
; Add a Unix epoch timestamp to events (not action responses)
|
||||
|
@@ -60,9 +60,21 @@
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#else
|
||||
typedef struct {} SSL; /* so we can define a pointer to it */
|
||||
/* declare dummy types so we can define a pointer to them */
|
||||
typedef struct {} SSL;
|
||||
typedef struct {} SSL_CTX;
|
||||
#endif /* DO_SSL */
|
||||
|
||||
/* SSL support */
|
||||
#define AST_CERTFILE "asterisk.pem"
|
||||
|
||||
struct tls_config {
|
||||
int enabled;
|
||||
char *certfile;
|
||||
char *cipher;
|
||||
SSL_CTX *ssl_ctx;
|
||||
};
|
||||
|
||||
/*!
|
||||
* The following code implements a generic mechanism for starting
|
||||
* services on a TCP or TLS socket.
|
||||
@@ -111,7 +123,7 @@ struct server_instance {
|
||||
struct server_args {
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in oldsin;
|
||||
int is_ssl; /* is this an SSL accept ? */
|
||||
struct tls_config *tls_cfg; /* points to the SSL configuration if any */
|
||||
int accept_fd;
|
||||
int poll_timeout;
|
||||
pthread_t master;
|
||||
@@ -123,7 +135,7 @@ struct server_args {
|
||||
|
||||
void *server_root(void *);
|
||||
void server_start(struct server_args *desc);
|
||||
int ssl_setup(void);
|
||||
int ssl_setup(struct tls_config *cfg);
|
||||
|
||||
/*! \brief HTTP Callbacks take the socket, the method and the path as arguments and should
|
||||
return the content, allocated with malloc(). Status should be changed to reflect
|
||||
|
81
main/http.c
81
main/http.c
@@ -73,26 +73,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
*
|
||||
* We declare most of ssl support variables unconditionally,
|
||||
* because their number is small and this simplifies the code.
|
||||
*
|
||||
* NOTE: the ssl-support variables (ssl_ctx, do_ssl, certfile, cipher)
|
||||
* and their setup should be moved to a more central place, e.g. asterisk.conf
|
||||
* and the source files that processes it. Similarly, ssl_setup() should
|
||||
* be run earlier in the startup process so modules have it available.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
|
||||
#define DO_SSL /* comment in/out if you want to support ssl */
|
||||
#endif
|
||||
|
||||
#ifdef DO_SSL
|
||||
static SSL_CTX* ssl_ctx;
|
||||
#endif /* DO_SSL */
|
||||
|
||||
/* SSL support */
|
||||
#define AST_CERTFILE "asterisk.pem"
|
||||
static int do_ssl;
|
||||
static char *certfile;
|
||||
static char *cipher;
|
||||
static struct tls_config http_tls_cfg;
|
||||
|
||||
static void *httpd_helper_thread(void *arg);
|
||||
|
||||
@@ -102,7 +89,7 @@ static void *httpd_helper_thread(void *arg);
|
||||
static struct server_args http_desc = {
|
||||
.accept_fd = -1,
|
||||
.master = AST_PTHREADT_NULL,
|
||||
.is_ssl = 0,
|
||||
.tls_cfg = NULL,
|
||||
.poll_timeout = -1,
|
||||
.name = "http server",
|
||||
.accept_fn = server_root,
|
||||
@@ -112,7 +99,7 @@ static struct server_args http_desc = {
|
||||
static struct server_args https_desc = {
|
||||
.accept_fd = -1,
|
||||
.master = AST_PTHREADT_NULL,
|
||||
.is_ssl = 1,
|
||||
.tls_cfg = &http_tls_cfg,
|
||||
.poll_timeout = -1,
|
||||
.name = "https server",
|
||||
.accept_fn = server_root,
|
||||
@@ -250,7 +237,7 @@ static char *httpstatus_callback(struct sockaddr_in *req, const char *uri, struc
|
||||
ast_inet_ntoa(http_desc.oldsin.sin_addr));
|
||||
ast_build_string(&c, &reslen, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
|
||||
ntohs(http_desc.oldsin.sin_port));
|
||||
if (do_ssl)
|
||||
if (http_tls_cfg.enabled)
|
||||
ast_build_string(&c, &reslen, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
|
||||
ntohs(https_desc.oldsin.sin_port));
|
||||
ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
|
||||
@@ -482,10 +469,10 @@ static void *make_file_from_fd(void *data)
|
||||
/*
|
||||
* open a FILE * as appropriate.
|
||||
*/
|
||||
if (!ser->parent->is_ssl)
|
||||
if (!ser->parent->tls_cfg)
|
||||
ser->f = fdopen(ser->fd, "w+");
|
||||
#ifdef DO_SSL
|
||||
else if ( (ser->ssl = SSL_new(ssl_ctx)) ) {
|
||||
else if ( (ser->ssl = SSL_new(ser->parent->tls_cfg->ssl_ctx)) ) {
|
||||
SSL_set_fd(ser->ssl, ser->fd);
|
||||
if (SSL_accept(ser->ssl) == 0)
|
||||
ast_verbose(" error setting up ssl connection");
|
||||
@@ -702,32 +689,32 @@ char *ast_http_setcookie(const char *var, const char *val, int expires, char *bu
|
||||
return buf;
|
||||
}
|
||||
|
||||
int ssl_setup(void)
|
||||
int ssl_setup(struct tls_config *cfg)
|
||||
{
|
||||
#ifndef DO_SSL
|
||||
do_ssl = 0;
|
||||
cfg->enabled = 0;
|
||||
return 0;
|
||||
#else
|
||||
if (!do_ssl)
|
||||
if (!cfg->enabled)
|
||||
return 0;
|
||||
SSL_load_error_strings();
|
||||
SSLeay_add_ssl_algorithms();
|
||||
ssl_ctx = SSL_CTX_new( SSLv23_server_method() );
|
||||
if (!ast_strlen_zero(certfile)) {
|
||||
if (SSL_CTX_use_certificate_file(ssl_ctx, certfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_use_PrivateKey_file(ssl_ctx, certfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_check_private_key(ssl_ctx) == 0 ) {
|
||||
ast_verbose("ssl cert error <%s>", certfile);
|
||||
cfg->ssl_ctx = SSL_CTX_new( SSLv23_server_method() );
|
||||
if (!ast_strlen_zero(cfg->certfile)) {
|
||||
if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 ) {
|
||||
ast_verbose("ssl cert error <%s>", cfg->certfile);
|
||||
sleep(2);
|
||||
do_ssl = 0;
|
||||
cfg->enabled = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!ast_strlen_zero(cipher)) {
|
||||
if (SSL_CTX_set_cipher_list(ssl_ctx, cipher) == 0 ) {
|
||||
ast_verbose("ssl cipher error <%s>", cipher);
|
||||
if (!ast_strlen_zero(cfg->cipher)) {
|
||||
if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
|
||||
ast_verbose("ssl cipher error <%s>", cfg->cipher);
|
||||
sleep(2);
|
||||
do_ssl = 0;
|
||||
cfg->enabled = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -824,13 +811,13 @@ static int __ast_http_load(int reload)
|
||||
strcpy(newprefix, DEFAULT_PREFIX);
|
||||
cfg = ast_config_load("http.conf");
|
||||
|
||||
do_ssl = 0;
|
||||
if (certfile)
|
||||
free(certfile);
|
||||
certfile = ast_strdup(AST_CERTFILE);
|
||||
if (cipher)
|
||||
free(cipher);
|
||||
cipher = ast_strdup("");
|
||||
http_tls_cfg.enabled = 0;
|
||||
if (http_tls_cfg.certfile)
|
||||
free(http_tls_cfg.certfile);
|
||||
http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
|
||||
if (http_tls_cfg.cipher)
|
||||
free(http_tls_cfg.cipher);
|
||||
http_tls_cfg.cipher = ast_strdup("");
|
||||
|
||||
if (cfg) {
|
||||
v = ast_variable_browse(cfg, "general");
|
||||
@@ -838,15 +825,15 @@ static int __ast_http_load(int reload)
|
||||
if (!strcasecmp(v->name, "enabled"))
|
||||
enabled = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "sslenable"))
|
||||
do_ssl = ast_true(v->value);
|
||||
http_tls_cfg.enabled = ast_true(v->value);
|
||||
else if (!strcasecmp(v->name, "sslbindport"))
|
||||
https_desc.sin.sin_port = htons(atoi(v->value));
|
||||
else if (!strcasecmp(v->name, "sslcert")) {
|
||||
free(certfile);
|
||||
certfile = ast_strdup(v->value);
|
||||
free(http_tls_cfg.certfile);
|
||||
http_tls_cfg.certfile = ast_strdup(v->value);
|
||||
} else if (!strcasecmp(v->name, "sslcipher")) {
|
||||
free(cipher);
|
||||
cipher = ast_strdup(v->value);
|
||||
free(http_tls_cfg.cipher);
|
||||
http_tls_cfg.cipher = ast_strdup(v->value);
|
||||
}
|
||||
else if (!strcasecmp(v->name, "enablestatic"))
|
||||
newenablestatic = ast_true(v->value);
|
||||
@@ -886,7 +873,7 @@ static int __ast_http_load(int reload)
|
||||
ast_copy_string(prefix, newprefix, sizeof(prefix));
|
||||
enablestatic = newenablestatic;
|
||||
server_start(&http_desc);
|
||||
if (ssl_setup())
|
||||
if (ssl_setup(https_desc.tls_cfg))
|
||||
server_start(&https_desc);
|
||||
return 0;
|
||||
}
|
||||
@@ -904,7 +891,7 @@ static int handle_show_http(int fd, int argc, char *argv[])
|
||||
ast_cli(fd, "Server Enabled and Bound to %s:%d\n\n",
|
||||
ast_inet_ntoa(http_desc.oldsin.sin_addr),
|
||||
ntohs(http_desc.oldsin.sin_port));
|
||||
if (do_ssl)
|
||||
if (http_tls_cfg.enabled)
|
||||
ast_cli(fd, "HTTPS Server Enabled and Bound to %s:%d\n\n",
|
||||
ast_inet_ntoa(https_desc.oldsin.sin_addr),
|
||||
ntohs(https_desc.oldsin.sin_port));
|
||||
|
@@ -2079,12 +2079,17 @@ static int get_input(struct mansession *s, char *output)
|
||||
* Look for \r\n within the buffer. If found, copy to the output
|
||||
* buffer and return, trimming the \r\n (not used afterwards).
|
||||
*/
|
||||
for (x = 1; x < s->inlen; x++) {
|
||||
if (src[x] != '\n' || src[x-1] != '\r')
|
||||
for (x = 0; x < s->inlen; x++) {
|
||||
int cr; /* set if we have \r */
|
||||
if (src[x] == '\r' && x+1 < s->inlen && src[x+1] == '\n')
|
||||
cr = 2; /* Found. Update length to include \r\n */
|
||||
else if (src[x] == '\n')
|
||||
cr = 1; /* also accept \n only */
|
||||
else
|
||||
continue;
|
||||
x++; /* Found. Update length to include \r\n */
|
||||
memmove(output, src, x-2); /*... but trim \r\n */
|
||||
output[x-2] = '\0'; /* terminate the string */
|
||||
memmove(output, src, x); /*... but trim \r\n */
|
||||
output[x] = '\0'; /* terminate the string */
|
||||
x += cr; /* number of bytes used */
|
||||
s->inlen -= x; /* remaining size */
|
||||
memmove(src, src + x, s->inlen); /* remove used bytes */
|
||||
return 1;
|
||||
@@ -2871,10 +2876,11 @@ static void purge_old_stuff(void *data)
|
||||
purge_events();
|
||||
}
|
||||
|
||||
struct tls_config ami_tls_cfg;
|
||||
static struct server_args ami_desc = {
|
||||
.accept_fd = -1,
|
||||
.master = AST_PTHREADT_NULL,
|
||||
.is_ssl = 0,
|
||||
.tls_cfg = NULL,
|
||||
.poll_timeout = 5000, /* wake up every 5 seconds */
|
||||
.periodic_fn = purge_old_stuff,
|
||||
.name = "AMI server",
|
||||
@@ -2882,6 +2888,16 @@ static struct server_args ami_desc = {
|
||||
.worker_fn = session_do, /* thread handling the session */
|
||||
};
|
||||
|
||||
static struct server_args amis_desc = {
|
||||
.accept_fd = -1,
|
||||
.master = AST_PTHREADT_NULL,
|
||||
.tls_cfg = &ami_tls_cfg,
|
||||
.poll_timeout = -1, /* the other does the periodic cleanup */
|
||||
.name = "AMI TLS server",
|
||||
.accept_fn = server_root, /* thread doing the accept() */
|
||||
.worker_fn = session_do, /* thread handling the session */
|
||||
};
|
||||
|
||||
int init_manager(void)
|
||||
{
|
||||
struct ast_config *cfg = NULL;
|
||||
@@ -2890,6 +2906,9 @@ int init_manager(void)
|
||||
int webenabled = 0;
|
||||
int enabled = 0;
|
||||
int newhttptimeout = 60;
|
||||
int have_sslbindaddr = 0;
|
||||
struct hostent *hp;
|
||||
struct ast_hostent ahp;
|
||||
struct ast_manager_user *user = NULL;
|
||||
|
||||
if (!registered) {
|
||||
@@ -2930,6 +2949,42 @@ int init_manager(void)
|
||||
ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* default values */
|
||||
memset(&amis_desc.sin, 0, sizeof(amis_desc.sin));
|
||||
amis_desc.sin.sin_port = htons(5039);
|
||||
|
||||
ami_tls_cfg.enabled = 0;
|
||||
if (ami_tls_cfg.certfile)
|
||||
free(ami_tls_cfg.certfile);
|
||||
ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
|
||||
if (ami_tls_cfg.cipher)
|
||||
free(ami_tls_cfg.cipher);
|
||||
ami_tls_cfg.cipher = ast_strdup("");
|
||||
|
||||
/* XXX change this into a loop on ast_variable_browse(cfg, "general"); */
|
||||
|
||||
if ((val = ast_variable_retrieve(cfg, "general", "sslenable")))
|
||||
ami_tls_cfg.enabled = ast_true(val);
|
||||
if ((val = ast_variable_retrieve(cfg, "general", "sslbindport")))
|
||||
amis_desc.sin.sin_port = htons(atoi(val));
|
||||
if ((val = ast_variable_retrieve(cfg, "general", "sslbindaddr"))) {
|
||||
if ((hp = ast_gethostbyname(val, &ahp))) {
|
||||
memcpy(&amis_desc.sin.sin_addr, hp->h_addr, sizeof(amis_desc.sin.sin_addr));
|
||||
have_sslbindaddr = 1;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Invalid bind address '%s'\n", val);
|
||||
}
|
||||
}
|
||||
if ((val = ast_variable_retrieve(cfg, "general", "sslcert"))) {
|
||||
free(ami_tls_cfg.certfile);
|
||||
ami_tls_cfg.certfile = ast_strdup(val);
|
||||
}
|
||||
if ((val = ast_variable_retrieve(cfg, "general", "sslcipher"))) {
|
||||
free(ami_tls_cfg.cipher);
|
||||
ami_tls_cfg.cipher = ast_strdup(val);
|
||||
}
|
||||
|
||||
val = ast_variable_retrieve(cfg, "general", "enabled");
|
||||
if (val)
|
||||
enabled = ast_true(val);
|
||||
@@ -2972,7 +3027,12 @@ int init_manager(void)
|
||||
memset(&ami_desc.sin.sin_addr, 0, sizeof(ami_desc.sin.sin_addr));
|
||||
}
|
||||
}
|
||||
if (!have_sslbindaddr)
|
||||
amis_desc.sin.sin_addr = ami_desc.sin.sin_addr;
|
||||
if (ami_tls_cfg.enabled)
|
||||
amis_desc.sin.sin_family = AF_INET;
|
||||
|
||||
|
||||
AST_LIST_LOCK(&users);
|
||||
|
||||
while ((cat = ast_category_browse(cfg, cat))) {
|
||||
@@ -3073,6 +3133,8 @@ int init_manager(void)
|
||||
httptimeout = newhttptimeout;
|
||||
|
||||
server_start(&ami_desc);
|
||||
if (ssl_setup(amis_desc.tls_cfg))
|
||||
server_start(&amis_desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user