From 166d26ff13e81b08a10604cd0d07a2fe19f51e86 Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Wed, 26 Jun 2019 16:21:21 +0300 Subject: [PATCH] Avoid using SQLITE_OPEN_URI Centos6 uses a very old version of SQLite without support for URI filenames. PAM authenticator must use a file-based database. Commit cherry-picked to 2.4.0 from 2.3. --- .../authenticator/PAM/PAMAuth/pam_auth.cc | 3 ++ .../authenticator/PAM/PAMAuth/pam_auth.hh | 3 ++ .../PAM/PAMAuth/pam_client_session.cc | 25 ++++++++--- .../authenticator/PAM/PAMAuth/pam_instance.cc | 45 +++++++++++++------ 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc b/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc index fb9e78443..f33b0422d 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_auth.cc @@ -29,6 +29,9 @@ const string FIELD_AUTHSTR = "authentication_string"; const string FIELD_PROXY = "proxy_grant"; const int NUM_FIELDS = 6; +const char* SQLITE_OPEN_FAIL = "Failed to open SQLite3 handle for file '%s': '%s'"; +const char* SQLITE_OPEN_OOM = "Failed to allocate memory for SQLite3 handle for file '%s'."; + /** * Initialize PAM authenticator * diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh b/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh index d1d9cd080..5e0a16d00 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh +++ b/server/modules/authenticator/PAM/PAMAuth/pam_auth.hh @@ -34,3 +34,6 @@ extern const string FIELD_ANYDB; extern const string FIELD_AUTHSTR; extern const string FIELD_PROXY; extern const int NUM_FIELDS; + +extern const char* SQLITE_OPEN_FAIL; +extern const char* SQLITE_OPEN_OOM; diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc index 22a0bc50f..8506f18ab 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc @@ -91,18 +91,33 @@ PamClientSession* PamClientSession::create(const PamInstance& inst) { // This handle is only used from one thread, can define no_mutex. sqlite3* dbhandle = NULL; - int db_flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX - | SQLITE_OPEN_URI; - if (sqlite3_open_v2(inst.m_dbname.c_str(), &dbhandle, db_flags, NULL) == SQLITE_OK) + bool error = false; + int db_flags = SQLITE_OPEN_READONLY | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX; + const char* filename = inst.m_dbname.c_str(); + if (sqlite3_open_v2(filename, &dbhandle, db_flags, NULL) == SQLITE_OK) { sqlite3_busy_timeout(dbhandle, 1000); } else { - MXS_ERROR("Failed to open SQLite3 handle."); + if (dbhandle) + { + MXS_ERROR(SQLITE_OPEN_FAIL, filename, sqlite3_errmsg(dbhandle)); + } + else + { + MXS_ERROR(SQLITE_OPEN_OOM, filename); + } + error = true; } + PamClientSession* rval = NULL; - if (!dbhandle || (rval = new(std::nothrow) PamClientSession(dbhandle, inst)) == NULL) + if (!error && ((rval = new (std::nothrow) PamClientSession(dbhandle, inst)) == NULL)) + { + error = true; + } + + if (error) { sqlite3_close_v2(dbhandle); } diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc index d88a7bff8..34b2e8c8f 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_instance.cc @@ -16,11 +16,10 @@ #include #include #include +#include #include #include -#define DEFAULT_PAM_DATABASE_NAME "file:pam.db?mode=memory&cache=shared" -#define DEFAULT_PAM_TABLE_NAME "pam_users" using std::string; /** @@ -31,10 +30,12 @@ using std::string; */ PamInstance* PamInstance::create(char** options) { - /** Name of the in-memory database */ - const string pam_db_name = DEFAULT_PAM_DATABASE_NAME; - /** The table name where we store the users */ - const string pam_table_name = DEFAULT_PAM_TABLE_NAME; + // Name of the in-memory database. + // TODO: Once Centos6 is no longer needed and Sqlite version 3.7+ can be assumed, + // use a memory-only db with a URI filename (e.g. file:pam.db?mode=memory&cache=shared) + const string pam_db_fname = string(get_cachedir()) + "/pam_db.sqlite3"; + // The table name where we store the users + const string pam_table_name = "pam_users"; /** Deletion statement for the in-memory table */ const string drop_sql = string("DROP TABLE IF EXISTS ") + pam_table_name + ";"; /** CREATE TABLE statement for the in-memory table */ @@ -55,15 +56,25 @@ PamInstance* PamInstance::create(char** options) bool error = false; /* This handle may be used from multiple threads, set full mutex. */ sqlite3* dbhandle = NULL; - int db_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE - | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_URI; - if (sqlite3_open_v2(pam_db_name.c_str(), &dbhandle, db_flags, NULL) != SQLITE_OK) + int db_flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_FULLMUTEX; + const char* filename = pam_db_fname.c_str(); + if (sqlite3_open_v2(filename, &dbhandle, db_flags, NULL) != SQLITE_OK) { - MXS_ERROR("Failed to open SQLite3 handle."); + // Even if the open failed, the handle may exist and an error message can be read. + if (dbhandle) + { + MXS_ERROR(SQLITE_OPEN_FAIL, filename, sqlite3_errmsg(dbhandle)); + } + else + { + // This means memory allocation failed. + MXS_ERROR(SQLITE_OPEN_OOM, filename); + } error = true; } - char* err; + char *err = NULL; if (!error && sqlite3_exec(dbhandle, drop_sql.c_str(), NULL, NULL, &err) != SQLITE_OK) { MXS_ERROR("Failed to drop table: '%s'", err); @@ -77,10 +88,16 @@ PamInstance* PamInstance::create(char** options) error = true; } - PamInstance* instance = NULL; - if (!error - && ((instance = new(std::nothrow) PamInstance(dbhandle, pam_db_name, pam_table_name)) == NULL)) + PamInstance *instance = NULL; + if (!error && + ((instance = new (std::nothrow) PamInstance(dbhandle, pam_db_fname, pam_table_name)) == NULL)) { + error = true; + } + + if (error) + { + // Close the handle even if never opened. sqlite3_close_v2(dbhandle); } return instance;