Skip to content

Commit

Permalink
db_mysql: support different TLS domains per connection
Browse files Browse the repository at this point in the history
This is done by adding the "tls_domain=dom_name" parameter to the db_url
of each module.
  • Loading branch information
rvlad-patrascu committed Jul 19, 2018
1 parent 9ad8071 commit cdfd595
Show file tree
Hide file tree
Showing 12 changed files with 313 additions and 178 deletions.
52 changes: 41 additions & 11 deletions db/db_id.c
Expand Up @@ -61,7 +61,7 @@ static int dupl_string(char** dst, const char* begin, const char* end)

/**
* Parse a database URL of form
* scheme://[username[:password]@]hostname[:port]/database
* scheme://[username[:password]@]hostname[:port]/database[?parameters]
*
* \param id filled id struct
* \param url parsed URL
Expand All @@ -80,7 +80,8 @@ static int parse_db_url(struct db_id* id, const str* url)
ST_PASS_PORT, /* Password or port part */
ST_HOST, /* Hostname part */
ST_PORT, /* Port part */
ST_DB /* Database part */
ST_DB, /* Database part */
ST_PARAMS /* Parameters part */
};

enum state st;
Expand Down Expand Up @@ -152,9 +153,9 @@ static int parse_db_url(struct db_id* id, const str* url)
break;

case '/':
st = ST_DB;
if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
begin = url->s + i + 1;
}
break;

Expand All @@ -170,8 +171,8 @@ static int parse_db_url(struct db_id* id, const str* url)
case '/':
id->host = prev_token;
id->port = str2s(begin, url->s + i - begin, 0);
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
st = ST_DB;
begin = url->s + i + 1;
}
break;

Expand All @@ -185,26 +186,42 @@ static int parse_db_url(struct db_id* id, const str* url)

case '/':
if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
st = ST_DB;
begin = url->s + i + 1;
}
break;

case ST_PORT:
switch(url->s[i]) {
case '/':
id->port = str2s(begin, url->s + i - begin, 0);
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
st = ST_DB;
begin = url->s + i + 1;
}
break;

case ST_DB:
switch(url->s[i]) {
case '?':
st = ST_PARAMS;
if (dupl_string(&id->database, begin, url->s + i) < 0) goto err;
begin = url->s + i + 1;
}
break;

case ST_PARAMS:
break;
}
}

if (st != ST_DB) goto err;
if (st != ST_DB && st != ST_PARAMS) goto err;

if (st == ST_DB) {
if (dupl_string(&id->database, begin, url->s + len) < 0) goto err;
} else {
if (dupl_string(&id->parameters, begin, url->s + len) < 0) goto err;
}

return 0;

err:
Expand Down Expand Up @@ -266,21 +283,33 @@ struct db_id* new_db_id(const str* url)
unsigned char cmp_db_id(const struct db_id* id1, const struct db_id* id2)
{
if (!id1 || !id2) return 0;

if (id1->port != id2->port) return 0;

if (strcmp(id1->scheme, id2->scheme)) return 0;

if (id1->username != 0 && id2->username != 0) {
if (strcmp(id1->username, id2->username)) return 0;
} else {
if (id1->username!=0 || id2->username!=0) return 0;
}

if (id1->password!=0 && id2->password!=0) {
if(strcmp(id1->password, id2->password)) return 0;
} else {
if (id1->password!=0 || id2->password!=0) return 0;
}

if (strcasecmp(id1->host, id2->host)) return 0;

if (strcmp(id1->database, id2->database)) return 0;

if (id1->parameters != 0 && id2->parameters != 0) {
if(strcmp(id1->parameters, id2->parameters)) return 0;
} else {
if (id1->parameters!=0 || id2->parameters!=0) return 0;
}

return 1;
}

Expand All @@ -298,5 +327,6 @@ void free_db_id(struct db_id* id)
if (id->password) pkg_free(id->password);
if (id->host) pkg_free(id->host);
if (id->database) pkg_free(id->database);
if (id->parameters) pkg_free(id->parameters);
pkg_free(id);
}
3 changes: 3 additions & 0 deletions db/db_id.h
Expand Up @@ -29,6 +29,8 @@

#include "../str.h"

#define DB_TLS_DOMAIN_PARAM "tls_domain"

/** Structure representing a database ID */
struct db_id {
char* scheme; /**< URL scheme */
Expand All @@ -37,6 +39,7 @@ struct db_id {
char* host; /**< Host or IP, case insensitive */
unsigned short port; /**< Port number */
char* database; /**< Database, case sensitive */
char *parameters; /**< Parameters, case sensitive */
str url; /**< Pointer to the original url> */
};

Expand Down
36 changes: 22 additions & 14 deletions modules/db_mysql/README
Expand Up @@ -17,7 +17,7 @@ mysql Module
1.3.2. timeout_interval (integer)
1.3.3. max_db_queries (integer)
1.3.4. max_db_retries (integer)
1.3.5. tls_client_domain (string)
1.3.5. use_tls (string)

1.4. Exported Functions
1.5. Installation
Expand Down Expand Up @@ -47,7 +47,7 @@ mysql Module
1.2. Set timeout_interval parameter
1.3. Set max_db_queries parameter
1.4. Set max_db_retries parameter
1.5. Set the tls_client_domain parameter
1.5. Set the use_tls parameter

Chapter 1. Admin Guide

Expand All @@ -61,8 +61,8 @@ Chapter 1. Admin Guide
1.2.1. OpenSIPS Modules

The following modules must be loaded before this module:
* If a tls_client_domain is defined, the tls_mgm module will
need to be loaded as well.
* If a use_tls is defined, the tls_mgm module will need to be
loaded as well.

1.2.2. External Libraries or Applications

Expand Down Expand Up @@ -129,25 +129,30 @@ modparam("db_mysql", "max_db_queries", 2)
modparam("db_mysql", "max_db_retries", 2)
...

1.3.5. tls_client_domain (string)
1.3.5. use_tls (string)

Setting this parameter with the name of TLS domain will enable
TLS for all MySQL connections established by the module. Refer
to the tls_mgm module for additional info regarding TLS client
domains.
Setting this parameter will allow you to use TLS for MySQL
connections. In order to enable TLS for a specific connection,
you can use the "tls_domain=dom_name" URL parameter in the
db_url of the respective OpenSIPS module. This should be placed
at the end of the URL after the '?' character.

If using this parameter, you must also ensure that tls_mgm is
loaded and properly configured.
When using this parameter, you must also ensure that tls_mgm is
loaded and properly configured. Refer to the the module for
additional info regarding TLS client domains.

Note that if you want to use this feature, the TLS domain must
be provisioned in the configuration file, NOT in the database.
In case you are loading TLS certificates from the database, you
must at least define one domain in the configuration script, to
use for the initial connection to the DB.

Default value is NULL (not set)
Also, you can NOT enable TLS for the connection to the database
of the tls_mgm itself.

Example 1.5. Set the tls_client_domain parameter
Default value is 0 (not enabled)

Example 1.5. Set the use_tls parameter
...
modparam("tls_mgm", "client_domain", "dom1")
modparam("tls_mgm", "certificate", "[dom1]/etc/pki/tls/certs/opensips.pe
Expand All @@ -156,7 +161,10 @@ modparam("tls_mgm", "private_key", "[dom1]/etc/pki/tls/private/opensips.
key")
modparam("tls_mgm", "ca_list", "[dom1]/etc/pki/tls/certs/ca.pem")
...
modparam("db_mysql", "tls_client_domain", "dom1")
modparam("db_mysql", "use_tls", "dom1")
...
modparam("usrloc", "db_url", "mysql://root:1234@localhost/opensips?tls_d
omain=dom1")
...

1.4. Exported Functions
Expand Down
44 changes: 23 additions & 21 deletions modules/db_mysql/db_mysql.c
Expand Up @@ -31,7 +31,6 @@
#include "../../sr_module.h"
#include "../../db/db.h"
#include "../../db/db_cap.h"

#include "../tls_mgm/api.h"

#include "dbase.h"
Expand Down Expand Up @@ -60,7 +59,7 @@ static cmd_export_t cmds[] = {

struct tls_mgm_binds tls_api;
struct tls_domain *tls_dom;
str tls_client_domain;
int use_tls;

/*
* Exported parameters
Expand All @@ -70,17 +69,34 @@ static param_export_t params[] = {
{"exec_query_threshold", INT_PARAM, &db_mysql_exec_query_threshold},
{"max_db_retries", INT_PARAM, &max_db_retries},
{"max_db_queries", INT_PARAM, &max_db_queries},
{"tls_client_domain", STR_PARAM, &tls_client_domain.s},
{"use_tls", INT_PARAM, &use_tls},
{0, 0, 0}
};

static module_dependency_t *get_deps_use_tls(param_export_t *param)
{
if (*(int *)param->param_pointer == 0)
return NULL;

return alloc_module_dep(MOD_TYPE_DEFAULT, "tls_mgm", DEP_ABORT);
}

static dep_export_t deps = {
{
{ MOD_TYPE_NULL, NULL, 0 },
},
{
{ "use_tls", get_deps_use_tls },
{ NULL, NULL },
},
};

struct module_exports exports = {
"db_mysql",
MOD_TYPE_SQLDB, /* class of this module */
MODULE_VERSION,
DEFAULT_DLFLAGS, /* dlopen flags */
NULL, /* OpenSIPS module dependencies */
&deps, /* OpenSIPS module dependencies */
cmds,
0, /* exported async functions */
params, /* module parameters */
Expand Down Expand Up @@ -115,23 +131,9 @@ static int mysql_mod_init(void)
max_db_retries = 3;
}

if (tls_client_domain.s) {
LM_INFO("using tls_mgm client domain '%s' for all MySQL connections\n",
tls_client_domain.s);

tls_client_domain.len = strlen(tls_client_domain.s);

if (load_tls_mgm_api(&tls_api) != 0) {
LM_ERR("failed to load tls_mgm API! Is the \"tls_mgm\" module loaded?\n");
return -1;
}

tls_dom = tls_api.find_client_domain_name(&tls_client_domain);
if (!tls_dom) {
LM_ERR("failed to match tls_client_domain '%s'!\n",
tls_client_domain.s);
return -1;
}
if (use_tls && load_tls_mgm_api(&tls_api) != 0) {
LM_ERR("failed to load tls_mgm API!\n");
return -1;
}

return 0;
Expand Down
3 changes: 3 additions & 0 deletions modules/db_mysql/db_mysql.h
Expand Up @@ -33,6 +33,9 @@ extern unsigned int db_mysql_timeout_interval;
extern unsigned int db_mysql_exec_query_threshold;
extern int max_db_retries;
extern int max_db_queries;
extern int use_tls;

extern struct tls_mgm_binds tls_api;

int mysql_register_event(void);

Expand Down
32 changes: 20 additions & 12 deletions modules/db_mysql/doc/db_mysql_admin.xml
Expand Up @@ -21,7 +21,7 @@
<itemizedlist>
<listitem>
<para>
<emphasis>If a <xref linkend="param_tls_client_domain"/> is defined, the <emphasis role='bold'>tls_mgm</emphasis> module will need to be loaded as well</emphasis>.
<emphasis>If a <xref linkend="param_use_tls"/> is defined, the <emphasis role='bold'>tls_mgm</emphasis> module will need to be loaded as well</emphasis>.
</para>
</listitem>
</itemizedlist>
Expand Down Expand Up @@ -131,17 +131,19 @@ modparam("db_mysql", "max_db_retries", 2)
</programlisting>
</example>
</section>
<section id="param_tls_client_domain" xreflabel="tls_client_domain">
<title><varname>tls_client_domain</varname> (string)</title>
<section id="param_use_tls" xreflabel="use_tls">
<title><varname>use_tls</varname> (integer)</title>
<para>
Setting this parameter with the name of TLS domain will enable TLS for
all MySQL connections established by the module.
Refer to the <emphasis>tls_mgm</emphasis>
module for additional info regarding TLS client domains.
Setting this parameter will allow you to use TLS for MySQL connections.
In order to enable TLS for a specific connection, you can use the
"tls_domain=<emphasis>dom_name</emphasis>" URL parameter in the db_url of
the respective OpenSIPS module. This should be placed at the end of the
URL after the '?' character.
</para>
<para>
If using this parameter, you must also ensure that
<emphasis>tls_mgm</emphasis> is loaded and properly configured.
When using this parameter, you must also ensure that
<emphasis>tls_mgm</emphasis> is loaded and properly configured. Refer to
the the module for additional info regarding TLS client domains.
</para>
<para>
Note that if you want to use this feature, the TLS domain must be
Expand All @@ -151,20 +153,26 @@ modparam("db_mysql", "max_db_retries", 2)
configuration script, to use for the initial connection to the DB.
</para>
<para>
Also, you can <emphasis>NOT</emphasis> enable TLS for the connection
to the database of the <emphasis>tls_mgm</emphasis> module itself.
</para>
<para>
<emphasis>
Default value is <emphasis role='bold'>NULL</emphasis> (not set)
Default value is <emphasis role='bold'>0</emphasis> (not enabled)
</emphasis>
</para>
<example>
<title>Set the <varname>tls_client_domain</varname> parameter</title>
<title>Set the <varname>use_tls</varname> parameter</title>
<programlisting format="linespecific">
...
modparam("tls_mgm", "client_domain", "dom1")
modparam("tls_mgm", "certificate", "[dom1]/etc/pki/tls/certs/opensips.pem")
modparam("tls_mgm", "private_key", "[dom1]/etc/pki/tls/private/opensips.key")
modparam("tls_mgm", "ca_list", "[dom1]/etc/pki/tls/certs/ca.pem")
...
modparam("db_mysql", "tls_client_domain", "dom1")
modparam("db_mysql", "use_tls", "dom1")
...
modparam("usrloc", "db_url", "mysql://root:1234@localhost/opensips?tls_domain=dom1")
...
</programlisting>
</example>
Expand Down

0 comments on commit cdfd595

Please sign in to comment.