From 63c8fbbb78a8ad3c7a3dc5dc39ab9924cb7d51aa Mon Sep 17 00:00:00 2001 From: Norm Brandinger Date: Tue, 5 Oct 2021 15:23:38 -0400 Subject: [PATCH 1/2] Added feature branch tls_postgres --- modules/db_postgres/README | 89 +++-- modules/db_postgres/db_postgres.c | 46 ++- modules/db_postgres/db_postgres.h | 4 + modules/db_postgres/dbase.c | 6 +- modules/db_postgres/dbase.h | 3 - modules/db_postgres/doc/db_postgres_admin.xml | 50 +++ modules/db_postgres/pg_con.c | 346 ++++++++++++++---- modules/db_postgres/pg_con.h | 3 + 8 files changed, 435 insertions(+), 112 deletions(-) diff --git a/modules/db_postgres/README b/modules/db_postgres/README index cefcefc0b00..99d711be150 100644 --- a/modules/db_postgres/README +++ b/modules/db_postgres/README @@ -53,15 +53,16 @@ Chapter 1. Admin Guide 1.2.1. OpenSIPS Modules The following modules must be loaded before this module: - * No dependencies on other OpenSIPS modules. + + tls_wolfssl - if use_tls=1 is specified + tls_mgm - if use_tls=1 is specified 1.2.2. External Libraries or Applications The following libraries or applications must be installed before running OpenSIPS with this module loaded: * PostgreSQL library - e.g., libpq5. - * PostgreSQL devel library - to compile the module (e.g., - libpq-dev). + * PostgreSQL devel library - to compile the module (e.g., libpq-dev). 1.3. Exported Parameters @@ -100,7 +101,7 @@ modparam("db_postgres", "max_db_queries", 2) succeed, OpenSIPS will block until the connection becomes back available and gets successfully established. This is the default behavior of the library and is the behavior prior to - the adition of this parameter. + the addition of this parameter. Default value is 5. @@ -109,6 +110,51 @@ modparam("db_postgres", "max_db_queries", 2) modparam("db_postgres", "timeout", 2) ... +1.3.4. use_tls (integer) + + Warning: wolfSSL is the required TLS/SSL Library + + This feature is not compatible with OpenSSL for the reasons defined in + https://blog.opensips.org/2021/02/11/exploring-ssl-tls-libraries-for-opensips-3-2 + + Setting this parameter will allow you to use TLS for PostgreSQL + 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. + + 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. + + Also, you can NOT enable TLS for the connection to the database + of the tls_mgm module itself. + + Default value is 0 (not enabled) + + Example 1.6. Set the use_tls parameter +... +loadmodule "tls_wolfssl" +loadmodule "tls_mgm" +loadmodule "db_postgres" +... +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_postgres", "use_tls", 1) +... +loadmodule "usrloc" +modparam("usrloc", "db_url", "postgres://root:1234@localhost/opensips?tls_domain=dom1") +... + 1.4. Exported Functions NONE @@ -135,9 +181,9 @@ Chapter 2. Contributors 9. Klaus Darilion 10 6 139 67 10. Vlad Paiu (@vladpaiu) 9 7 102 34 - All remaining contributors: Ancuta Onofrei, Norman Brandinger, - Maksym Sobolyev (@sobomax), Vlad Patrascu (@rvlad-patrascu), - Andrei Pelinescu-Onciul, Dusan Klinec (@ph4r05), Eseanu Marius + All remaining contributors: Ancuta Onofrei, Maksym Sobolyev + (@sobomax), Vlad Patrascu (@rvlad-patrascu), Andrei + Pelinescu-Onciul, Dusan Klinec (@ph4r05), Eseanu Marius Cristian (@eseanucristian), Ruslan Bukin, Ryan Bullock (@rrb3942), Konstantin Bokarius, Razvan Pistolea, Aron Podrigal, Dan Pascu (@danpascu), Peter Lemenkov (@lemenkov), @@ -163,7 +209,7 @@ Chapter 2. Contributors Table 2.2. Most recently active contributors^(1) to this module Name Commit Activity - 1. Norman Brandinger (@NormB) Aug 2006 - Aug 2021 + 1. Norm Brandinger (@NormB) Oct 2006 - Jul 2021 2. Razvan Crainea (@razvancrainea) Oct 2011 - Sep 2019 3. Dan Pascu (@danpascu) May 2019 - May 2019 4. Liviu Chircu (@liviuchircu) Sep 2012 - May 2019 @@ -173,14 +219,14 @@ Chapter 2. Contributors 8. Vlad Paiu (@vladpaiu) Jan 2011 - Feb 2019 9. Peter Lemenkov (@lemenkov) Jun 2018 - Jun 2018 10. Jarrod Baumann (@jarrodb) Mar 2016 - Mar 2016 + 11. Dusan Klinec (@ph4r05) Dec 2015 - Dec 2015 - All remaining contributors: Dusan Klinec (@ph4r05), Aron - Podrigal, Eseanu Marius Cristian (@eseanucristian), Razvan - Pistolea, Ruslan Bukin, Henning Westerholt (@henningw), - Daniel-Constantin Mierla (@miconda), Konstantin Bokarius, Edson - Gellert Schubert, Ancuta Onofrei, Klaus Darilion, Norman - Brandinger, Maksym Sobolyev (@sobomax), Jan Janak (@janakj), - Greg Fausak, Andrei Pelinescu-Onciul. + All remaining contributors: Aron Podrigal, Eseanu Marius + Cristian (@eseanucristian), Razvan Pistolea, Ruslan Bukin, + Henning Westerholt (@henningw), Daniel-Constantin Mierla + (@miconda), Konstantin Bokarius, Edson Gellert Schubert, Ancuta + Onofrei, Klaus Darilion, Maksym Sobolyev (@sobomax), Jan Janak + (@janakj), Greg Fausak, Andrei Pelinescu-Onciul. (1) including any documentation-related commits, excluding merge commits @@ -189,12 +235,13 @@ Chapter 3. Documentation 3.1. Contributors - Last edited by: Liviu Chircu (@liviuchircu), Razvan Crainea - (@razvancrainea), Peter Lemenkov (@lemenkov), Aron Podrigal, - Eseanu Marius Cristian (@eseanucristian), Bogdan-Andrei Iancu - (@bogdan-iancu), Vlad Paiu (@vladpaiu), Daniel-Constantin - Mierla (@miconda), Konstantin Bokarius, Edson Gellert Schubert, - Henning Westerholt (@henningw), Jan Janak (@janakj). + Last edited by: Norm Brandinger (@NormB) Liviu Chircu + (@liviuchircu), Razvan Crainea (@razvancrainea), Peter + Lemenkov (@lemenkov), Aron Podrigal, Eseanu Marius Cristian + (@eseanucristian), Bogdan-Andrei Iancu (@bogdan-iancu), + Vlad Paiu (@vladpaiu), Daniel-Constantin Mierla (@miconda), + Konstantin Bokarius, Edson Gellert Schubert, Henning + Westerholt (@henningw), Jan Janak (@janakj). Documentation Copyrights: diff --git a/modules/db_postgres/db_postgres.c b/modules/db_postgres/db_postgres.c index 5881d77673f..8df68811153 100644 --- a/modules/db_postgres/db_postgres.c +++ b/modules/db_postgres/db_postgres.c @@ -31,11 +31,12 @@ #include "../../db/db_con.h" #include "../../db/db.h" #include "../../db/db_cap.h" +#include "../tls_mgm/api.h" #include "dbase.h" #include "db_postgres.h" int db_postgres_exec_query_threshold = 0; /* Warning in case DB query - takes too long disabled by default*/ + takes too long disabled by default*/ int max_db_queries = 2; int pq_timeout = DEFAULT_PSQL_TIMEOUT; @@ -51,6 +52,10 @@ static cmd_export_t cmds[] = { {0,0,{{0,0,0}},0} }; +struct tls_mgm_binds tls_api; +struct tls_domain *tls_dom; +int use_tls = 0; + /* * Exported parameters */ @@ -58,15 +63,33 @@ static param_export_t params[] = { {"exec_query_threshold", INT_PARAM, &db_postgres_exec_query_threshold}, {"max_db_queries", INT_PARAM, &max_db_queries}, {"timeout", INT_PARAM, &pq_timeout}, + {"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 module_dependency_t *get_deps_use_tls_wolfssl(param_export_t *param) +{ + if (*(int *)param->param_pointer == 0) + return NULL; + + return alloc_module_dep(MOD_TYPE_DEFAULT, "tls_wolfssl", DEP_ABORT); +} + static dep_export_t deps = { { /* OpenSIPS module dependencies */ - { MOD_TYPE_DEFAULT, "tls_mgm", DEP_SILENT }, { MOD_TYPE_NULL, NULL, 0 }, }, { /* modparam dependencies */ + { "use_tls", get_deps_use_tls }, + { "use_tls", get_deps_use_tls_wolfssl }, { NULL, NULL }, }, }; @@ -98,19 +121,31 @@ struct module_exports exports = { static int mod_init(void) { LM_INFO("initializing...\n"); - + if(max_db_queries < 1){ LM_WARN("Invalid number for max_db_queries\n"); max_db_queries = 2; } - + + if (use_tls && load_tls_mgm_api(&tls_api) != 0) { + LM_ERR("failed to load tls_mgm API!\n"); + return -1; + } + + if (use_tls && module_loaded("tls_openssl")) { + LM_ERR("use_tls and tls_openssl are incompatible. Instead, use tls_wolfssl\n"); + return -1; + } + return 0; } int db_postgres_bind_api(const str* mod, db_func_t *dbb) { - if(dbb==NULL) + if(!dbb) { + LM_ERR("%.*s dbb parameter is NULL\n", mod->len, mod->s); return -1; + } memset(dbb, 0, sizeof(db_func_t)); @@ -132,4 +167,3 @@ int db_postgres_bind_api(const str* mod, db_func_t *dbb) dbb->cap |= DB_CAP_MULTIPLE_INSERT; return 0; } - diff --git a/modules/db_postgres/db_postgres.h b/modules/db_postgres/db_postgres.h index 9d2b2a56dac..11086bba6b4 100644 --- a/modules/db_postgres/db_postgres.h +++ b/modules/db_postgres/db_postgres.h @@ -29,4 +29,8 @@ #define DEFAULT_PSQL_TIMEOUT 5 extern int pq_timeout; +extern int use_tls; + +extern struct tls_mgm_binds tls_api; + #endif /* DB_POSTGRES_H */ diff --git a/modules/db_postgres/dbase.c b/modules/db_postgres/dbase.c index 7c1419985c3..5bbdfc8992e 100644 --- a/modules/db_postgres/dbase.c +++ b/modules/db_postgres/dbase.c @@ -473,7 +473,7 @@ int db_postgres_free_result(db_con_t* _con, db_res_t* _r) * _op: operators * _v: values of the keys that must match * _c: column names to return - * _n: nmber of key=values pairs to compare + * _n: number of key=values pairs to compare * _nc: number of columns to return * _o: order by the specified column */ @@ -503,7 +503,7 @@ int db_postgres_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r) * * Input: * db_con_t* _con Structure representing the database connection - * db_res_t** _r pointer to a structure represending the result set + * db_res_t** _r pointer to a structure representing the result set * * Output: * return 0: If the status of the last command produced a result set and, @@ -516,7 +516,7 @@ int db_postgres_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r) * Notes: * A new result structure is allocated on every call to this routine. * - * If this routine returns 0, it is the callers responsbility to free the + * If this routine returns 0, it is the callers' responsibility to free the * result structure. If this routine returns < 0, then the result structure * is freed before returning to the caller. * diff --git a/modules/db_postgres/dbase.h b/modules/db_postgres/dbase.h index 9242be71700..2448f2284b9 100644 --- a/modules/db_postgres/dbase.h +++ b/modules/db_postgres/dbase.h @@ -42,10 +42,8 @@ /** * Postgres default timeout */ -#define DEFAULT_POSTGRES_TIMEOUT 5 extern int pg_timeout; - /** * Initialize database connection */ @@ -61,7 +59,6 @@ void db_postgres_close(db_con_t* _h); */ int db_postgres_store_result(const db_con_t* _h, db_res_t** _r); - /** * Free all memory allocated by get_result */ diff --git a/modules/db_postgres/doc/db_postgres_admin.xml b/modules/db_postgres/doc/db_postgres_admin.xml index a5929f574cd..3c42b725ab2 100644 --- a/modules/db_postgres/doc/db_postgres_admin.xml +++ b/modules/db_postgres/doc/db_postgres_admin.xml @@ -112,6 +112,56 @@ modparam("db_postgres", "max_db_queries", 2) ... modparam("db_postgres", "timeout", 2) ... + + + + +
+ <varname>use_tls</varname> (integer) + + Warning: wolfSSL is the recommended TLS/SSL Library + + + Setting this parameter will allow you to use TLS for PostgreSQL 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. + + + 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. + + + Also, you can NOT enable TLS for the connection + to the database of the tls_mgm module itself. + + + + Default value is 0 (not enabled) + + + + Set the <varname>use_tls</varname> parameter + +... +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_postgres", "use_tls", 1) +... +modparam("usrloc", "db_url", "postgres://root:1234@localhost/opensips?tls_domain=dom1") +...
diff --git a/modules/db_postgres/pg_con.c b/modules/db_postgres/pg_con.c index f22dc755f84..d9e60ff55d4 100644 --- a/modules/db_postgres/pg_con.c +++ b/modules/db_postgres/pg_con.c @@ -19,21 +19,64 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "db_postgres.h" + +#include +#include + #include "pg_con.h" +#include "db_postgres.h" +#include "dbase.h" + +#include "../tls_mgm/api.h" #include "../../mem/mem.h" #include "../../dprint.h" #include "../../ut.h" -#include -#include -#define PSQL_PARAMS_MAX 7 +#define PSQL_PARAMS_MAX 15 +#define DB_TLS_DOMAIN_PARAM_EQ_LEN 11 +#define EXPAND_DBNAME 1 -/* - * Create a new connection structure, - * open the PostgreSQL connection and set reference count to 1 - */ -struct pg_con* db_postgres_new_connection(struct db_id* id) +/* locate tls_domain=[dom] in the parameter string */ +/* if found, a new string with tls_domain=[dom] is returned and MUST be freed */ +/* if not found, NULL is returned */ +char *get_postgres_tls_dom(struct db_id* id) +{ + char *output = NULL; + char *index = strstr(id->parameters, DB_TLS_DOMAIN_PARAM_EQ); + + if (index) { + int len; + char *end = strchr(index, '&'); + if (end) { + len = end - index; + } else { + len = strlen(index); + } + output = (char *)pkg_malloc(len+1); + memcpy(output, index, len); + output[len] = '\0'; + } + return output; +} + +/* helper routine to remove a substring from a string */ +void rmSubstr(char *str, const char *toRemove) +{ + size_t length = strlen(toRemove); + while((str = strstr(str, toRemove))) + { + memmove(str, str + length, 1 + strlen(str + length)); + } +} + +/* helper routine to remove a character at an index from a string */ +void removeChar(char *str, unsigned int index) { + char *src; + for (src = str+index; *src != '\0'; *src = *(src+1),++src) ; + *src = '\0'; +} + +int db_postgres_connect(struct pg_con* ptr) { #define PSQL_PARAM(_k, _v) \ do { \ @@ -41,65 +84,119 @@ struct pg_con* db_postgres_new_connection(struct db_id* id) values[p] = (_v); \ p++; \ } while (0); - struct pg_con* ptr; const char *keywords[PSQL_PARAMS_MAX]; const char *values[PSQL_PARAMS_MAX]; - char *ports; - char *dbname; - int p = 0, lend, lenp; + int p = 0; - LM_DBG("db_id = %p\n", id); + char *ports = NULL; + int len = 0; + char *tls_domain = NULL; + char *copy = NULL; + str tls_domain_name = {0, 0}; + struct db_id* id = NULL; - if (!id) { - LM_ERR("invalid db_id parameter value\n"); - return 0; + if (ptr) { + id = ptr->id; + } else { + LM_ERR("connection ptr parameter invalid\n"); + return -1; } - ptr = (struct pg_con*)pkg_malloc(sizeof(struct pg_con)); - if (!ptr) { - LM_ERR("failed trying to allocated %lu bytes for connection structure." - "\n", (unsigned long)sizeof(struct pg_con)); - return 0; + if (id->parameters) { + int len = strlen(id->parameters); + copy = (char *)pkg_malloc(len+1); + memcpy(copy, id->parameters, len); + copy[len] = '\0'; + + /* locate tls_domain=[dom] in the parameter string */ + /* if found, a new string with tls_domain=[dom] is returned and MUST be freed */ + /* if not found, NULL is returned */ + tls_domain = get_postgres_tls_dom(id); } - LM_DBG("%p=pkg_malloc(%zu)\n", ptr, sizeof(struct pg_con)); - memset(ptr, 0, sizeof(struct pg_con)); - ptr->ref = 1; + /* If tls_domain=[dom] is found in the parameter list, set str tls_domain_name and remove it */ + if (tls_domain) { + tls_domain_name.s = tls_domain + DB_TLS_DOMAIN_PARAM_EQ_LEN; // tls_domain= + tls_domain_name.len = (int)strlen(tls_domain + DB_TLS_DOMAIN_PARAM_EQ_LEN); // len of [dom] + + LM_DBG("TLS domain(%d): %.*s\n", tls_domain_name.len, tls_domain_name.len, tls_domain_name.s); + + // remove tls_domain=[dom] + rmSubstr(copy, tls_domain); - if (id->parameters) { - lend = strlen(id->database); - lenp = strlen(id->parameters); - dbname = pkg_malloc(7 /* "dbname=" */ + - lend + 1 /* ? */ + lenp + 1 /* '\0' */); - if (!dbname) { - LM_ERR("oom for building database name!\n"); - goto err; + // if tls_domain was the first parameter + // before rmSubstr() tls_domain=[dom]&application_name=opensips&connect_timeout=100 + // after rmSubstr() &application_name=opensips&connect_timeout=100 + if (*copy == '&') { + memmove(copy, copy+1, strlen(copy)); } - memcpy(dbname, "dbname=", 7); - memcpy(dbname + 7, id->database, lend); - lend += 7; - dbname[lend] = ' '; - lend += 1; - memcpy(dbname + lend, id->parameters, lenp); - dbname[lend + lenp] = '\0'; - /* convert '&' to spaces */ - for (; dbname[lend] != '\0'; lend++) { - if (dbname[lend] == '&' && lend > 2 && - (dbname[lend-1] != '\\' || (dbname[lend-2] != '\\'))) - dbname[lend] = ' '; + // if tls_domain was the last parameter + // before rmSubstr() application_name=opensips&connect_timeout=100&tls_domain=[dom] + // after rmSubstr() &application_name=opensips&connect_timeout=100& + len = strlen(copy); + if (copy[len-1] == '&') { + copy[len-1] = '\0'; } - } else - dbname = id->database; - if (id->port) { - ports = int2str(id->port, 0); - LM_DBG("opening connection: postgres://xxxx:xxxx@%s:%d/%s\n", ZSW(id->host), - id->port, ZSW(dbname)); - PSQL_PARAM("port", ports); - } else { - ports = NULL; - LM_DBG("opening connection: postgres://xxxx:xxxx@%s/%s\n", ZSW(id->host), - ZSW(dbname)); + // if tls_domain was a middle parameter + // before rmSubstr() application_name=opensips&tls_domain=[dom]&connect_timeout=100 + // after rmSubstr() &application_name=opensips&&connect_timeout=100 + char *index = strstr(copy, "&&"); + if (index) { + removeChar(copy, index-copy); + } + + pkg_free(tls_domain); + } + + /* If use_tls is specified and tls_domain=[dom] was found in the parameter list */ + /* configure the SSL connection parameters */ + if (use_tls && tls_domain_name.len) { + /* the connection should use TLS */ + if (!ptr->tls_dom) { + ptr->tls_dom = tls_api.find_client_domain_name(&tls_domain_name); + if (!ptr->tls_dom) { + LM_ERR("TLS domain: %.*s not found\n", tls_domain_name.len, tls_domain_name.s); + return -1; + } + } + + LM_DBG("SSL key file: %.*s\n", ptr->tls_dom->pkey.len, ptr->tls_dom->pkey.s); + LM_DBG("SSL cert file: %.*s\n", ptr->tls_dom->cert.len, ptr->tls_dom->cert.s); + LM_DBG("SSL ca file: %.*s\n", ptr->tls_dom->ca.len, ptr->tls_dom->ca.s); + LM_DBG("SSL verify_cert: %d\n", ptr->tls_dom->verify_cert); + + if (ptr->tls_dom->verify_cert == 1) { + PSQL_PARAM("sslmode", "verify-ca"); + } + + PSQL_PARAM("sslkey", ptr->tls_dom->pkey.s); + PSQL_PARAM("sslcert", ptr->tls_dom->cert.s); + PSQL_PARAM("sslrootcert", ptr->tls_dom->ca.s); + } + + /* force the default timeout */ + /* If connect_timeout is specified in the parameter list, it will override this value */ + if (pq_timeout > 0) { + PSQL_PARAM("connect_timeout", int2str(pq_timeout, 0)); + } + + if (copy) { + /* Change parameters to connection string: convert '&' to space */ + for (int i=0; copy[i] != '\0'; i++) { + if (copy[i] == '&' ) { + copy[i] = ' '; + } + } + + /* PQconnectdbParams(keywords, values, EXPAND_DBNAME) */ + /* When expand_dbname is non-zero, the value for the first dbname key word is checked to see if it is a connection string. */ + /* If so, it is expanded into the individual connection parameters extracted from the string. */ + /* The value is considered to be a connection string, rather than just a database name, */ + /* if it contains an equal sign (=) or it begins with a URI scheme designator. */ + /* Only the first occurrence of dbname is treated in this way; any subsequent dbname parameter is processed as a plain database name. */ + LM_DBG("connection string (%ld): %s\n", strlen(copy), copy); + PSQL_PARAM("dbname", copy); } if (id->host) @@ -108,38 +205,109 @@ struct pg_con* db_postgres_new_connection(struct db_id* id) PSQL_PARAM("user", id->username); if (id->password) PSQL_PARAM("password", id->password); + if (id->database) { + PSQL_PARAM("dbname", id->database); + } - PSQL_PARAM("dbname", dbname); + if (id->port) { + ports = int2str(id->port, 0); + LM_DBG("opening connection: postgres://xxxx:xxxx@%s:%d/%s %s\n", ZSW(id->host), id->port, ZSW(id->database), ZSW(copy)); + PSQL_PARAM("port", ports); + } else { + ports = NULL; + LM_DBG("opening connection: postgres://xxxx:xxxx@%s/%s %s\n", ZSW(id->host), ZSW(id->database), ZSW(copy)); + } - /* force the default timeout */ - if (pq_timeout > 0) - PSQL_PARAM("connect_timeout", int2str(pq_timeout, 0)); + /* End of the parameter list */ PSQL_PARAM(0, 0); - ptr->con = PQconnectdbParams(keywords, values, 1); - if (dbname != id->database) - pkg_free(dbname); + /* Print the parameter list created by PGSQL_PARAM */ + for (int i=0; icon = PQconnectdbParams(keywords, values, EXPAND_DBNAME); + + /* After the connection is attempted, there is no need to keep the copy of the parameter list */ + if (copy) { + pkg_free(copy); + } - if( (ptr->con == 0) || (PQstatus(ptr->con) != CONNECTION_OK) ) + /* If an error happened while trying to connect, cleanup */ + if(!ptr->con || (PQstatus(ptr->con) != CONNECTION_OK) ) { - LM_ERR("%s\n", PQerrorMessage(ptr->con)); + LM_ERR("PQconnectdbParams: %s\n", PQerrorMessage(ptr->con)); PQfinish(ptr->con); - goto err; + return -1; } ptr->connected = 1; ptr->timestamp = time(0); + + return 0; +} + +/* + * Create a new connection structure, + * open the PostgreSQL connection and set reference count to 1 + */ +struct pg_con* db_postgres_new_connection(struct db_id* id) +{ + struct pg_con* ptr = NULL; + + if (!id) { + LM_ERR("invalid db_id parameter value\n"); + return 0; + } else { + LM_DBG("db_id = %p\n", id); + } + + ptr = (struct pg_con*)pkg_malloc(sizeof(struct pg_con)); + if (!ptr) { + LM_ERR("failed trying to allocated %lu bytes for connection structure." + "\n", (unsigned long)sizeof(struct pg_con)); + return 0; + } + + LM_DBG("db_id: %p %p=pkg_malloc(%zu)\n", id, ptr, sizeof(struct pg_con)); + memset(ptr, 0, sizeof(struct pg_con)); + + ptr->ref = 1; ptr->id = id; - return ptr; + LM_DBG("calling db_postgres_connect ptr = %p, db_id = %p\n", ptr, ptr->id); - err: - if (ptr) { - LM_ERR("cleaning up %p=pkg_free()\n", ptr); - pkg_free(ptr); + if (db_postgres_connect(ptr)!=0) { + LM_ERR("initial connect failed, cleaning up %p=pkg_free()\n", ptr); + if (ptr) { + pkg_free(ptr); + } + return 0; } - return 0; -#undef PSQL_PARAM + + /* Print connection information */ + PQconninfoOption *conninfo = NULL; + conninfo = PQconninfo(ptr->con); + if (!conninfo) { + LM_DBG("unable to get connection options for ptr = %p con = %p\n", ptr, ptr->con); + } else { + for (int i=0; conninfo[i].keyword != NULL; i++) { + if (!strncmp(conninfo[i].keyword, "password", 8) || !strncmp(conninfo[i].keyword, "user", 4)) { + continue; + } + LM_DBG("con(%p) %s=%s\n", ptr->con, conninfo[i].keyword, conninfo[i].val); + } + PQconninfoFree(conninfo); + } + + return ptr; } /* @@ -148,12 +316,22 @@ struct pg_con* db_postgres_new_connection(struct db_id* id) */ struct pg_con* db_postgres_new_async_connection(struct db_id* id) { - struct pg_con * ret = db_postgres_new_connection(id); - if (ret) { - PQsetnonblocking(ret->con, 1); + struct pg_con *ptr; + + if (!id) { + LM_ERR("invalid db_id parameter value\n"); + return 0; + } else { + LM_DBG("db_id = %p\n", id); + } + + ptr = db_postgres_new_connection(id); + + if (ptr) { + PQsetnonblocking(ptr->con, 1); } - return ret; + return ptr; } /* @@ -162,11 +340,21 @@ struct pg_con* db_postgres_new_async_connection(struct db_id* id) void db_postgres_free_connection(struct pool_con* con) { - if (!con) return; + if (!con) { + LM_ERR("invalid connection parameter value\n"); + return; + } else { + LM_DBG("connection = %p\n", con); + } struct pg_con * _c; _c = (struct pg_con*)con; + if (_c->tls_dom) { + tls_api.release_domain(_c->tls_dom); + _c->tls_dom = NULL; + } + if (_c->res) { LM_DBG("PQclear(%p)\n", _c->res); PQclear(_c->res); @@ -178,6 +366,6 @@ void db_postgres_free_connection(struct pool_con* con) PQfinish(_c->con); _c->con = 0; } - LM_DBG("pkg_free(%p)\n", _c); + LM_DBG("cleaning up connection pkg_free(%p)\n", _c); pkg_free(_c); } diff --git a/modules/db_postgres/pg_con.h b/modules/db_postgres/pg_con.h index 3215b40a9ea..e081edd876b 100644 --- a/modules/db_postgres/pg_con.h +++ b/modules/db_postgres/pg_con.h @@ -34,6 +34,7 @@ #include "../../db/db_pool.h" #include "../../db/db_id.h" +#include "../tls_mgm/tls_helper.h" #include #include @@ -56,6 +57,8 @@ struct pg_con { char** row; /* Actual row in the result */ time_t timestamp; /* Timestamp of last query */ + struct tls_domain *tls_dom;; /* TLS domain */ + }; #define CON_SQLURL(db_con) (((struct pg_con*)((db_con)->tail))->sqlurl) From 146b23e7ea24597135d94ad8e14572730f598f69 Mon Sep 17 00:00:00 2001 From: Vlad Patrascu Date: Sun, 10 Oct 2021 21:51:05 +0300 Subject: [PATCH 2/2] db_postgres: remove the tls_wolfssl module dependency --- modules/db_postgres/db_postgres.c | 9 --------- modules/db_postgres/doc/db_postgres_admin.xml | 4 +++- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/modules/db_postgres/db_postgres.c b/modules/db_postgres/db_postgres.c index 8df68811153..c9e36e4cb57 100644 --- a/modules/db_postgres/db_postgres.c +++ b/modules/db_postgres/db_postgres.c @@ -75,21 +75,12 @@ static module_dependency_t *get_deps_use_tls(param_export_t *param) return alloc_module_dep(MOD_TYPE_DEFAULT, "tls_mgm", DEP_ABORT); } -static module_dependency_t *get_deps_use_tls_wolfssl(param_export_t *param) -{ - if (*(int *)param->param_pointer == 0) - return NULL; - - return alloc_module_dep(MOD_TYPE_DEFAULT, "tls_wolfssl", DEP_ABORT); -} - static dep_export_t deps = { { /* OpenSIPS module dependencies */ { MOD_TYPE_NULL, NULL, 0 }, }, { /* modparam dependencies */ { "use_tls", get_deps_use_tls }, - { "use_tls", get_deps_use_tls_wolfssl }, { NULL, NULL }, }, }; diff --git a/modules/db_postgres/doc/db_postgres_admin.xml b/modules/db_postgres/doc/db_postgres_admin.xml index 3c42b725ab2..db0113c96b7 100644 --- a/modules/db_postgres/doc/db_postgres_admin.xml +++ b/modules/db_postgres/doc/db_postgres_admin.xml @@ -119,7 +119,9 @@ modparam("db_postgres", "timeout", 2)
<varname>use_tls</varname> (integer) - Warning: wolfSSL is the recommended TLS/SSL Library + Warning: the tls_openssl module cannot be used + when setting this parameter. Use the tls_wolfssl + module instead if a TLS/SSL Library is required. Setting this parameter will allow you to use TLS for PostgreSQL connections.