You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pEpEngine/src/platform_unix.c

533 lines
12 KiB
C

// This file is under GNU General Public License 3.0
// see LICENSE.txt
#define _POSIX_C_SOURCE 200809L
#ifdef ANDROID
#ifndef __LP64__
#include <time64.h>
#endif
#endif
4 years ago
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
4 years ago
#include <stdio.h>
#include <glob.h>
4 years ago
#include <errno.h>
#include <sys/stat.h>
8 years ago
#include <sys/types.h>
#include <fcntl.h>
7 years ago
#include <regex.h>
8 years ago
#include "platform_unix.h"
4 years ago
#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 <uuid.h>
/* 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) {
8 years ago
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
7 years ago
#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");
4 years ago
assert(home);
if (!home)
return NULL;
path = strdup(home);
assert(path);
if (!path)
return NULL;
char *_path = _stradd(&path, "/");
if (!_path)
goto error;
4 years ago
_path = _stradd(&path, PER_USER_DIRECTORY);
if (!_path)
goto error;
4 years ago
return path;
error:
_empty(&path);
return NULL;
}
#ifdef NDEBUG
const char *unix_local_db(void)
#else
const char *unix_local_db(int reset)
#endif
{
4 years ago
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)
4 years ago
return NULL;
path = strdup(pathret);
4 years ago
assert(path);
if (!path)
return NULL;
4 years ago
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;
}
}
4 years ago
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
4 years ago
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
}
4 years ago
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;
}