// This file is under GNU General Public License 3.0 // see LICENSE.txt #define _POSIX_C_SOURCE 200809L #ifdef ANDROID #ifndef __LP64__ #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "platform_unix.h" #include "dynamic_api.h" #define MAX_PATH 1024 #ifndef LOCAL_DB_FILENAME #define OLD_LOCAL_DB_FILENAME ".pEp_management.db" #define OLD_KEYS_DB_FILENAME ".pEp_keys.db" #define LOCAL_DB_FILENAME "management.db" #define KEYS_DB_FILENAME "keys.db" #endif #define SYSTEM_DB_FILENAME "system.db" #ifdef ANDROID #include /* FIXME : timegm will miss when linking for x86_64 on android, when supported */ #ifndef __LP64__ time_t timegm(struct tm* const t) { static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1)); static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1)); time64_t result = timegm64(t); if (result < kTimeMin || result > kTimeMax) return -1; return result; } #endif char *stpncpy(char *dst, const char *src, size_t n) { if (n != 0) { char *d = dst; const char *s = src; dst = &dst[n]; do { if ((*d++ = *s++) == 0) { dst = d - 1; /* NUL pad the remaining n-1 bytes */ while (--n != 0) *d++ = 0; break; } } while (--n != 0); } return (dst); } char *stpcpy(char *dst, const char *src) { for (;; ++dst, ++src) { *dst = *src; if (*dst == 0) break; } return dst; } /* long int random(void) { static bool seeded = false; static unsigned short xsubi[3]; if(!seeded) { const long long t = (long long)time(NULL); xsubi[0] = (unsigned short)t; xsubi[1] = (unsigned short)(t>>16); xsubi[2] = (unsigned short)(t>>32); seeded = true; } return nrand48(xsubi); } */ const char *android_system_db(void) { static char buffer[MAX_PATH]; static bool done = false; if (!done) { char *tw_env; if(tw_env = getenv("TRUSTWORDS")){ char *p = stpncpy(buffer, tw_env, MAX_PATH); ssize_t len = MAX_PATH - (p - buffer) - 2; if (len < strlen(SYSTEM_DB_FILENAME)) { assert(0); return NULL; } *p++ = '/'; strncpy(p, SYSTEM_DB_FILENAME, len); done = true; }else{ return NULL; } } return buffer; } void uuid_generate_random(pEpUUID out) { uuid_t *uuid; uuid_rc_t rc_create; size_t size = sizeof(uuid_string_t); void *_out = out; if ((rc_create = uuid_create(&uuid)) != UUID_RC_OK || uuid_make(uuid, UUID_MAKE_V1) != UUID_RC_OK || uuid_export(uuid, UUID_FMT_BIN, &_out, &size) != UUID_RC_OK) { memset(out, 0, sizeof(pEpUUID)); } if (rc_create == UUID_RC_OK) { uuid_destroy(uuid); } } void uuid_unparse_upper(pEpUUID uu, uuid_string_t out) { uuid_t *uuid; uuid_rc_t rc_create; size_t size = sizeof(uuid_string_t); void *_out = out; if ((rc_create = uuid_create(&uuid)) != UUID_RC_OK || uuid_import(uuid, UUID_FMT_BIN, uu, sizeof(pEpUUID)) != UUID_RC_OK || uuid_export(uuid, UUID_FMT_STR, &_out, &size) != UUID_RC_OK) { memset(out, 0, sizeof(uuid_string_t)); } else { out[sizeof(uuid_string_t) - 1] = 0; } if (rc_create == UUID_RC_OK) { uuid_destroy(uuid); } } #endif #if !defined(BSD) && !defined(__APPLE__) size_t strlcpy(char* dst, const char* src, size_t size) { size_t retval = strlen(src); size_t size_to_copy = (retval < size ? retval : size - 1); // strlcpy doc says src and dst not allowed to overlap, as // it's undefined. So this is acceptable: memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either dst[size_to_copy] = '\0'; return retval; } size_t strlcat(char* dst, const char* src, size_t size) { size_t start_len = strnlen(dst, size); if (start_len == size) return size; // no copy, no null termination in size bytes, according to spec size_t add_len = strlen(src); size_t retval = start_len + add_len; size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1); // strlcat doc says src and dst not allowed to overlap, as // it's undefined. So this is acceptable: memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either dst[start_len + size_to_copy] = '\0'; return retval; } char *strnstr(const char *big, const char *little, size_t len) { if (big == NULL || little == NULL) return NULL; if (*little == '\0') return (char*)big; const char* curr_big = big; size_t little_len = strlen(little); size_t remaining = len; const char* retval = NULL; for (remaining = len; remaining >= little_len && *curr_big != '\0'; remaining--, curr_big++) { // find first-char match if (*curr_big != *little) { continue; } retval = curr_big; const char* inner_big = retval + 1; const char* curr_little = little + 1; int j; for (j = 1; j < little_len; j++, inner_big++, curr_little++) { if (*inner_big != *curr_little) { retval = NULL; break; } } if (retval) break; } return (char*)retval; } // #ifdef USE_NETPGP // // FIXME: This may cause problems - this is a quick compatibility fix for netpgp code // int regnexec(const regex_t* preg, const char* string, // size_t len, size_t nmatch, regmatch_t pmatch[], int eflags) { // return regexec(preg, string, nmatch, pmatch, eflags); // } // #endif #endif static char *_stradd(char **first, const char *second) { assert(first && *first && second); if (!(first && *first && second)) return NULL; size_t len1 = strlen(*first); size_t len2 = strlen(second); size_t size = len1 + len2 + 1; char *_first = realloc(*first, size); assert(_first); if (!_first) return NULL; *first = _first; strlcat(*first, second, size); return *first; } static void _empty(char **p) { free(*p); *p = NULL; } static void _move(const char *o, const char *ext, const char *n) { assert(o && ext && n); if (!(o && ext && n)) return; char *_old = strdup(o); assert(_old); if (!_old) return; char *r = _stradd(&_old, ext); if (!r) { free(_old); return; } char *_new = strdup(n); assert(_new); if (!_new) { free(_old); return; } r = _stradd(&_new, ext); if (r) rename(_old, _new); free(_old); free(_new); } #ifndef NDEBUG static const char *_per_user_directory(int reset) #else static const char *_per_user_directory(void) #endif { static char *path = NULL; #ifdef NDEBUG if (path) return path; #else if (path && !reset) return path; else if (path) { free(path); path = NULL; } #endif const char *home = NULL; #ifndef NDEBUG home = getenv("PEP_HOME"); if (!home) #endif home = getenv("HOME"); assert(home); if (!home) return NULL; path = strdup(home); assert(path); if (!path) return NULL; char *_path = _stradd(&path, "/"); if (!_path) goto error; _path = _stradd(&path, PER_USER_DIRECTORY); if (!_path) goto error; return path; error: _empty(&path); return NULL; } #ifdef NDEBUG const char *unix_local_db(void) #else const char *unix_local_db(int reset) #endif { static char *path = NULL; #ifdef NDEBUG if (path) #else if (path && !reset) #endif return path; const char* pathret = NULL; #ifndef NDEBUG pathret = _per_user_directory(reset); #else pathret = _per_user_directory(); #endif if (!pathret) return NULL; path = strdup(pathret); assert(path); if (!path) return NULL; char *path_c = NULL; char *old_path = NULL; char *old_path_c = NULL; struct stat dir; int r = stat(path, &dir); if (r) { if (errno == ENOENT) { // directory does not yet exist r = mkdir(path, 0700); if (r) goto error; } else { goto error; } } char *_path = _stradd(&path, "/"); if (!_path) goto error; // make a copy of this path in case we need to move files path_c = strdup(path); assert(path_c); if (!path_c) goto error; _path = _stradd(&path, LOCAL_DB_FILENAME); if (!_path) goto error; struct stat file; r = stat(path, &file); if (r) { if (errno == ENOENT) { // we do not have management.db yet, let's test if we need to move // one with the old name const char *home = NULL; #ifndef NDEBUG home = getenv("PEP_HOME"); if (!home) #endif home = getenv("HOME"); // we were already checking for HOME existing, so this is only a // safeguard assert(home); old_path = strdup(home); assert(old_path); if (!old_path) goto error; char *_old_path = _stradd(&old_path, "/"); if (!_old_path) goto error; old_path_c = strdup(old_path); assert(old_path_c); if (!old_path_c) goto error; _old_path = _stradd(&old_path, OLD_LOCAL_DB_FILENAME); if (!_old_path) goto error; struct stat old; r = stat(old_path, &old); if (r == 0) { // old file existing, new file not yet existing, move rename(old_path, path); // if required move associated files, too _move(old_path, "-shm", path); _move(old_path, "-wal", path); // move keys database _old_path = _stradd(&old_path_c, OLD_KEYS_DB_FILENAME); if (!_old_path) goto error; _path = _stradd(&path_c, KEYS_DB_FILENAME); if (!_path) goto error; rename(old_path_c, path_c); // if required move associated files, too _move(old_path_c, "-shm", path_c); _move(old_path_c, "-wal", path_c); } } else { goto error; } } goto the_end; error: _empty(&path); the_end: free(path_c); free(old_path); free(old_path_c); return path; } DYNAMIC_API const char *per_user_directory(void) { #ifdef NDEBUG return _per_user_directory(); #else return _per_user_directory(false); #endif } DYNAMIC_API const char *per_machine_directory(void) { return PER_MACHINE_DIRECTORY; } const char *unix_system_db(void) { static char *path = NULL; if (path) return path; path = strdup(per_machine_directory()); assert(path); if (!path) return NULL; char *_path = _stradd(&path, "/"); if (!_path) goto error; _path = _stradd(&path, SYSTEM_DB_FILENAME); if (!_path) goto error; return path; error: _empty(&path); return NULL; }