src/platform_unix.c
author Krista 'DarthMama' Bennett <krista@pep.foundation>
Thu, 04 Jun 2020 11:18:45 +0200
changeset 4729 3df9a2a67597
parent 4471 2738f89bde23
child 4792 7056435ab9e7
permissions -rw-r--r--
forgot test files
vb@1517
     1
// This file is under GNU General Public License 3.0
vb@1517
     2
// see LICENSE.txt
vb@1517
     3
vb@1
     4
#define _POSIX_C_SOURCE 200809L
vb@1
     5
Edouard@1267
     6
#ifdef ANDROID
Edouard@1267
     7
#ifndef __LP64__ 
Edouard@1267
     8
#include <time64.h>
Edouard@1267
     9
#endif
Edouard@1267
    10
#endif
Edouard@1267
    11
vb@4003
    12
#include <stdbool.h>
Edouard@1136
    13
#include <time.h>
vb@1
    14
#include <string.h>
vb@1
    15
#include <stdlib.h>
vb@1
    16
#include <assert.h>
vb@3997
    17
#include <stdio.h>
vb@3997
    18
#include <glob.h>
krista@4023
    19
#include <errno.h>
Edouard@158
    20
#include <sys/stat.h>
vb@149
    21
#include <sys/types.h>
Edouard@158
    22
#include <fcntl.h>
krista@1033
    23
#include <regex.h>
Edouard@158
    24
vb@1
    25
#include "platform_unix.h"
vb@4003
    26
#include "dynamic_api.h"
vb@1
    27
vb@1
    28
#define MAX_PATH 1024
vb@1089
    29
#ifndef LOCAL_DB_FILENAME
vb@3997
    30
#define OLD_LOCAL_DB_FILENAME ".pEp_management.db"
vb@3997
    31
#define OLD_KEYS_DB_FILENAME ".pEp_keys.db"
vb@3997
    32
#define LOCAL_DB_FILENAME "management.db"
vb@3997
    33
#define KEYS_DB_FILENAME "keys.db"
vb@1089
    34
#endif
Edouard@347
    35
#define SYSTEM_DB_FILENAME "system.db"
vb@1
    36
Edouard@347
    37
#ifdef ANDROID
Edouard@1119
    38
#include <uuid.h>
Edouard@1267
    39
Edouard@1267
    40
/* FIXME : timegm will miss when linking for x86_64 on android, when supported */
Edouard@1267
    41
#ifndef __LP64__ 
Edouard@1267
    42
time_t timegm(struct tm* const t) {
Edouard@1267
    43
    static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1));
Edouard@1267
    44
    static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1));
Edouard@1267
    45
    time64_t result = timegm64(t);
Edouard@1267
    46
    if (result < kTimeMin || result > kTimeMax)
Edouard@1267
    47
        return -1;
Edouard@1267
    48
    return result;
Edouard@1267
    49
}
Edouard@1267
    50
#endif
Edouard@1267
    51
Edouard@347
    52
char *stpncpy(char *dst, const char *src, size_t n)
Edouard@333
    53
{
Edouard@333
    54
    if (n != 0) {
Edouard@333
    55
        char *d = dst;
Edouard@333
    56
        const char *s = src;
Edouard@333
    57
Edouard@333
    58
        dst = &dst[n];
Edouard@333
    59
        do {
Edouard@333
    60
            if ((*d++ = *s++) == 0) {
Edouard@333
    61
                dst = d - 1;
Edouard@333
    62
                /* NUL pad the remaining n-1 bytes */
Edouard@333
    63
                while (--n != 0)
Edouard@333
    64
                    *d++ = 0;
Edouard@333
    65
                break;
Edouard@333
    66
            }
Edouard@333
    67
        } while (--n != 0);
Edouard@333
    68
    }
Edouard@333
    69
    return (dst);
Edouard@333
    70
}
Edouard@333
    71
Edouard@338
    72
char *stpcpy(char *dst, const char *src)
Edouard@338
    73
{
Edouard@338
    74
    for (;; ++dst, ++src) {
Edouard@338
    75
        *dst = *src;
Edouard@338
    76
        if (*dst == 0)
Edouard@338
    77
            break;
Edouard@338
    78
    }
Edouard@338
    79
    return dst;
Edouard@338
    80
}
Edouard@338
    81
huss@1528
    82
/*
roker@438
    83
long int random(void)
roker@438
    84
{
Edouard@841
    85
    static bool seeded = false;
Edouard@838
    86
    static unsigned short xsubi[3];
Edouard@841
    87
    if(!seeded)
Edouard@841
    88
    {
roker@847
    89
        const long long t = (long long)time(NULL);
roker@847
    90
        xsubi[0] = (unsigned short)t;
roker@847
    91
        xsubi[1] = (unsigned short)(t>>16);
roker@847
    92
        xsubi[2] = (unsigned short)(t>>32);
Edouard@841
    93
        seeded = true;
Edouard@841
    94
    }
Edouard@838
    95
vb@436
    96
    return nrand48(xsubi);
huss@1528
    97
} */
Edouard@347
    98
Edouard@347
    99
const char *android_system_db(void)
Edouard@347
   100
{
Edouard@347
   101
    static char buffer[MAX_PATH];
Edouard@347
   102
    static bool done = false;
Edouard@347
   103
Edouard@347
   104
    if (!done) {
Edouard@349
   105
        char *tw_env;
Edouard@349
   106
        if(tw_env = getenv("TRUSTWORDS")){
Edouard@349
   107
            char *p = stpncpy(buffer, tw_env, MAX_PATH);
Edouard@814
   108
            ssize_t len = MAX_PATH - (p - buffer) - 2;
Edouard@347
   109
Edouard@347
   110
            if (len < strlen(SYSTEM_DB_FILENAME)) {
Edouard@347
   111
                assert(0);
Edouard@347
   112
                return NULL;
Edouard@347
   113
            }
Edouard@347
   114
Edouard@347
   115
            *p++ = '/';
Edouard@347
   116
            strncpy(p, SYSTEM_DB_FILENAME, len);
Edouard@347
   117
            done = true;
Edouard@347
   118
        }else{
Edouard@347
   119
            return NULL;
Edouard@347
   120
        }
Edouard@347
   121
Edouard@347
   122
    }
Edouard@347
   123
    return buffer;
Edouard@347
   124
}
Edouard@1119
   125
huss@1318
   126
markus@1226
   127
void uuid_generate_random(pEpUUID out)
Edouard@1119
   128
{
Edouard@1136
   129
    uuid_t *uuid;
Edouard@1136
   130
    uuid_rc_t rc_create;
huss@1318
   131
    size_t size = sizeof(uuid_string_t);
huss@1318
   132
    void *_out = out;
huss@1318
   133
	
Edouard@1136
   134
    if ((rc_create = uuid_create(&uuid)) != UUID_RC_OK ||
Edouard@1136
   135
        uuid_make(uuid, UUID_MAKE_V1) != UUID_RC_OK ||
huss@1318
   136
        uuid_export(uuid, UUID_FMT_BIN, &_out, &size) != UUID_RC_OK)
Edouard@1136
   137
    {
markus@1226
   138
        memset(out, 0, sizeof(pEpUUID));
Edouard@1136
   139
    }
Edouard@1136
   140
Edouard@1136
   141
    if (rc_create == UUID_RC_OK)
Edouard@1136
   142
    {
Edouard@1136
   143
        uuid_destroy(uuid);
Edouard@1136
   144
    }
Edouard@1119
   145
}
Edouard@1119
   146
huss@1318
   147
markus@1226
   148
void uuid_unparse_upper(pEpUUID uu, uuid_string_t out)
Edouard@1119
   149
{
Edouard@1136
   150
    uuid_t *uuid;
Edouard@1136
   151
    uuid_rc_t rc_create;
huss@1318
   152
    size_t size = sizeof(uuid_string_t);
huss@1318
   153
    void *_out = out;
Edouard@1136
   154
Edouard@1136
   155
    if ((rc_create = uuid_create(&uuid)) != UUID_RC_OK ||
Edouard@1262
   156
        uuid_import(uuid, UUID_FMT_BIN, uu, sizeof(pEpUUID)) != UUID_RC_OK ||
huss@1318
   157
        uuid_export(uuid, UUID_FMT_STR, &_out, &size) != UUID_RC_OK)
Edouard@1136
   158
    {
Edouard@1136
   159
        memset(out, 0, sizeof(uuid_string_t));
Edouard@1136
   160
    }
Edouard@1136
   161
    else 
Edouard@1136
   162
    {
Edouard@1136
   163
        out[sizeof(uuid_string_t) - 1] = 0;
Edouard@1136
   164
    }
Edouard@1136
   165
Edouard@1136
   166
    if (rc_create == UUID_RC_OK)
Edouard@1136
   167
    {
Edouard@1136
   168
        uuid_destroy(uuid);
Edouard@1136
   169
    }
Edouard@1119
   170
}
Edouard@1119
   171
Edouard@338
   172
#endif
Edouard@338
   173
vb@926
   174
#if !defined(BSD) && !defined(__APPLE__)
vb@926
   175
krista@918
   176
size_t strlcpy(char* dst, const	char* src, size_t size) {
krista@918
   177
    size_t retval = strlen(src);
krista@918
   178
    size_t size_to_copy = (retval < size ? retval : size - 1);
krista@918
   179
    
krista@918
   180
    // strlcpy doc says src and dst not allowed to overlap, as
krista@918
   181
    // it's undefined. So this is acceptable:
krista@918
   182
    memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
krista@918
   183
    dst[size_to_copy] = '\0';
krista@918
   184
    return retval;
krista@918
   185
}
vb@926
   186
krista@918
   187
size_t strlcat(char* dst, const	char* src, size_t size) {
krista@918
   188
    size_t start_len = strnlen(dst, size);
krista@918
   189
    if (start_len == size)
krista@918
   190
        return size; // no copy, no null termination in size bytes, according to spec
krista@918
   191
    
krista@918
   192
    size_t add_len = strlen(src);
krista@918
   193
    size_t retval = start_len + add_len;
krista@918
   194
    size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
krista@918
   195
    
krista@918
   196
    // strlcat doc says src and dst not allowed to overlap, as
krista@918
   197
    // it's undefined. So this is acceptable:
krista@918
   198
    memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
krista@918
   199
    dst[start_len + size_to_copy] = '\0';
krista@918
   200
    return retval;
krista@918
   201
}
vb@926
   202
krista@3901
   203
char *strnstr(const char *big, const char *little, size_t len) {
krista@3901
   204
    if (big == NULL || little == NULL)
krista@3901
   205
        return NULL;
krista@3901
   206
        
krista@3901
   207
    if (*little == '\0')
krista@3901
   208
        return (char*)big;
krista@3901
   209
        
krista@3901
   210
    const char* curr_big = big;
krista@3901
   211
    
krista@3901
   212
    size_t little_len = strlen(little);
krista@3901
   213
    size_t remaining = len;
krista@3901
   214
krista@3901
   215
    const char* retval = NULL;
krista@3901
   216
    
krista@3901
   217
    for (remaining = len; remaining >= little_len && *curr_big != '\0'; remaining--, curr_big++) {
krista@3901
   218
        // find first-char match
krista@3901
   219
        if (*curr_big != *little) {
krista@3901
   220
            continue;
krista@3901
   221
        }
krista@3901
   222
        retval = curr_big;
krista@3901
   223
krista@3901
   224
        const char* inner_big = retval + 1;
krista@3901
   225
        const char* curr_little = little + 1;
krista@3901
   226
        int j;
krista@3901
   227
        for (j = 1; j < little_len; j++, inner_big++, curr_little++) {
krista@3901
   228
            if (*inner_big != *curr_little) {
krista@3901
   229
                retval = NULL;
krista@3901
   230
                break;
krista@3901
   231
            }    
krista@3901
   232
        }
krista@3901
   233
        if (retval)
krista@3901
   234
            break;
krista@3901
   235
    }
krista@3901
   236
    return (char*)retval;
krista@3901
   237
}
krista@3901
   238
krista@3901
   239
krista@4471
   240
// #ifdef USE_NETPGP
krista@4471
   241
// // FIXME: This may cause problems - this is a quick compatibility fix for netpgp code
krista@4471
   242
// int regnexec(const regex_t* preg, const char* string,
krista@4471
   243
//              size_t len, size_t nmatch, regmatch_t pmatch[], int eflags) {
krista@4471
   244
//     return regexec(preg, string, nmatch, pmatch, eflags);
krista@4471
   245
// }
krista@4471
   246
// #endif
krista@1033
   247
krista@919
   248
#endif
krista@918
   249
vb@3997
   250
static char *_stradd(char **first, const char *second)
vb@3997
   251
{
vb@3997
   252
    assert(first && *first && second);
vb@3997
   253
    if (!(first && *first && second))
vb@3997
   254
        return NULL;
vb@3997
   255
vb@3997
   256
    size_t len1 = strlen(*first);
vb@3997
   257
    size_t len2 = strlen(second);
vb@3997
   258
    size_t size = len1 + len2 + 1;
vb@3997
   259
vb@3997
   260
    char *_first = realloc(*first, size);
vb@3997
   261
    assert(_first);
vb@3997
   262
    if (!_first)
vb@3997
   263
        return NULL;
vb@3997
   264
    *first = _first;
vb@3997
   265
vb@3997
   266
    strlcat(*first, second, size);
vb@3997
   267
    return *first;
vb@3997
   268
}
vb@3997
   269
vb@3997
   270
static void _empty(char **p)
vb@3997
   271
{
vb@3997
   272
    free(*p);
vb@3997
   273
    *p = NULL;
vb@3997
   274
}
vb@3997
   275
vb@3997
   276
static void _move(const char *o, const char *ext, const char *n)
vb@3997
   277
{
vb@3997
   278
    assert(o && ext && n);
vb@3997
   279
    if (!(o && ext && n))
vb@3997
   280
        return;
vb@3997
   281
vb@3997
   282
    char *_old = strdup(o);
vb@3997
   283
    assert(_old);
vb@3997
   284
    if (!_old)
vb@3997
   285
        return;
vb@3997
   286
vb@3997
   287
    char *r = _stradd(&_old, ext);
vb@3997
   288
    if (!r) {
vb@3997
   289
        free(_old);
vb@3997
   290
        return;
vb@3997
   291
    }
vb@3997
   292
vb@3997
   293
    char *_new = strdup(n);
vb@3997
   294
    assert(_new);
vb@3997
   295
    if (!_new) {
vb@3997
   296
        free(_old);
vb@3997
   297
        return;
vb@3997
   298
    }
vb@3997
   299
vb@3997
   300
    r = _stradd(&_new, ext);
vb@3997
   301
    if (r)
vb@3997
   302
        rename(_old, _new);
vb@3997
   303
vb@3997
   304
    free(_old);
vb@3997
   305
    free(_new);
vb@3997
   306
}
vb@3997
   307
krista@4089
   308
#ifndef NDEBUG
krista@4089
   309
static const char *_per_user_directory(int reset)
krista@4089
   310
#else 
krista@4089
   311
static const char *_per_user_directory(void)
krista@4089
   312
#endif
vb@1
   313
{
vb@3997
   314
    static char *path = NULL;
krista@4089
   315
krista@4089
   316
#ifdef NDEBUG    
vb@3997
   317
    if (path)
vb@3997
   318
        return path;
krista@4089
   319
#else        
krista@4089
   320
    if (path && !reset)
krista@4089
   321
        return path;
krista@4089
   322
    else if (path) {
krista@4089
   323
        free(path);
krista@4089
   324
        path = NULL;
krista@4089
   325
    }
krista@4089
   326
#endif    
vb@3997
   327
vb@3997
   328
    const char *home = NULL;
vb@3997
   329
#ifndef NDEBUG
vb@3997
   330
    home = getenv("PEP_HOME");
vb@3997
   331
    if (!home)
vb@3997
   332
#endif
vb@3997
   333
    home = getenv("HOME");
vb@4003
   334
    assert(home);
vb@4003
   335
    if (!home)
vb@4003
   336
        return NULL;
vb@3997
   337
vb@3997
   338
    path = strdup(home);
vb@3997
   339
    assert(path);
vb@3997
   340
    if (!path)
vb@3997
   341
        return NULL;
vb@3997
   342
vb@4003
   343
    char *_path = _stradd(&path, "/");   
vb@4003
   344
    if (!_path)
vb@4003
   345
        goto error;
vb@4003
   346
vb@4003
   347
    _path = _stradd(&path, PER_USER_DIRECTORY);
vb@4003
   348
    if (!_path)
vb@4003
   349
        goto error;
vb@4003
   350
vb@4003
   351
    return path;
vb@4003
   352
vb@4003
   353
error:
vb@4003
   354
    _empty(&path);
vb@4003
   355
    return NULL;
vb@4003
   356
}
vb@4003
   357
vb@4003
   358
#ifdef NDEBUG
vb@4003
   359
const char *unix_local_db(void)
vb@4003
   360
#else
vb@4003
   361
const char *unix_local_db(int reset)
vb@4003
   362
#endif
vb@4003
   363
{
vb@4003
   364
    static char *path = NULL;
vb@4003
   365
#ifdef NDEBUG
vb@4003
   366
    if (path)
vb@4003
   367
#else
vb@4003
   368
    if (path && !reset)
vb@4003
   369
#endif
vb@4003
   370
        return path;
vb@4003
   371
vb@4128
   372
    const char* pathret = NULL;
krista@4089
   373
#ifndef NDEBUG 
krista@4089
   374
    pathret = _per_user_directory(reset);
krista@4089
   375
#else 
krista@4089
   376
    pathret = _per_user_directory();
krista@4089
   377
#endif
krista@4089
   378
krista@4089
   379
    if (!pathret)
vb@4003
   380
        return NULL;
vb@4003
   381
krista@4089
   382
    path = strdup(pathret);
vb@4003
   383
    assert(path);
vb@4003
   384
    if (!path)
vb@4003
   385
        return NULL;
vb@4003
   386
vb@3997
   387
    char *path_c = NULL;
vb@3997
   388
    char *old_path = NULL;
vb@3997
   389
    char *old_path_c = NULL;
vb@3997
   390
vb@3997
   391
    struct stat dir;
vb@3997
   392
    int r = stat(path, &dir);
vb@3997
   393
    if (r) {
vb@3997
   394
        if (errno == ENOENT) {
vb@3997
   395
            // directory does not yet exist
vb@3997
   396
            r = mkdir(path, 0700);
vb@3997
   397
            if (r)
vb@3997
   398
                goto error;
vb@3997
   399
        }
vb@3997
   400
        else {
vb@3997
   401
            goto error;
vb@3997
   402
        }
vb@3997
   403
    }
vb@3997
   404
vb@4003
   405
    char *_path = _stradd(&path, "/");   
vb@3997
   406
    if (!_path)
vb@3997
   407
        goto error;
vb@3997
   408
vb@3997
   409
    // make a copy of this path in case we need to move files
vb@3997
   410
    path_c = strdup(path);
vb@3997
   411
    assert(path_c);
vb@3997
   412
    if (!path_c)
vb@3997
   413
        goto error;
vb@3997
   414
vb@3997
   415
    _path = _stradd(&path, LOCAL_DB_FILENAME);
vb@3997
   416
    if (!_path)
vb@3997
   417
        goto error;
vb@1
   418
vb@3997
   419
    struct stat file;
vb@3997
   420
    r = stat(path, &file);
vb@3997
   421
    if (r) {
vb@3997
   422
        if (errno == ENOENT) {
vb@3997
   423
            // we do not have management.db yet, let's test if we need to move
vb@3997
   424
            // one with the old name
vb@4003
   425
            const char *home = NULL;
vb@4003
   426
#ifndef NDEBUG
vb@4003
   427
            home = getenv("PEP_HOME");
vb@4003
   428
            if (!home)
vb@4003
   429
#endif
vb@4003
   430
            home = getenv("HOME");
vb@4003
   431
            // we were already checking for HOME existing, so this is only a
vb@4003
   432
            // safeguard
vb@4003
   433
            assert(home);
vb@4003
   434
vb@3997
   435
            old_path = strdup(home);
vb@3997
   436
            assert(old_path);
vb@3997
   437
            if (!old_path)
vb@3997
   438
                goto error;
vb@3997
   439
vb@3997
   440
            char *_old_path = _stradd(&old_path, "/");   
vb@3997
   441
            if (!_old_path)
vb@3997
   442
                goto error;
vb@3997
   443
vb@3997
   444
            old_path_c = strdup(old_path);
vb@3997
   445
            assert(old_path_c);
vb@3997
   446
            if (!old_path_c)
vb@3997
   447
                goto error;
vb@3997
   448
vb@3997
   449
            _old_path = _stradd(&old_path, OLD_LOCAL_DB_FILENAME);
vb@3997
   450
            if (!_old_path)
vb@3997
   451
                goto error;
vb@3997
   452
vb@3997
   453
            struct stat old;
vb@3997
   454
            r = stat(old_path, &old);
vb@3997
   455
            if (r == 0) {
vb@3997
   456
                // old file existing, new file not yet existing, move
vb@3997
   457
                rename(old_path, path);
Edouard@346
   458
vb@3997
   459
                // if required move associated files, too
vb@3997
   460
                _move(old_path, "-shm", path);
vb@3997
   461
                _move(old_path, "-wal", path);
vb@3997
   462
vb@3997
   463
                // move keys database
vb@3997
   464
                _old_path = _stradd(&old_path_c, OLD_KEYS_DB_FILENAME);
vb@3997
   465
                if (!_old_path)
vb@3997
   466
                    goto error;
vb@3997
   467
vb@3997
   468
                _path = _stradd(&path_c, KEYS_DB_FILENAME);
vb@3997
   469
                if (!_path)
vb@3997
   470
                    goto error;
vb@3997
   471
vb@3997
   472
                rename(old_path_c, path_c);
vb@3997
   473
vb@3997
   474
                // if required move associated files, too
vb@3997
   475
                _move(old_path_c, "-shm", path_c);
vb@3997
   476
                _move(old_path_c, "-wal", path_c);
vb@3997
   477
            }
vb@1
   478
        }
vb@3997
   479
        else {
vb@3997
   480
            goto error;
vb@3997
   481
        }
vb@1
   482
    }
vb@3997
   483
    goto the_end;
vb@3997
   484
vb@3997
   485
error:
vb@3997
   486
    _empty(&path);
vb@3997
   487
vb@3997
   488
the_end:
vb@3997
   489
    free(path_c);
vb@3997
   490
    free(old_path);
vb@3997
   491
    free(old_path_c);
vb@3997
   492
    return path;
vb@1
   493
}
vb@1
   494
krista@4089
   495
DYNAMIC_API const char *per_user_directory(void) {
krista@4089
   496
#ifdef NDEBUG
andreas@4101
   497
    return _per_user_directory();
krista@4089
   498
#else 
krista@4089
   499
    return _per_user_directory(false);
krista@4089
   500
#endif
krista@4089
   501
}
krista@4089
   502
vb@4003
   503
DYNAMIC_API const char *per_machine_directory(void)
vb@4003
   504
{
vb@4003
   505
    return PER_MACHINE_DIRECTORY;
vb@4003
   506
}
vb@4003
   507
vb@4003
   508
const char *unix_system_db(void)
vb@4003
   509
{
vb@4003
   510
    static char *path = NULL;
vb@4003
   511
    if (path)
vb@4003
   512
        return path;
vb@4003
   513
vb@4003
   514
    path = strdup(per_machine_directory());
vb@4003
   515
    assert(path);
vb@4003
   516
    if (!path)
vb@4003
   517
        return NULL;
vb@4003
   518
vb@4003
   519
    char *_path = _stradd(&path, "/");
vb@4003
   520
    if (!_path)
vb@4003
   521
        goto error;
vb@4003
   522
vb@4003
   523
    _path = _stradd(&path, SYSTEM_DB_FILENAME);
vb@4003
   524
    if (!_path)
vb@4003
   525
        goto error;
vb@4003
   526
vb@4003
   527
    return path;
vb@4003
   528
vb@4003
   529
error:
vb@4003
   530
    _empty(&path);
vb@4003
   531
    return NULL;
vb@4003
   532
}