src/platform_unix.c
author Edouard Tisserant
Tue, 11 Oct 2016 17:58:15 +0200
changeset 1267 1b7df2133aab
parent 1262 d6339a9c973e
child 1318 72e7ce41cce0
permissions -rw-r--r--
Added timegm() for Android in platform_unix.c
vb@1
     1
#define _POSIX_C_SOURCE 200809L
vb@1
     2
Edouard@1267
     3
#ifdef ANDROID
Edouard@1267
     4
#ifndef __LP64__ 
Edouard@1267
     5
#include <time64.h>
Edouard@1267
     6
#endif
Edouard@1267
     7
#endif
Edouard@1267
     8
Edouard@1136
     9
#include <time.h>
vb@1
    10
#include <string.h>
vb@1
    11
#include <stdlib.h>
vb@1
    12
#include <assert.h>
Edouard@158
    13
#include <sys/stat.h>
vb@149
    14
#include <sys/types.h>
Edouard@158
    15
#include <fcntl.h>
krista@1033
    16
#include <regex.h>
Edouard@158
    17
vb@1
    18
#include "platform_unix.h"
vb@1
    19
vb@1
    20
#define MAX_PATH 1024
vb@1089
    21
#ifndef LOCAL_DB_FILENAME
vb@1
    22
#define LOCAL_DB_FILENAME ".pEp_management.db"
vb@1089
    23
#endif
Edouard@347
    24
#define SYSTEM_DB_FILENAME "system.db"
vb@1
    25
vb@1
    26
#ifndef bool
vb@1
    27
#define bool int
vb@1
    28
#define true 1
vb@1
    29
#define false 0
vb@1
    30
#endif
vb@1
    31
Edouard@347
    32
#ifdef ANDROID
Edouard@1119
    33
#include <uuid.h>
Edouard@1267
    34
Edouard@1267
    35
/* FIXME : timegm will miss when linking for x86_64 on android, when supported */
Edouard@1267
    36
#ifndef __LP64__ 
Edouard@1267
    37
time_t timegm(struct tm* const t) {
Edouard@1267
    38
    static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1));
Edouard@1267
    39
    static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1));
Edouard@1267
    40
    time64_t result = timegm64(t);
Edouard@1267
    41
    if (result < kTimeMin || result > kTimeMax)
Edouard@1267
    42
        return -1;
Edouard@1267
    43
    return result;
Edouard@1267
    44
}
Edouard@1267
    45
#endif
Edouard@1267
    46
Edouard@347
    47
char *stpncpy(char *dst, const char *src, size_t n)
Edouard@333
    48
{
Edouard@333
    49
    if (n != 0) {
Edouard@333
    50
        char *d = dst;
Edouard@333
    51
        const char *s = src;
Edouard@333
    52
Edouard@333
    53
        dst = &dst[n];
Edouard@333
    54
        do {
Edouard@333
    55
            if ((*d++ = *s++) == 0) {
Edouard@333
    56
                dst = d - 1;
Edouard@333
    57
                /* NUL pad the remaining n-1 bytes */
Edouard@333
    58
                while (--n != 0)
Edouard@333
    59
                    *d++ = 0;
Edouard@333
    60
                break;
Edouard@333
    61
            }
Edouard@333
    62
        } while (--n != 0);
Edouard@333
    63
    }
Edouard@333
    64
    return (dst);
Edouard@333
    65
}
Edouard@333
    66
Edouard@338
    67
char *stpcpy(char *dst, const char *src)
Edouard@338
    68
{
Edouard@338
    69
    for (;; ++dst, ++src) {
Edouard@338
    70
        *dst = *src;
Edouard@338
    71
        if (*dst == 0)
Edouard@338
    72
            break;
Edouard@338
    73
    }
Edouard@338
    74
    return dst;
Edouard@338
    75
}
Edouard@338
    76
roker@438
    77
long int random(void)
roker@438
    78
{
Edouard@841
    79
    static bool seeded = false;
Edouard@838
    80
    static unsigned short xsubi[3];
Edouard@841
    81
    if(!seeded)
Edouard@841
    82
    {
roker@847
    83
        const long long t = (long long)time(NULL);
roker@847
    84
        xsubi[0] = (unsigned short)t;
roker@847
    85
        xsubi[1] = (unsigned short)(t>>16);
roker@847
    86
        xsubi[2] = (unsigned short)(t>>32);
Edouard@841
    87
        seeded = true;
Edouard@841
    88
    }
Edouard@838
    89
vb@436
    90
    return nrand48(xsubi);
Edouard@338
    91
}
Edouard@347
    92
Edouard@347
    93
const char *android_system_db(void)
Edouard@347
    94
{
Edouard@347
    95
    static char buffer[MAX_PATH];
Edouard@347
    96
    static bool done = false;
Edouard@347
    97
Edouard@347
    98
    if (!done) {
Edouard@349
    99
        char *tw_env;
Edouard@349
   100
        if(tw_env = getenv("TRUSTWORDS")){
Edouard@349
   101
            char *p = stpncpy(buffer, tw_env, MAX_PATH);
Edouard@814
   102
            ssize_t len = MAX_PATH - (p - buffer) - 2;
Edouard@347
   103
Edouard@347
   104
            if (len < strlen(SYSTEM_DB_FILENAME)) {
Edouard@347
   105
                assert(0);
Edouard@347
   106
                return NULL;
Edouard@347
   107
            }
Edouard@347
   108
Edouard@347
   109
            *p++ = '/';
Edouard@347
   110
            strncpy(p, SYSTEM_DB_FILENAME, len);
Edouard@347
   111
            done = true;
Edouard@347
   112
        }else{
Edouard@347
   113
            return NULL;
Edouard@347
   114
        }
Edouard@347
   115
Edouard@347
   116
    }
Edouard@347
   117
    return buffer;
Edouard@347
   118
}
Edouard@1119
   119
markus@1226
   120
// TODO: Check and possibly fix this function if necessary
markus@1226
   121
void uuid_generate_random(pEpUUID out)
Edouard@1119
   122
{
Edouard@1136
   123
    uuid_t *uuid;
Edouard@1136
   124
    uuid_rc_t rc_create;
Edouard@1136
   125
Edouard@1136
   126
    if ((rc_create = uuid_create(&uuid)) != UUID_RC_OK ||
Edouard@1136
   127
        uuid_make(uuid, UUID_MAKE_V1) != UUID_RC_OK ||
Edouard@1136
   128
        uuid_export(uuid, UUID_FMT_BIN, out, NULL) != UUID_RC_OK)
Edouard@1136
   129
    {
markus@1226
   130
        memset(out, 0, sizeof(pEpUUID));
Edouard@1136
   131
    }
Edouard@1136
   132
Edouard@1136
   133
    if (rc_create == UUID_RC_OK)
Edouard@1136
   134
    {
Edouard@1136
   135
        uuid_destroy(uuid);
Edouard@1136
   136
    }
Edouard@1119
   137
}
Edouard@1119
   138
markus@1226
   139
// TODO: Check and possibly fix this function if necessary
markus@1226
   140
void uuid_unparse_upper(pEpUUID uu, uuid_string_t out)
Edouard@1119
   141
{
Edouard@1136
   142
    uuid_t *uuid;
Edouard@1136
   143
    uuid_rc_t rc_create;
Edouard@1136
   144
Edouard@1136
   145
    if ((rc_create = uuid_create(&uuid)) != UUID_RC_OK ||
Edouard@1262
   146
        uuid_import(uuid, UUID_FMT_BIN, uu, sizeof(pEpUUID)) != UUID_RC_OK ||
Edouard@1136
   147
        uuid_export(uuid, UUID_FMT_STR, out, NULL) != UUID_RC_OK)
Edouard@1136
   148
    {
Edouard@1136
   149
        memset(out, 0, sizeof(uuid_string_t));
Edouard@1136
   150
    }
Edouard@1136
   151
    else 
Edouard@1136
   152
    {
Edouard@1136
   153
        out[sizeof(uuid_string_t) - 1] = 0;
Edouard@1136
   154
    }
Edouard@1136
   155
Edouard@1136
   156
    if (rc_create == UUID_RC_OK)
Edouard@1136
   157
    {
Edouard@1136
   158
        uuid_destroy(uuid);
Edouard@1136
   159
    }
Edouard@1119
   160
}
Edouard@1119
   161
Edouard@338
   162
#endif
Edouard@338
   163
vb@926
   164
#if !defined(BSD) && !defined(__APPLE__)
vb@926
   165
krista@918
   166
size_t strlcpy(char* dst, const	char* src, size_t size) {
krista@918
   167
    size_t retval = strlen(src);
krista@918
   168
    size_t size_to_copy = (retval < size ? retval : size - 1);
krista@918
   169
    
krista@918
   170
    // strlcpy doc says src and dst not allowed to overlap, as
krista@918
   171
    // it's undefined. So this is acceptable:
krista@918
   172
    memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
krista@918
   173
    dst[size_to_copy] = '\0';
krista@918
   174
    return retval;
krista@918
   175
}
vb@926
   176
krista@918
   177
size_t strlcat(char* dst, const	char* src, size_t size) {
krista@918
   178
    size_t start_len = strnlen(dst, size);
krista@918
   179
    if (start_len == size)
krista@918
   180
        return size; // no copy, no null termination in size bytes, according to spec
krista@918
   181
    
krista@918
   182
    size_t add_len = strlen(src);
krista@918
   183
    size_t retval = start_len + add_len;
krista@918
   184
    size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
krista@918
   185
    
krista@918
   186
    // strlcat doc says src and dst not allowed to overlap, as
krista@918
   187
    // it's undefined. So this is acceptable:
krista@918
   188
    memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
krista@918
   189
    dst[start_len + size_to_copy] = '\0';
krista@918
   190
    return retval;
krista@918
   191
}
vb@926
   192
krista@1095
   193
#ifdef USE_NETPGP
krista@1033
   194
// FIXME: This may cause problems - this is a quick compatibility fix for netpgp code
krista@1033
   195
int regnexec(const regex_t* preg, const char* string,
krista@1033
   196
             size_t len, size_t nmatch, regmatch_t pmatch[], int eflags) {
krista@1033
   197
    return regexec(preg, string, nmatch, pmatch, eflags);
krista@1033
   198
}
krista@1095
   199
#endif
krista@1033
   200
krista@919
   201
#endif
krista@918
   202
vb@1
   203
const char *unix_local_db(void)
vb@1
   204
{
vb@1
   205
    static char buffer[MAX_PATH];
vb@1
   206
    static bool done = false;
vb@1
   207
vb@1
   208
    if (!done) {
Edouard@346
   209
        char *home_env;
vb@352
   210
        if((home_env = getenv("HOME"))){
Edouard@347
   211
            char *p = stpncpy(buffer, home_env, MAX_PATH);
Edouard@814
   212
            ssize_t len = MAX_PATH - (p - buffer) - 2;
vb@1
   213
Edouard@346
   214
            if (len < strlen(LOCAL_DB_FILENAME)) {
Edouard@346
   215
                assert(0);
Edouard@346
   216
                return NULL;
Edouard@346
   217
            }
Edouard@346
   218
Edouard@346
   219
            *p++ = '/';
Edouard@346
   220
            strncpy(p, LOCAL_DB_FILENAME, len);
Edouard@346
   221
            done = true;
Edouard@346
   222
        }else{
vb@1
   223
            return NULL;
vb@1
   224
        }
vb@1
   225
vb@1
   226
    }
vb@1
   227
    return buffer;
vb@1
   228
}
vb@1
   229
vb@1
   230
static const char *gpg_conf_path = ".gnupg";
vb@1
   231
static const char *gpg_conf_name = "gpg.conf";
krista@763
   232
static const char *gpg_agent_conf_name = "gpg-agent.conf";
Edouard@158
   233
static const char *gpg_conf_empty = "# Created by pEpEngine\n";
vb@1
   234
Edouard@168
   235
static bool ensure_gpg_home(const char **conf, const char **home){
Edouard@168
   236
    static char path[MAX_PATH];
Edouard@158
   237
    static char dirname[MAX_PATH];
vb@1
   238
    static bool done = false;
vb@1
   239
vb@1
   240
    if (!done) {
Edouard@168
   241
        char *p;
Edouard@814
   242
        ssize_t len;
Edouard@168
   243
        char *gpg_home_env = getenv("GNUPGHOME");
Edouard@346
   244
        char *home_env = getenv("HOME");
Edouard@158
   245
Edouard@168
   246
        if(gpg_home_env){
Edouard@168
   247
Edouard@347
   248
            p = stpncpy(path, gpg_home_env, MAX_PATH);
Edouard@168
   249
            len = MAX_PATH - (p - path) - 2;
Edouard@168
   250
Edouard@158
   251
            if (len < strlen(gpg_conf_name))
Edouard@158
   252
            {
Edouard@158
   253
                assert(0);
Edouard@168
   254
                return false;
Edouard@158
   255
            }
Edouard@158
   256
Edouard@346
   257
        }else if(home_env){
vb@1
   258
Edouard@347
   259
            p = stpncpy(path, home_env, MAX_PATH);
Edouard@168
   260
            len = MAX_PATH - (p - path) - 3;
Edouard@158
   261
Edouard@158
   262
            if (len < strlen(gpg_conf_path) + strlen(gpg_conf_name))
Edouard@158
   263
            {
Edouard@158
   264
                assert(0);
Edouard@168
   265
                return false;
Edouard@158
   266
            }
Edouard@158
   267
Edouard@158
   268
            *p++ = '/';
Edouard@158
   269
            strncpy(p, gpg_conf_path, len);
Edouard@158
   270
            p += strlen(gpg_conf_path);
Edouard@158
   271
            len -= strlen(gpg_conf_path) - 1;
Edouard@346
   272
Edouard@346
   273
        }else{
Edouard@346
   274
Edouard@346
   275
            assert(0);
Edouard@346
   276
            return false;
vb@1
   277
        }
vb@1
   278
Edouard@168
   279
        strncpy(dirname, path, MAX_PATH);
Edouard@168
   280
        *p++ = '/';
Edouard@168
   281
        strncpy(p, gpg_conf_name, len);
Edouard@168
   282
Edouard@168
   283
        if(access(path, F_OK)){ 
Edouard@158
   284
            int fd;
Edouard@158
   285
            if(access(dirname, F_OK )) { 
Edouard@158
   286
                mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR);
Edouard@158
   287
            }
vb@149
   288
Edouard@168
   289
            fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
vb@149
   290
Edouard@158
   291
            if(fd>0) {
Edouard@158
   292
                write(fd, gpg_conf_empty, strlen(gpg_conf_empty));
Edouard@158
   293
                close(fd);
Edouard@158
   294
            }
Edouard@158
   295
        }
vb@1
   296
vb@1
   297
        done = true;
vb@1
   298
    }
Edouard@168
   299
Edouard@168
   300
    if(conf) *conf=path;
Edouard@168
   301
    if(home) *home=dirname;
Edouard@168
   302
Edouard@168
   303
    return true;
vb@1
   304
}
Edouard@168
   305
krista@763
   306
static bool ensure_gpg_agent_conf(const char **agent_conf){
krista@763
   307
    static char agent_path[MAX_PATH];
krista@763
   308
    static bool done = false;
krista@763
   309
krista@763
   310
    if (!done) {
krista@763
   311
        const char *dirname;
krista@763
   312
krista@763
   313
        if (!ensure_gpg_home(NULL, &dirname)) /* Then dirname won't be set. */
krista@763
   314
            return false;
krista@763
   315
krista@763
   316
        char *p;
krista@763
   317
        p = stpncpy(agent_path, dirname, MAX_PATH);
krista@763
   318
        
Edouard@814
   319
        ssize_t len = MAX_PATH - (p - agent_path) - 2;
krista@763
   320
krista@763
   321
        if (len < strlen(gpg_agent_conf_name))
krista@763
   322
        {
krista@763
   323
            assert(0);
krista@763
   324
            return false;
krista@763
   325
        }
krista@763
   326
krista@763
   327
        *p++ = '/';
krista@763
   328
     
krista@763
   329
        strncpy(p, gpg_agent_conf_name, len);
krista@763
   330
krista@763
   331
        if(access(agent_path, F_OK)){ 
krista@763
   332
            int fd;
krista@763
   333
            if(access(dirname, F_OK )) { 
krista@763
   334
                mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR);
krista@763
   335
            }
krista@763
   336
krista@763
   337
            fd = open(agent_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
krista@763
   338
krista@763
   339
            if(fd>0) {
krista@763
   340
                write(fd, gpg_conf_empty, strlen(gpg_conf_empty));
krista@763
   341
                close(fd);
krista@763
   342
            }
krista@763
   343
        }
krista@763
   344
        done = true;
krista@763
   345
    }
krista@763
   346
    if(agent_conf) *agent_conf=agent_path;
krista@763
   347
krista@763
   348
    return true;
krista@763
   349
}
krista@763
   350
Edouard@168
   351
const char *gpg_conf(void)
Edouard@168
   352
{
Edouard@168
   353
    const char *conf;
Edouard@168
   354
    if(ensure_gpg_home(&conf, NULL))
Edouard@168
   355
        return conf;
Edouard@168
   356
    return NULL;
Edouard@168
   357
}
Edouard@168
   358
Edouard@168
   359
const char *gpg_home(void)
Edouard@168
   360
{
Edouard@168
   361
    const char *home;
Edouard@168
   362
    if(ensure_gpg_home(NULL, &home))
Edouard@168
   363
        return home;
Edouard@168
   364
    return NULL;
Edouard@168
   365
}
krista@763
   366
krista@763
   367
const char *gpg_agent_conf(void)
krista@763
   368
{
krista@763
   369
    const char *agent_conf;
krista@763
   370
    if(ensure_gpg_agent_conf(&agent_conf))
krista@763
   371
        return agent_conf;
krista@763
   372
    return NULL;
krista@763
   373
}