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