src/platform_windows.cpp
author Krista Grothoff <krista@pep-project.org>
Sat, 24 Sep 2016 18:09:18 +0200
branchENGINE-27
changeset 1185 4b01328f3cf2
parent 920 4b31d5d0e4d0
child 948 2c689b7707a9
permissions -rw-r--r--
ENGINE-27: update_identity no longer pays attention to the input identity's fpr, but pulls one from elect_pubkey.
     1 // Windows platform specifica
     2 
     3 #define WIN32_LEAN_AND_MEAN
     4 #ifndef UNICODE
     5 #define UNICODE
     6 #endif
     7 #define _WIN32_WINNT 0x0600
     8 
     9 #include <windows.h>
    10 #define _CRT_RAND_S
    11 #include <stdlib.h>
    12 #include <assert.h>
    13 #include <string.h>
    14 #include <string>
    15 #include <stdexcept>
    16 #include "platform_windows.h"
    17 #include <fcntl.h>
    18 #include <sys\stat.h>
    19 
    20 #ifndef WC_ERR_INVALID_CHARS
    21 #define WC_ERR_INVALID_CHARS      0x00000080  // error for invalid chars
    22 #endif
    23 
    24 using namespace std;
    25 
    26 static string utf8_string(wstring wstr) {
    27     string result;
    28 
    29     if (wstr.length()) {
    30         int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
    31                 wstr.c_str(), -1, NULL, 0, NULL, NULL);
    32         assert(size);
    33         if (size) {
    34             char *buf = new char[size];
    35             WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wstr.c_str(),
    36                     -1, buf, size, NULL, NULL);
    37             result = buf;
    38             delete[] buf;
    39         } else
    40             throw out_of_range("input wstring is not valid"
    41                     " while converting UTF-16 to UTF-8.");
    42     }
    43 
    44     return result;
    45 }
    46 
    47 static wstring utf16_string(string str) {
    48     wstring result;
    49 
    50     if (str.length()) {
    51         int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
    52                 str.c_str(), -1, NULL, 0);
    53         assert(size);
    54         if (size) {
    55             wchar_t * buf = new wchar_t[size];
    56             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), -1,
    57                     buf, size);
    58             result = buf;
    59             delete[] buf;
    60         } else
    61             throw out_of_range("input string is not valid"
    62                     " while converting UTF-8 to UTF-16.");
    63     }
    64 
    65     return result;
    66 }
    67 
    68 static bool readRegistryString(
    69         HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPTSTR lpResult,
    70         DWORD dwSize, LPCTSTR lpDefault
    71     )
    72 {
    73     assert(lpResult);
    74 
    75 	HKEY theKey;
    76 	DWORD type;
    77 	DWORD bytesCopied = dwSize;
    78 	HRESULT result;
    79 
    80 	result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &theKey);
    81 	if (result != ERROR_SUCCESS) {
    82 		if (lpDefault) {
    83 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    84 			return true;
    85 		}
    86 		else
    87 			return false;
    88 	}
    89 
    90 	result = RegQueryValueEx(theKey, lpValueName, NULL, &type,
    91             (LPBYTE) lpResult, &bytesCopied);
    92     if (result != ERROR_SUCCESS || (type != REG_EXPAND_SZ && type != REG_SZ)) {
    93 		if (lpDefault) {
    94 			wcsncpy_s(lpResult, dwSize, lpDefault, _TRUNCATE);
    95 			RegCloseKey(theKey);
    96 			return true;
    97 		}
    98 		else {
    99 			RegCloseKey(theKey);
   100 			return false;
   101 		}
   102 	}
   103 
   104 	RegCloseKey(theKey);
   105 	return true;
   106 }
   107 
   108 static const DWORD PATH_BUF_SIZE = 32768;
   109 
   110 static inline string managementPath(const char *file_path, const char *file_name)
   111 {
   112     string path;
   113 	static TCHAR tPath[PATH_BUF_SIZE];
   114 
   115     DWORD length = ExpandEnvironmentStringsW(utf16_string(file_path).c_str(),
   116             tPath, PATH_BUF_SIZE);
   117 	assert(length);
   118     if (length == 0)
   119         throw bad_alloc(); // BUG: there are other errors possible beside out of memory
   120 
   121 	CreateDirectory(tPath, NULL);
   122 	DWORD error = GetLastError();
   123 
   124 	path = utf8_string(tPath);
   125 	path += "\\";
   126 	path += file_name;
   127 
   128 	return path;
   129 }
   130 
   131 extern "C" {
   132 
   133 void *dlopen(const char *filename, int flag) {
   134 	static TCHAR path[PATH_BUF_SIZE];
   135 
   136     assert(filename);
   137 	assert(flag == RTLD_LAZY); // only lazy binding is implemented
   138 
   139     bool result = readRegistryString(HKEY_LOCAL_MACHINE,
   140             TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   141             PATH_BUF_SIZE, NULL);
   142 	assert(result);
   143 	if (!result)
   144 		return NULL;
   145 
   146     SetDllDirectory(TEXT(""));
   147     BOOL _result = SetDllDirectory(path);
   148     assert(_result != 0);
   149     if (_result == 0)
   150         return NULL;
   151 
   152 	HMODULE module = LoadLibrary(utf16_string(filename).c_str());
   153     SetDllDirectory(NULL);
   154 	if (module == NULL)
   155 		return NULL;
   156 	else
   157 		return (void *) module;
   158 }
   159 
   160 int dlclose(void *handle) {
   161 	if (FreeLibrary((HMODULE) handle))
   162 		return 0;
   163 	else
   164 		return 1;
   165 }
   166 
   167 void *dlsym(void *handle, const char *symbol) {
   168 	return (void *) (intptr_t) GetProcAddress((HMODULE) handle, symbol);
   169 }
   170 
   171 const char *windoze_local_db(void) {
   172 	static string path;
   173 	if (path.length() == 0)
   174         path = managementPath("%LOCALAPPDATA%\\pEp", "management.db");
   175     return path.c_str();
   176 }
   177 
   178 const char *windoze_system_db(void) {
   179 	static string path;
   180 	if (path.length() == 0)
   181 		path = managementPath("%ALLUSERSPROFILE%\\pEp", "system.db");
   182     return path.c_str();
   183 }
   184 
   185 const char *gpg_conf(void)
   186 {
   187     static string path;
   188     if (path.length() == 0)
   189         path = managementPath("%APPDATA%\\gnupg", "gpg.conf");
   190     return path.c_str();
   191 }
   192 
   193 const char *gpg_agent_conf(void)
   194 {
   195     static string agent_path;
   196     if (agent_path.length() == 0)
   197         agent_path = managementPath("%APPDATA%\\gnupg", "gpg-agent.conf");
   198     return agent_path.c_str();
   199 }
   200 
   201 
   202 long random(void)
   203 {
   204     unsigned int r;
   205     errno_t e;
   206 
   207     assert(sizeof(unsigned int) == sizeof(long)); // this is Windoze
   208 
   209     do {
   210         e = rand_s(&r);
   211     } while (e);
   212 
   213     return (long) (r & ((1U<<31)-1));
   214 }
   215 
   216 char *strndup(const char *s1, size_t n)
   217 {
   218     char *str = (char *) calloc(n + 1, 1);
   219     if (str == NULL)
   220         return NULL;
   221 
   222     strncpy(str, s1, n);
   223     return str;
   224 }
   225 
   226 char *stpcpy(char *dst, const char *src)
   227 {
   228     for (;; ++dst, ++src) {
   229         *dst = *src;
   230         if (*dst == 0)
   231             break;
   232     }
   233     return dst;
   234 }
   235 
   236 size_t strlcpy(char* dst, const	char* src, size_t size) {
   237     size_t retval = strlen(src);
   238     size_t size_to_copy = (retval < size ? retval : size - 1);
   239     
   240     // strlcpy doc says src and dst not allowed to overlap, as
   241     // it's undefined. So this is acceptable:
   242     memcpy((void*)dst, (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   243     dst[size_to_copy] = '\0';
   244     return retval;
   245 }
   246 size_t strlcat(char* dst, const	char* src, size_t size) {
   247     size_t start_len = strnlen(dst, size);
   248     if (start_len == size)
   249         return size; // no copy, no null termination in size bytes, according to spec
   250     
   251     size_t add_len = strlen(src);
   252     size_t retval = start_len + add_len;
   253     size_t size_to_copy = (retval < size ? add_len : (size - start_len) - 1);
   254     
   255     // strlcat doc says src and dst not allowed to overlap, as
   256     // it's undefined. So this is acceptable:
   257     memcpy((void*)(dst + start_len), (void*)src, size_to_copy); // no defined error return, but strcpy doesn't either
   258     dst[start_len + size_to_copy] = '\0';
   259     return retval;
   260 }
   261 
   262 int mkstemp(char *templ)
   263 {
   264     char *pathname = _mktemp(templ);
   265     if (errno)
   266         return -1;
   267     return _open(pathname, _O_RDWR | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
   268 }
   269 
   270 } // "C"