src/platform_windows.cpp
author Krista Bennett <krista@pep-project.org>
Tue, 14 Aug 2018 13:45:34 +0200
branchENGINE-451
changeset 2826 07c080d73a63
parent 2808 fb8e139fcef6
permissions -rw-r--r--
ENGINE-451: abandoning branch - config files to be dealt with using gpgme (and hotfix will be external to engine
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 // Windows platform specification
     5 
     6 #define WIN32_LEAN_AND_MEAN
     7 #ifndef UNICODE
     8 #define UNICODE
     9 #endif
    10 #define _WIN32_WINNT 0x0600
    11 
    12 #include <windows.h>
    13 #define _CRT_RAND_S
    14 #include <stdlib.h>
    15 #include <assert.h>
    16 #include <string.h>
    17 #include <string>
    18 #include <stdexcept>
    19 #include "platform_windows.h"
    20 #include <fcntl.h>
    21 #include <tchar.h>
    22 #include <sys\stat.h>
    23 
    24 #ifndef WC_ERR_INVALID_CHARS
    25 #define WC_ERR_INVALID_CHARS      0x00000080  // error for invalid chars
    26 #endif
    27 
    28 using namespace std;
    29 
    30 static string utf8_string(wstring wstr) {
    31     string result;
    32 
    33     if (wstr.length()) {
    34         int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
    35                 wstr.c_str(), -1, NULL, 0, NULL, NULL);
    36         assert(size);
    37         if (size) {
    38             char *buf = new char[size];
    39             WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr.c_str(),
    40                     -1, buf, size, NULL, NULL);
    41             result = buf;
    42             delete[] buf;
    43         } else
    44             throw out_of_range("input wstring is not valid"
    45                     " while converting UTF-16 to UTF-8.");
    46     }
    47 
    48     return result;
    49 }
    50 
    51 static wstring utf16_string(string str) {
    52     wstring result;
    53 
    54     if (str.length()) {
    55         int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
    56                 str.c_str(), -1, NULL, 0);
    57         assert(size);
    58         if (size) {
    59             wchar_t * buf = new wchar_t[size];
    60             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1,
    61                     buf, size);
    62             result = buf;
    63             delete[] buf;
    64         } else
    65             throw out_of_range("input string is not valid"
    66                     " while converting UTF-8 to UTF-16.");
    67     }
    68 
    69     return result;
    70 }
    71 
    72 static bool readRegistryString(
    73         HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPTSTR lpResult,
    74         DWORD dwSize, LPCTSTR lpDefault
    75     )
    76 {
    77     assert(lpResult);
    78 
    79 	HKEY theKey;
    80 	DWORD type;
    81 	DWORD bytesCopied = dwSize;
    82 	HRESULT result;
    83 
    84 	result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &theKey);
    85 	if (result != ERROR_SUCCESS) {
    86 		if (lpDefault) {
    87 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    88 			return true;
    89 		}
    90 		else
    91 			return false;
    92 	}
    93 
    94 	result = RegQueryValueEx(theKey, lpValueName, NULL, &type,
    95             (LPBYTE) lpResult, &bytesCopied);
    96     if (result != ERROR_SUCCESS || (type != REG_EXPAND_SZ && type != REG_SZ)) {
    97 		if (lpDefault) {
    98 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    99 			RegCloseKey(theKey);
   100 			return true;
   101 		}
   102 		else {
   103 			RegCloseKey(theKey);
   104 			return false;
   105 		}
   106 	}
   107 
   108 	RegCloseKey(theKey);
   109 	return true;
   110 }
   111 
   112 static const DWORD PATH_BUF_SIZE = 32768;
   113 
   114 static inline string managementPath(const char *file_path, const char *file_name)
   115 {
   116     string path;
   117 	static TCHAR tPath[PATH_BUF_SIZE];
   118 
   119     DWORD length = ExpandEnvironmentStringsW(utf16_string(file_path).c_str(),
   120             tPath, PATH_BUF_SIZE);
   121 	assert(length);
   122     if (length == 0)
   123         throw bad_alloc(); // BUG: there are other errors possible beside out of memory
   124 
   125 	CreateDirectory(tPath, NULL);
   126 	DWORD error = GetLastError();
   127 
   128 	path = utf8_string(tPath);
   129 	path += "\\";
   130 	path += file_name;
   131 
   132 	return path;
   133 }
   134 
   135 extern "C" {
   136 
   137 void *dlopen(const char *filename, int flag) {
   138 	static TCHAR path[PATH_BUF_SIZE];
   139 
   140     assert(filename);
   141 	assert(flag == RTLD_LAZY); // only lazy binding is implemented
   142 
   143 	// Look up GnuPG installation in current user scope
   144 	bool result = readRegistryString(HKEY_CURRENT_USER,
   145 		TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
   146 		PATH_BUF_SIZE, NULL);
   147 	// If not found in current user, look up in local machine
   148 	if (!result)
   149 		result = readRegistryString(HKEY_LOCAL_MACHINE,
   150 			TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
   151 			PATH_BUF_SIZE, NULL);
   152 	assert(result);
   153 	if (!result)
   154 		return NULL;
   155 
   156     SetDllDirectory(TEXT(""));
   157     BOOL _result = SetDllDirectory(path);
   158     assert(_result != 0);
   159     if (_result == 0)
   160         return NULL;
   161 
   162 	HMODULE module = LoadLibrary(utf16_string(filename).c_str());
   163 
   164     if (module == NULL) {
   165         SetDllDirectory(NULL);
   166                     
   167 		_tcscat_s(path, TEXT("\\bin"));
   168         
   169         SetDllDirectory(TEXT(""));
   170         _result = SetDllDirectory(path);
   171         assert(_result != 0);
   172         if (_result == 0)
   173             return NULL;
   174 
   175     	module = LoadLibrary(utf16_string(filename).c_str());
   176     }
   177     
   178     SetDllDirectory(NULL);
   179 	if (module == NULL)
   180 		return NULL;
   181 	else
   182 		return (void *) module;
   183 }
   184 
   185 int dlclose(void *handle) {
   186 	if (FreeLibrary((HMODULE) handle))
   187 		return 0;
   188 	else
   189 		return 1;
   190 }
   191 
   192 void *dlsym(void *handle, const char *symbol) {
   193 	return (void *) (intptr_t) GetProcAddress((HMODULE) handle, symbol);
   194 }
   195 
   196 const char *windoze_local_db(void) {
   197 	static string path;
   198 	if (path.length() == 0)
   199         path = managementPath("%LOCALAPPDATA%\\pEp", "management.db");
   200     return path.c_str();
   201 }
   202 
   203 const char *windoze_system_db(void) {
   204 	static string path;
   205 	if (path.length() == 0)
   206 		path = managementPath("%ALLUSERSPROFILE%\\pEp", "system.db");
   207     return path.c_str();
   208 }
   209 
   210 const char *gpg_conf(void)
   211 {
   212     static string path;
   213     if (path.length() == 0)
   214         path = managementPath("%APPDATA%\\gnupg", "gpg.conf");
   215     return path.c_str();
   216 }
   217 
   218 const char *gpg_agent_conf(void)
   219 {
   220     static string agent_path;
   221     if (agent_path.length() == 0)
   222         agent_path = managementPath("%APPDATA%\\gnupg", "gpg-agent.conf");
   223     return agent_path.c_str();
   224 }
   225 
   226 
   227 long random(void)
   228 {
   229     unsigned int r;
   230     errno_t e;
   231 
   232     assert(sizeof(unsigned int) == sizeof(long)); // this is Windoze
   233 
   234     do {
   235         e = rand_s(&r);
   236     } while (e);
   237 
   238     return (long) (r & ((1U<<31)-1));
   239 }
   240 
   241 char *strndup(const char *s1, size_t n)
   242 {
   243     char *str = (char *) calloc(n + 1, 1);
   244     if (str == NULL)
   245         return NULL;
   246 
   247     strncpy(str, s1, n);
   248     return str;
   249 }
   250 
   251 char *stpcpy(char *dst, const char *src)
   252 {
   253     for (;; ++dst, ++src) {
   254         *dst = *src;
   255         if (*dst == 0)
   256             break;
   257     }
   258     return dst;
   259 }
   260 
   261 size_t strlcpy(char* dst, const	char* src, size_t size) {
   262     size_t retval = strlen(src);
   263     size_t size_to_copy = (retval < size ? retval : size - 1);
   264     
   265     // strlcpy doc says src and dst not allowed to overlap, as
   266     // it's undefined. So this is acceptable:
   267     memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   268     dst[size_to_copy] = '\0';
   269     return retval;
   270 }
   271 size_t strlcat(char* dst, const	char* src, size_t size) {
   272     size_t start_len = strnlen(dst, size);
   273     if (start_len == size)
   274         return size; // no copy, no null termination in size bytes, according to spec
   275     
   276     size_t add_len = strlen(src);
   277     size_t retval = start_len + add_len;
   278     size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
   279     
   280     // strlcat doc says src and dst not allowed to overlap, as
   281     // it's undefined. So this is acceptable:
   282     memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   283     dst[start_len + size_to_copy] = '\0';
   284     return retval;
   285 }
   286 
   287 int mkstemp(char *templ)
   288 {
   289     char *pathname = _mktemp(templ);
   290     if (pathname == NULL)
   291         return -1;
   292     return _open(pathname, _O_RDWR | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
   293 }
   294 
   295 void uuid_generate_random(pEpUUID out)
   296 {
   297     RPC_STATUS rpc_status = UuidCreate(out);
   298     assert(rpc_status == RPC_S_OK);
   299 }
   300 
   301 int uuid_parse(char *in, pEpUUID uu)
   302 {
   303     unsigned char *_in = (unsigned char *) in;
   304     RPC_STATUS rpc_status = UuidFromStringA(_in, uu);
   305     assert(rpc_status == RPC_S_OK);
   306     if (rpc_status == RPC_S_INVALID_STRING_UUID)
   307         return -1;
   308     return 0;
   309 }
   310 
   311 void uuid_unparse_upper(pEpUUID uu, uuid_string_t out)
   312 {
   313     unsigned char *_out = (unsigned char*)out;
   314     RPC_CSTR str;
   315     RPC_STATUS rpc_status = UuidToStringA(uu, &str);
   316     assert(rpc_status == RPC_S_OK);
   317     if (rpc_status == RPC_S_OK) {
   318         memcpy(out, str, 36);
   319         out[36] = 0;
   320         RpcStringFreeA(&str);
   321     }
   322     else { // if (rpc_status == RPC_S_OUT_OF_MEMORY)
   323         memset(out, 0, 37);
   324     }
   325 }
   326 
   327 time_t timegm(struct tm* tm) {
   328     return _mkgmtime(tm);
   329 }
   330 
   331 } // "C"