diff options
author | Heiko Hund <heiko.hund@sophos.com> | 2012-02-10 15:13:42 +0100 |
---|---|---|
committer | David Sommerseth <davids@redhat.com> | 2012-02-13 17:11:50 +0100 |
commit | 71bbbd76c62630c88441237d72fe5b61f0b45b2a (patch) | |
tree | 715f8c8183c6e47bb26f0a10c0f6b14f9b9f83a2 /win32.c | |
parent | 2ee0dc2bd72ec318fcc227af54e5ca7e1384a6cc (diff) | |
download | openvpn-71bbbd76c62630c88441237d72fe5b61f0b45b2a.tar.gz openvpn-71bbbd76c62630c88441237d72fe5b61f0b45b2a.tar.xz openvpn-71bbbd76c62630c88441237d72fe5b61f0b45b2a.zip |
handle Windows unicode paths
Openvpn for Windows is not compiled as a Unicode binary and thus cannot
handle paths which contain non-ASCII characters using the argv vector.
Characters that are not present in the system codepage are simply replaced
with a question mark, e.g. if started as 'openvpn --config домой.ovpn'
the file '?????.ovpn' is tried to be opened as configuration.
The same applies to paths in config files which need to be UTF-8
encoded if they contain non ASCII characters. The option line
'key лев.pem' will lead to openvpn trying to open 'лев.pem' on a
system with codepage 1252.
This patch makes openvpn read the command line in UCS-2 and convert
it to UTF-8 internally. Windows stores names in the filesystem in UCS-2.
When using a paths openvpn converts it from UTF-8 to UCS-2 and uses the
wide character Windows API function.
Signed-off-by: Heiko Hund <heiko.hund@sophos.com>
Acked-by: David Sommerseth <davids@redhat.com>
Signed-off-by: David Sommerseth <davids@redhat.com>
Diffstat (limited to 'win32.c')
-rw-r--r-- | win32.c | 60 |
1 files changed, 48 insertions, 12 deletions
@@ -931,8 +931,8 @@ env_block (const struct env_set *es) return NULL; } -static char * -cmd_line (const struct argv *a) +static WCHAR * +wide_cmd_line (const struct argv *a, struct gc_arena *gc) { size_t nchars = 1; size_t maxlen = 0; @@ -952,9 +952,9 @@ cmd_line (const struct argv *a) maxlen = len; } - work = (char *) malloc (maxlen + 1); + work = gc_malloc (maxlen + 1, false, gc); check_malloc_return (work); - buf = alloc_buf (nchars); + buf = alloc_buf_gc (nchars, gc); for (i = 0; i < a->argc; ++i) { @@ -969,8 +969,7 @@ cmd_line (const struct argv *a) buf_printf (&buf, "\"%s\"", work); } - free (work); - return BSTR(&buf); + return wide_string (BSTR (&buf), gc); } /* @@ -988,23 +987,24 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i { if (script_method == SM_EXECVE) { - STARTUPINFO start_info; + struct gc_arena gc = gc_new (); + STARTUPINFOW start_info; PROCESS_INFORMATION proc_info; char *env = env_block (es); - char *cl = cmd_line (a); - char *cmd = a->argv[0]; + WCHAR *cl = wide_cmd_line (a, &gc); + WCHAR *cmd = wide_string (a->argv[0], &gc); CLEAR (start_info); CLEAR (proc_info); /* fill in STARTUPINFO struct */ - GetStartupInfo(&start_info); + GetStartupInfoW(&start_info); start_info.cb = sizeof(start_info); start_info.dwFlags = STARTF_USESHOWWINDOW; start_info.wShowWindow = SW_HIDE; - if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) + if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) { DWORD exit_status = 0; CloseHandle (proc_info.hThread); @@ -1019,8 +1019,8 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i { msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd); } - free (cl); free (env); + gc_free (&gc); } else if (script_method == SM_SYSTEM) { @@ -1045,6 +1045,42 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i return ret; } +WCHAR * +wide_string (const char* utf8, struct gc_arena *gc) +{ + int n = MultiByteToWideChar (CP_UTF8, 0, utf8, -1, NULL, 0); + WCHAR *ucs16 = gc_malloc (n * sizeof (WCHAR), false, gc); + MultiByteToWideChar (CP_UTF8, 0, utf8, -1, ucs16, n); + return ucs16; +} + +FILE * +openvpn_fopen (const char *path, const char *mode) +{ + struct gc_arena gc = gc_new (); + FILE *f = _wfopen (wide_string (path, &gc), wide_string (mode, &gc)); + gc_free (&gc); + return f; +} + +int +openvpn_open (const char *path, int flags, mode_t mode) +{ + struct gc_arena gc = gc_new (); + int fd = _wopen (wide_string (path, &gc), flags, mode); + gc_free (&gc); + return fd; +} + +int +openvpn_stat (const char *path, struct stat *buf) +{ + struct gc_arena gc = gc_new (); + int res = wstat (wide_string (path, &gc), buf); + gc_free (&gc); + return res; +} + /* * call ourself in another process */ |