WIP: ENGINE-524: make paths to sys, mgmt and keys DB configurable via env ENGINE-524
authorClaudio Luck <claudio.luck@pep.foundation>
Mon, 06 May 2019 17:52:20 +0200
branchENGINE-524
changeset 36384ba9bd8b80c1
parent 3637 b759366d2500
child 3672 80b56b8c68dd
WIP: ENGINE-524: make paths to sys, mgmt and keys DB configurable via env

Rationale: full compatibility on systems which already have a system and management DB,
while moving things under $HOME/.pEp (or $XDG_CONFIG_DIR/pEp) on new sytems.

TODO:

- Write and run tests
- Do we need to create sub-directories (e.g. ~/.pEp)?
- Bring the new defines into the Makefiles
- Implementation for Windows: windoze_local_db()

Changes:

- The hardcoded location for system DB is now in /usr/local/share/pEp instead of
/usr/share/pEp, the Makefile should default to /usr/share/pEp.


User documentation:

Set the following environment variables to select the location of the various databases:

TRUSTWORDS sets path to:
- $TRUSTWORDS/system.db

PEPHOME sets path to:
- $PEPHOME/pEp_management.db (*)
- $PEPHOME/pEp_keys.db (**)
- $PEPHOME/system.db (***)

(*) Note that there is no dot in the filename (pEp_management.db) when PEPHOME
is set. The default is still $HOME/.pEp_management.db (with dot) when PEPHOME
is unset.

(**) When you set PEPHOME, both pEp_keys.db and pEp_management.db must be
co-located. If the databases don't exist, new ones will be initialized. The
PEPHOME directory must exist before starting the adapters.

(***) system.db will be found in PEPHOME only if TRUSTWORDS is not set. If
TRUSTWORDS is set, the system DB MUST be where TRUSTWORDS points to. Otherwise,
if TRUSTWORDS is unset and PEPHOME contains no system DB, search will continue
at the default location. In other words, while keys and management DB must be
in PEPHOME when set, the system DB may be in the default location too.

The default locations are:
- $HOME/.pEp/pEp_management.db (if file exists)
- $HOME/.pEp_management.db (otherwise)
- /usr/local/share/pEp/system.db
- $HOME/.pEp_keys.db
src/pEpEngine.c
src/pEp_internal.h
src/pgp_sequoia.c
src/platform_unix.c
src/platform_unix.h
     1.1 --- a/src/pEpEngine.c	Mon May 06 15:44:27 2019 +0200
     1.2 +++ b/src/pEpEngine.c	Mon May 06 17:52:20 2019 +0200
     1.3 @@ -863,6 +863,12 @@
     1.4          goto pEp_error;
     1.5      }
     1.6  
     1.7 +    assert(LOCAL_KEYS_DB);
     1.8 +    if (LOCAL_KEYS_DB == NULL) {
     1.9 +        status = PEP_INIT_CANNOT_OPEN_DB;
    1.10 +        goto pEp_error;
    1.11 +    }
    1.12 +
    1.13      int_result = sqlite3_exec(
    1.14              _session->db,
    1.15              "PRAGMA locking_mode=NORMAL;\n"
     2.1 --- a/src/pEp_internal.h	Mon May 06 15:44:27 2019 +0200
     2.2 +++ b/src/pEp_internal.h	Mon May 06 17:52:20 2019 +0200
     2.3 @@ -56,6 +56,7 @@
     2.4  
     2.5  #ifdef WIN32
     2.6  #define LOCAL_DB windoze_local_db()
     2.7 +#define LOCAL_KEYS_DB windoze_local_db()
     2.8  #define SYSTEM_DB windoze_system_db()
     2.9  #define LIBGPGME "libgpgme-11.dll"
    2.10  #else // UNIX
    2.11 @@ -63,11 +64,17 @@
    2.12  #include <dlfcn.h>
    2.13  #ifdef NDEBUG
    2.14  #define LOCAL_DB unix_local_db()
    2.15 +#define LOCAL_KEYS_DB unix_local_keys_db()
    2.16  #else
    2.17  #define LOCAL_DB unix_local_db(false)
    2.18 +#define LOCAL_KEYS_DB unix_local_keys_db(false)
    2.19  #endif
    2.20  #ifndef SYSTEM_DB
    2.21 -#define SYSTEM_DB "/usr/share/pEp/system.db"
    2.22 +#ifdef NDEBUG
    2.23 +#define SYSTEM_DB unix_system_db()
    2.24 +#else
    2.25 +#define SYSTEM_DB unix_system_db(false)
    2.26 +#endif
    2.27  #endif
    2.28  #ifndef LIBGPGME
    2.29  #define LIBGPGME "libgpgme-pthread.so"
     3.1 --- a/src/pgp_sequoia.c	Mon May 06 15:44:27 2019 +0200
     3.2 +++ b/src/pgp_sequoia.c	Mon May 06 17:52:20 2019 +0200
     3.3 @@ -5,7 +5,8 @@
     3.4  
     3.5  #define _GNU_SOURCE 1
     3.6  
     3.7 -#include "platform.h"
     3.8 +#define MAX_PATH 1024
     3.9 +
    3.10  #include "pEp_internal.h"
    3.11  #include "pgp_gpg.h"
    3.12  
    3.13 @@ -72,22 +73,11 @@
    3.14  {
    3.15      PEP_STATUS status = PEP_STATUS_OK;
    3.16  
    3.17 -    // Create the home directory.
    3.18 -    char *home_env = getenv("HOME");
    3.19 -    if (!home_env)
    3.20 -        ERROR_OUT(NULL, PEP_INIT_GPGME_INIT_FAILED, "HOME unset");
    3.21 -
    3.22 -    // Create the DB and initialize it.
    3.23 -    size_t path_size = strlen(home_env)+13+1;
    3.24 -    char *path = (char *) calloc(1, path_size);
    3.25 -    assert(path);
    3.26 +    char path[MAX_PATH];
    3.27 +    unix_local_db_file(path, "pEp_keys.db");
    3.28      if (!path)
    3.29 -        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
    3.30 -
    3.31 -    int r = snprintf(path, path_size, "%s/.pEp_keys.db", home_env);
    3.32 -    assert(r >= 0 && r < path_size);
    3.33 -    if (r < 0)
    3.34 -        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "snprintf");
    3.35 +        ERROR_OUT(NULL, PEP_INIT_GPGME_INIT_FAILED,
    3.36 +                  "could not determine path to keys DB");
    3.37  
    3.38      int sqlite_result;
    3.39      sqlite_result = sqlite3_open_v2(path,
    3.40 @@ -97,7 +87,7 @@
    3.41                                      | SQLITE_OPEN_FULLMUTEX
    3.42                                      | SQLITE_OPEN_PRIVATECACHE,
    3.43                                      NULL);
    3.44 -    free(path);
    3.45 +
    3.46      if (sqlite_result != SQLITE_OK)
    3.47          ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
    3.48                    "opening keys DB: %s", sqlite3_errmsg(session->key_db));
     4.1 --- a/src/platform_unix.c	Mon May 06 15:44:27 2019 +0200
     4.2 +++ b/src/platform_unix.c	Mon May 06 17:52:20 2019 +0200
     4.3 @@ -17,14 +17,21 @@
     4.4  #include <sys/types.h>
     4.5  #include <fcntl.h>
     4.6  #include <regex.h>
     4.7 +// #include <stdio.h>
     4.8  
     4.9  #include "platform_unix.h"
    4.10  
    4.11  #define MAX_PATH 1024
    4.12  #ifndef LOCAL_DB_FILENAME
    4.13 -#define LOCAL_DB_FILENAME ".pEp_management.db"
    4.14 +#define LOCAL_DB_FILENAME "pEp_management.db"  /* dot (hidden file) now added in *_local_db() */
    4.15 +#endif
    4.16 +#ifndef LOCAL_KEYS_DB_FILENAME
    4.17 +#define LOCAL_KEYS_DB_FILENAME "pEp_keys.db"
    4.18  #endif
    4.19  #define SYSTEM_DB_FILENAME "system.db"
    4.20 +#ifndef SYSTEM_DB_PREFIX
    4.21 +#define SYSTEM_DB_PREFIX "/usr/local/share/pEp"
    4.22 +#endif
    4.23  
    4.24  #ifndef bool
    4.25  #define bool int
    4.26 @@ -169,6 +176,58 @@
    4.27  
    4.28  #endif
    4.29  
    4.30 +#ifdef NDEBUG
    4.31 +const char *unix_system_db(void)
    4.32 +#else
    4.33 +const char *unix_system_db(int reset)
    4.34 +#endif
    4.35 +{
    4.36 +    static char buffer[MAX_PATH];
    4.37 +    static bool done = false;
    4.38 +
    4.39 +    #ifdef NDEBUG
    4.40 +    if (!done)
    4.41 +    #else
    4.42 +    if ((!done) || reset)
    4.43 +    #endif
    4.44 +    {
    4.45 +        const char *home_env;
    4.46 +        const char *subdir;
    4.47 +        /* TODO: ugly data layout, maybe switch to nested struct */
    4.48 +        const char * const confvars[] = { "TRUSTWORDS", "PEPHOME", "XDG_CONFIG_DIR", NULL,             "HOME",  NULL };
    4.49 +        const char * const confvals[] = { NULL,         NULL,      NULL,             SYSTEM_DB_PREFIX, NULL,    NULL };
    4.50 +        const char * const confsdir[] = { "",           "",        "/pEp",           "",               "/.pEp", NULL };
    4.51 +        const bool confisimportant[] =  { true,         false,     false,            false,            false,   false };
    4.52 +        int cf_i;
    4.53 +        for (cf_i = 0; confvars[cf_i] || confvals[cf_i]; cf_i++) {
    4.54 +            if (((home_env = confvals[cf_i]) || (home_env = getenv (confvars[cf_i]))) && (subdir = confsdir[cf_i])) {
    4.55 +                // printf("unix_system_db (%s) [%s] %s\n", SYSTEM_DB_FILENAME, confvars[cf_i], home_env);
    4.56 +                char *p = stpncpy (buffer, home_env, MAX_PATH);
    4.57 +                ssize_t len = MAX_PATH - (p - buffer) - 2;
    4.58 +
    4.59 +                if (len < strlen (SYSTEM_DB_FILENAME) + strlen (confsdir[cf_i])) {
    4.60 +                    assert(0);
    4.61 +                    return NULL;
    4.62 +                }
    4.63 +
    4.64 +                p = stpncpy(p, confsdir[cf_i], len);
    4.65 +                *p++ = '/';
    4.66 +                strncpy(p, SYSTEM_DB_FILENAME, len);
    4.67 +                // printf("unix_system_db (%s) [%s] -> %s\n", SYSTEM_DB_FILENAME, confvars[cf_i], buffer);
    4.68 +                if (access (buffer, R_OK) == 0) {
    4.69 +                    done = true;
    4.70 +                    return buffer;
    4.71 +                }
    4.72 +                else if (confisimportant[cf_i])
    4.73 +                    return NULL;
    4.74 +            }
    4.75 +            // printf("unix_system_db (%s) %s failed\n", SYSTEM_DB_FILENAME, confvars[cf_i]);
    4.76 +        }
    4.77 +        return NULL;
    4.78 +    }
    4.79 +    return buffer;
    4.80 +}
    4.81 +
    4.82  #if !defined(BSD) && !defined(__APPLE__)
    4.83  
    4.84  size_t strlcpy(char* dst, const	char* src, size_t size) {
    4.85 @@ -209,6 +268,45 @@
    4.86  #endif
    4.87  
    4.88  #ifdef NDEBUG
    4.89 +int unix_local_db_file(char *buffer, const char *fname)
    4.90 +#else
    4.91 +int unix_local_db_file(char *buffer, const char *fname, int reset)
    4.92 +#endif
    4.93 +{
    4.94 +    const char *home_env;
    4.95 +    const char *subdir;
    4.96 +    /* TODO: ugly data layout, maybe switch to nested struct */
    4.97 +    /* Note: in HOME, a dot is prepended to the file (~/.pEp_management.db, vs ~/.pEp/pEp_management.db) */
    4.98 +    const char * const confvars[] = { "PEPHOME", "XDG_CONFIG_DIR", "HOME",  "HOME",   NULL };
    4.99 +    const char * const confvals[] = { NULL,      NULL,             NULL,    NULL,     NULL };
   4.100 +    const char * const confsdir[] = { "/",       "/pEp/",          "/.",    "/.pEp/", NULL };
   4.101 +    const bool confisimportant[] =  { true,      false,            false,   true,     false };
   4.102 +    int cf_i;
   4.103 +
   4.104 +    for (cf_i = 0; confvars[cf_i] || confvals[cf_i]; cf_i++) {
   4.105 +        if (((home_env = confvals[cf_i]) || (home_env = getenv (confvars[cf_i]))) && (subdir = confsdir[cf_i])) {
   4.106 +            // printf("unix_local_db_file(%s) [%s] %s\n", fname, confvars[cf_i], home_env);
   4.107 +            char *p = stpncpy (buffer, home_env, MAX_PATH);
   4.108 +            ssize_t len = MAX_PATH - (p - buffer) - 1;
   4.109 +
   4.110 +            if (len < strlen (fname) + strlen (confsdir[cf_i])) {
   4.111 +                assert(0);
   4.112 +                return false;
   4.113 +            }
   4.114 +
   4.115 +            p = stpncpy(p, confsdir[cf_i], len);
   4.116 +            strncpy(p, fname, len);
   4.117 +            // printf("unix_local_db_file(%s) [%s] -> %s\n", fname, confvars[cf_i], buffer);
   4.118 +            if (confisimportant[cf_i] || (access (buffer, R_OK) == 0)) {
   4.119 +                return true;
   4.120 +            }
   4.121 +        }
   4.122 +        // printf("unix_local_db_file(%s) %s failed\n", fname, confvars[cf_i]);
   4.123 +    }
   4.124 +    return false;
   4.125 +}
   4.126 +
   4.127 +#ifdef NDEBUG
   4.128  const char *unix_local_db(void)
   4.129  #else
   4.130  const char *unix_local_db(int reset)
   4.131 @@ -219,31 +317,41 @@
   4.132  
   4.133      #ifdef NDEBUG
   4.134      if (!done)
   4.135 +        done = unix_local_db_file(buffer, LOCAL_DB_FILENAME);
   4.136      #else
   4.137      if ((!done) || reset)
   4.138 +        done = unix_local_db_file(buffer, LOCAL_DB_FILENAME, reset);
   4.139      #endif
   4.140 -    {
   4.141 -        char *home_env;
   4.142 -        if((home_env = getenv("HOME"))){
   4.143 -            char *p = stpncpy(buffer, home_env, MAX_PATH);
   4.144 -            ssize_t len = MAX_PATH - (p - buffer) - 2;
   4.145  
   4.146 -            if (len < strlen(LOCAL_DB_FILENAME)) {
   4.147 -                assert(0);
   4.148 -                return NULL;
   4.149 -            }
   4.150 +    if (done)
   4.151 +        return buffer;
   4.152 +    return NULL;
   4.153 +}
   4.154  
   4.155 -            *p++ = '/';
   4.156 -            strncpy(p, LOCAL_DB_FILENAME, len);
   4.157 -            done = true;
   4.158 -        }else{
   4.159 -            return NULL;
   4.160 -        }
   4.161 +#ifdef NDEBUG
   4.162 +const char *unix_local_keys_db(void)
   4.163 +#else
   4.164 +const char *unix_local_keys_db(int reset)
   4.165 +#endif
   4.166 +{
   4.167 +    static char buffer[MAX_PATH];
   4.168 +    static bool done = false;
   4.169  
   4.170 +    #ifdef NDEBUG
   4.171 +    if (!done)
   4.172 +        done = unix_local_db_file(buffer, LOCAL_KEYS_DB_FILENAME);
   4.173 +    #else
   4.174 +    if ((!done) || reset)
   4.175 +        done = unix_local_db_file(buffer, LOCAL_KEYS_DB_FILENAME, reset);
   4.176 +    #endif
   4.177 +
   4.178 +    if (done) {
   4.179 +        return buffer;
   4.180      }
   4.181 -    return buffer;
   4.182 +    return NULL;
   4.183  }
   4.184  
   4.185 +
   4.186  static const char *gpg_conf_path = ".gnupg";
   4.187  static const char *gpg_conf_name = "gpg.conf";
   4.188  static const char *gpg_agent_conf_name = "gpg-agent.conf";
     5.1 --- a/src/platform_unix.h	Mon May 06 15:44:27 2019 +0200
     5.2 +++ b/src/platform_unix.h	Mon May 06 17:52:20 2019 +0200
     5.3 @@ -22,12 +22,16 @@
     5.4  #endif
     5.5  
     5.6  #ifdef NDEBUG
     5.7 +int unix_local_db_file(const char *buffer, const char *fname);
     5.8  const char *unix_local_db(void);
     5.9 +const char *unix_system_db(void);
    5.10  const char *gpg_conf(void);
    5.11  const char *gpg_agent_conf(void);
    5.12  const char *gpg_home(void);
    5.13  #else
    5.14 +int unix_local_db_file(const char *buffer, const char *fname, int reset);
    5.15  const char *unix_local_db(int reset);
    5.16 +const char *unix_system_db(int reset);
    5.17  const char *gpg_conf(int reset);
    5.18  const char *gpg_agent_conf(int reset);
    5.19  const char *gpg_home(int reset);