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