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