From 62c3863278db954b524b367b6e8bc66c0f9f62b5 Mon Sep 17 00:00:00 2001
From: Mark Salisbury <mark.salisbury@hp.com>
Date: Wed, 13 Jun 2012 11:16:35 -0600
Subject: [PATCH 1/8] SSPI related code: Unicode support for WinCE

SSPI related code now compiles with ANSI and WCHAR versions of security
methods (WinCE requires WCHAR versions of methods).

setup.h, idn_win32.c, win32_multibyte.c - pulled UTF8 to WCHAR
conversion methods out of idn_win32.c into their own file, added
USE_WINDOWS_MULTIBYTE_CONVERSION #define to compile these methods.
---
 lib/curl_ntlm_msgs.c      |   61 ++++++++++++++++++++---------------
 lib/curl_schannel.c       |   48 +++++++++++++++++++++++++---
 lib/curl_sspi.c           |   25 ++++++++++----
 lib/curl_sspi.h           |    2 +-
 lib/getenv.c              |    2 +-
 lib/http_negotiate_sspi.c |   26 +++++++++++++--
 lib/idn_win32.c           |   49 +----------------------------
 lib/setup.h               |    9 +++++
 lib/socks_sspi.c          |   76 ++++++++++++++++++++++++++------------------
 lib/strerror.c            |    4 +-
 lib/telnet.c              |    2 +-
 lib/win32_multibyte.c     |   75 ++++++++++++++++++++++++++++++++++++++++++++
 lib/win32_multibyte.h     |   33 +++++++++++++++++++
 13 files changed, 286 insertions(+), 126 deletions(-)
 create mode 100644 lib/win32_multibyte.c
 create mode 100644 lib/win32_multibyte.h

diff --git a/lib/curl_ntlm_msgs.c b/lib/curl_ntlm_msgs.c
index 5789a24..2a0abf4 100644
--- a/lib/curl_ntlm_msgs.c
+++ b/lib/curl_ntlm_msgs.c
@@ -79,6 +79,9 @@
 
 #elif defined(USE_WINDOWS_SSPI)
 #  include "curl_sspi.h"
+#if defined(UNICODE)
+#  include "win32_multibyte.h"
+#endif
 #else
 #  error "Can't compile NTLM support without a crypto library."
 #endif
@@ -394,7 +397,6 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp,
   SecBufferDesc desc;
   SECURITY_STATUS status;
   ULONG attrs;
-  const char *dest = "";
   const char *user;
   const char *domain = "";
   size_t userlen = 0;
@@ -431,11 +433,19 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp,
      */
     ntlm->p_identity = &ntlm->identity;
     memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
+#ifdef UNICODE
+    if ((ntlm->identity.User = _curl_win32_UTF8_to_wchar(user)) == NULL)
+#else
     if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
+#endif
       return CURLE_OUT_OF_MEMORY;
 
     ntlm->identity.UserLength = (unsigned long)userlen;
+#ifdef UNICODE
+    if((ntlm->identity.Password = _curl_win32_UTF8_to_wchar(passwdp)) == NULL)
+#else
     if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
+#endif
       return CURLE_OUT_OF_MEMORY;
 
     ntlm->identity.PasswordLength = (unsigned long)passwdlen;
@@ -450,10 +460,10 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp,
   else
     ntlm->p_identity = NULL;
 
-  status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM",
-                                               SECPKG_CRED_OUTBOUND, NULL,
-                                               ntlm->p_identity, NULL, NULL,
-                                               &ntlm->handle, &tsDummy);
+  status = s_pSecFn->AcquireCredentialsHandle(NULL, TEXT("NTLM"),
+                                              SECPKG_CRED_OUTBOUND, NULL,
+                                              ntlm->p_identity, NULL, NULL,
+                                              &ntlm->handle, &tsDummy);
   if(status != SEC_E_OK)
     return CURLE_OUT_OF_MEMORY;
 
@@ -464,15 +474,15 @@ CURLcode Curl_ntlm_create_type1_message(const char *userp,
   buf.BufferType = SECBUFFER_TOKEN;
   buf.pvBuffer   = ntlmbuf;
 
-  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
-                                                (void *)dest,
-                                                ISC_REQ_CONFIDENTIALITY |
-                                                ISC_REQ_REPLAY_DETECT |
-                                                ISC_REQ_CONNECTION,
-                                                0, SECURITY_NETWORK_DREP,
-                                                NULL, 0,
-                                                &ntlm->c_handle, &desc,
-                                                &attrs, &tsDummy);
+  status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
+                                               TEXT(""),
+                                               ISC_REQ_CONFIDENTIALITY |
+                                               ISC_REQ_REPLAY_DETECT |
+                                               ISC_REQ_CONNECTION,
+                                               0, SECURITY_NETWORK_DREP,
+                                               NULL, 0,
+                                               &ntlm->c_handle, &desc,
+                                               &attrs, &tsDummy);
 
   if(status == SEC_I_COMPLETE_AND_CONTINUE ||
      status == SEC_I_CONTINUE_NEEDED)
@@ -615,7 +625,6 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
   size_t size;
 
 #ifdef USE_WINDOWS_SSPI
-  const char *dest = "";
   SecBuffer type_2;
   SecBuffer type_3;
   SecBufferDesc type_2_desc;
@@ -640,17 +649,17 @@ CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
   type_3.pvBuffer   = ntlmbuf;
   type_3.cbBuffer   = NTLM_BUFSIZE;
 
-  status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle,
-                                                &ntlm->c_handle,
-                                                (void *)dest,
-                                                ISC_REQ_CONFIDENTIALITY |
-                                                ISC_REQ_REPLAY_DETECT |
-                                                ISC_REQ_CONNECTION,
-                                                0, SECURITY_NETWORK_DREP,
-                                                &type_2_desc,
-                                                0, &ntlm->c_handle,
-                                                &type_3_desc,
-                                                &attrs, &tsDummy);
+  status = s_pSecFn->InitializeSecurityContext(&ntlm->handle,
+                                               &ntlm->c_handle,
+                                               TEXT(""),
+                                               ISC_REQ_CONFIDENTIALITY |
+                                               ISC_REQ_REPLAY_DETECT |
+                                               ISC_REQ_CONNECTION,
+                                               0, SECURITY_NETWORK_DREP,
+                                               &type_2_desc,
+                                               0, &ntlm->c_handle,
+                                               &type_3_desc,
+                                               &attrs, &tsDummy);
   if(status != SEC_E_OK)
     return CURLE_RECV_ERROR;
 
diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 0f49e8d..3e06dc2 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -71,6 +71,9 @@
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
+#if defined(UNICODE)
+#include "win32_multibyte.h"
+#endif
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -98,6 +101,9 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 #ifdef ENABLE_IPV6
   struct in6_addr addr6;
 #endif
+#ifdef UNICODE
+  wchar_t * whost;
+#endif
 
   infof(data, "schannel: connecting to %s:%d (step 1/3)\n",
         conn->host.name, conn->remote_port);
@@ -166,7 +172,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
         failf(data, "schannel: SNI or certificate check failed: %s\n",
               Curl_sspi_strerror(conn, sspi_status));
       else
-        failf(data, "schannel: AcquireCredentialsHandleA failed: %s\n",
+        failf(data, "schannel: AcquireCredentialsHandle failed: %s\n",
               Curl_sspi_strerror(conn, sspi_status));
       free(connssl->cred);
       connssl->cred = NULL;
@@ -197,17 +203,31 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
   memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
 
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
+#ifdef UNICODE
+  whost = _curl_win32_UTF8_to_wchar(conn->host.name);
+  if (whost == NULL)
+    return CURLE_OUT_OF_MEMORY;
+#endif
   sspi_status = s_pSecFn->InitializeSecurityContext(
-    &connssl->cred->cred_handle, NULL, conn->host.name,
+    &connssl->cred->cred_handle, NULL, 
+#ifdef UNICODE
+    whost,
+#else
+    conn->host.name,
+#endif
     connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle,
     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
 
+#ifdef UNICODE
+  free(whost);
+#endif
+
   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
       failf(data, "schannel: SNI or certificate check failed: %s\n",
             Curl_sspi_strerror(conn, sspi_status));
     else
-      failf(data, "schannel: initial InitializeSecurityContextA failed: %s\n",
+      failf(data, "schannel: initial InitializeSecurityContext failed: %s\n",
             Curl_sspi_strerror(conn, sspi_status));
     free(connssl->ctxt);
     connssl->ctxt = NULL;
@@ -246,6 +266,9 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
   SecBuffer inbuf[2];
   SecBufferDesc inbuf_desc;
   SECURITY_STATUS sspi_status = SEC_E_OK;
+#ifdef UNICODE
+  wchar_t * whost;
+#endif
 
   infof(data, "schannel: connecting to %s:%d (step 2/3)\n",
         conn->host.name, conn->remote_port);
@@ -319,12 +342,27 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
   /* copy received handshake data into input buffer */
   memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, connssl->encdata_offset);
 
+#ifdef UNICODE
+  whost = _curl_win32_UTF8_to_wchar(conn->host.name);
+  if (whost == NULL)
+    return CURLE_OUT_OF_MEMORY;
+#endif
+
   /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
   sspi_status = s_pSecFn->InitializeSecurityContext(
     &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
-    conn->host.name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
+#ifdef UNICODE
+    whost,
+#else
+    conn->host.name,
+#endif
+    connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
 
+#ifdef UNICODE
+  free(whost);
+#endif
+
   /* free buffer for received handshake data */
   free(inbuf[0].pvBuffer);
 
@@ -364,7 +402,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
       failf(data, "schannel: SNI or certificate check failed: %s\n",
             Curl_sspi_strerror(conn, sspi_status));
     else
-      failf(data, "schannel: next InitializeSecurityContextA failed: %s\n",
+      failf(data, "schannel: next InitializeSecurityContext failed: %s\n",
             Curl_sspi_strerror(conn, sspi_status));
     return CURLE_SSL_CONNECT_ERROR;
   }
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index cb83809..539a0e4 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -36,13 +36,24 @@
 #include "memdebug.h"
 
 /* We use our own typedef here since some headers might lack these */
-typedef PSecurityFunctionTableA (APIENTRY *INITSECURITYINTERFACE_FN_A)(VOID);
+typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
+
+/* See definition of SECURITY_ENTRYPOINT in sspi.h */
+#ifdef UNICODE
+#ifdef _WIN32_WCE
+#define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
+#else
+#define SECURITYENTRYPOINT "InitSecurityInterfaceW"
+#endif
+#else
+#define SECURITYENTRYPOINT "InitSecurityInterfaceA"
+#endif
 
 /* Handle of security.dll or secur32.dll, depending on Windows version */
 HMODULE s_hSecDll = NULL;
 
 /* Pointer to SSPI dispatch table */
-PSecurityFunctionTableA s_pSecFn = NULL;
+PSecurityFunctionTable s_pSecFn = NULL;
 
 /*
  * Curl_sspi_global_init()
@@ -58,7 +69,7 @@ PSecurityFunctionTableA s_pSecFn = NULL;
 CURLcode Curl_sspi_global_init(void)
 {
   OSVERSIONINFO osver;
-  INITSECURITYINTERFACE_FN_A pInitSecurityInterface;
+  INITSECURITYINTERFACE_FN pInitSecurityInterface;
 
   /* If security interface is not yet initialized try to do this */
   if(!s_hSecDll) {
@@ -76,15 +87,15 @@ CURLcode Curl_sspi_global_init(void)
     /* Load SSPI dll into the address space of the calling process */
     if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT
       && osver.dwMajorVersion == 4)
-      s_hSecDll = LoadLibrary("security.dll");
+      s_hSecDll = LoadLibrary(TEXT("security.dll"));
     else
-      s_hSecDll = LoadLibrary("secur32.dll");
+      s_hSecDll = LoadLibrary(TEXT("secur32.dll"));
     if(!s_hSecDll)
       return CURLE_FAILED_INIT;
 
     /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
-    pInitSecurityInterface = (INITSECURITYINTERFACE_FN_A)
-      GetProcAddress(s_hSecDll, "InitSecurityInterfaceA");
+    pInitSecurityInterface = (INITSECURITYINTERFACE_FN)
+      GetProcAddress(s_hSecDll, SECURITYENTRYPOINT);
     if(!pInitSecurityInterface)
       return CURLE_FAILED_INIT;
 
diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h
index 4e7d4cf..c3e6d97 100644
--- a/lib/curl_sspi.h
+++ b/lib/curl_sspi.h
@@ -46,7 +46,7 @@ void Curl_sspi_global_cleanup(void);
 /* Forward-declaration of global variables defined in curl_sspi.c */
 
 extern HMODULE s_hSecDll;
-extern PSecurityFunctionTableA s_pSecFn;
+extern PSecurityFunctionTable s_pSecFn;
 
 /* Provide some definitions missing in old headers */
 
diff --git a/lib/getenv.c b/lib/getenv.c
index 6b40dd6..efa21e4 100644
--- a/lib/getenv.c
+++ b/lib/getenv.c
@@ -42,7 +42,7 @@ char *GetEnv(const char *variable)
   char *temp = getenv(variable);
   env[0] = '\0';
   if(temp != NULL)
-    ExpandEnvironmentStrings(temp, env, sizeof(env));
+    ExpandEnvironmentStringsA(temp, env, sizeof(env));
   return (env[0] != '\0')?strdup(env):NULL;
 #else
   char *env = getenv(variable);
diff --git a/lib/http_negotiate_sspi.c b/lib/http_negotiate_sspi.c
index f1ab33d..6dc8f15 100644
--- a/lib/http_negotiate_sspi.c
+++ b/lib/http_negotiate_sspi.c
@@ -36,7 +36,9 @@
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
-
+#if defined(UNICODE)
+#include "win32_multibyte.h"
+#endif
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -90,7 +92,9 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
   SecBuffer         in_sec_buff;
   ULONG             context_attributes;
   TimeStamp         lifetime;
-
+#ifdef UNICODE
+  wchar_t *         wserver;
+#endif
   int ret;
   size_t len = 0, input_token_len = 0;
   bool gss = FALSE;
@@ -137,7 +141,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
 
   if(!neg_ctx->output_token) {
     PSecPkgInfo SecurityPackage;
-    ret = s_pSecFn->QuerySecurityPackageInfo((SEC_CHAR *)"Negotiate",
+    ret = s_pSecFn->QuerySecurityPackageInfo(TEXT("Negotiate"),
                                              &SecurityPackage);
     if(ret != SEC_E_OK)
       return -1;
@@ -166,7 +170,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
       return -1;
 
     neg_ctx->status =
-      s_pSecFn->AcquireCredentialsHandle(NULL, (SEC_CHAR *)"Negotiate",
+      s_pSecFn->AcquireCredentialsHandle(NULL, TEXT("Negotiate"),
                                          SECPKG_CRED_OUTBOUND, NULL, NULL,
                                          NULL, NULL, neg_ctx->credentials,
                                          &lifetime);
@@ -205,10 +209,20 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
     in_sec_buff.pvBuffer   = input_token;
   }
 
+#ifdef UNICODE
+  wserver = _curl_win32_UTF8_to_wchar(neg_ctx->server_name);
+  if (!wserver)
+    return CURLE_OUT_OF_MEMORY;
+#endif
+
   neg_ctx->status = s_pSecFn->InitializeSecurityContext(
     neg_ctx->credentials,
     input_token ? neg_ctx->context : 0,
+#ifdef UNICODE
+    wserver,
+#else
     neg_ctx->server_name,
+#endif
     ISC_REQ_CONFIDENTIALITY,
     0,
     SECURITY_NATIVE_DREP,
@@ -219,6 +233,10 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy,
     &context_attributes,
     &lifetime);
 
+#ifdef UNICODE
+  free(wserver);
+#endif
+
   if(GSS_ERROR(neg_ctx->status))
     return -1;
 
diff --git a/lib/idn_win32.c b/lib/idn_win32.c
index 70286c0..a451917 100644
--- a/lib/idn_win32.c
+++ b/lib/idn_win32.c
@@ -29,6 +29,7 @@
 #ifdef USE_WIN32_IDN
 
 #include <tchar.h>
+#include "win32_multibyte.h"
 
 #ifdef WANT_IDN_PROTOTYPES
 WINBASEAPI int WINAPI IdnToAscii(DWORD, LPCWSTR, int, LPWSTR, int);
@@ -37,54 +38,6 @@ WINBASEAPI int WINAPI IdnToUnicode(DWORD, LPCWSTR, int, LPWSTR, int);
 
 #define IDN_MAX_LENGTH 255
 
-static wchar_t *_curl_win32_UTF8_to_wchar(const char *str_utf8)
-{
-  wchar_t *str_w = NULL;
-
-  if(str_utf8) {
-    int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
-                                        str_utf8, -1, NULL, 0);
-    if(str_w_len) {
-      str_w = malloc(str_w_len * sizeof(wchar_t));
-      if(str_w) {
-        if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
-                                str_w_len) == 0) {
-          free(str_w);
-          str_w = NULL;
-        }
-      }
-    }
-  }
-
-  return str_w;
-}
-
-static const char *_curl_win32_wchar_to_UTF8(const wchar_t *str_w)
-{
-  char *str_utf8 = NULL;
-
-  if(str_w) {
-    size_t str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL,
-                                              0, NULL, NULL);
-    if(str_utf8_len) {
-      str_utf8 = malloc(str_utf8_len * sizeof(wchar_t));
-      if(str_utf8) {
-        if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len,
-                                NULL, FALSE) == 0) {
-          (void) GetLastError();
-          free((void *)str_utf8);
-          str_utf8 = NULL;
-        }
-      }
-    }
-    else {
-      (void) GetLastError();
-    }
-  }
-
-  return str_utf8;
-}
-
 int curl_win32_idn_to_ascii(const char *in, char **out)
 {
   wchar_t *in_w = _curl_win32_UTF8_to_wchar(in);
diff --git a/lib/setup.h b/lib/setup.h
index a219080..8bb9bed 100644
--- a/lib/setup.h
+++ b/lib/setup.h
@@ -595,6 +595,15 @@ int netware_init(void);
 #endif
 #endif
 
+/* libcurl uses ANSI c strings; Windows generally has
+   ANSI and wide char equivalent functions.  Exceptions require
+   conversion routines between wide and ANSI strings.
+   Exceptions: IDN API, WinCE
+*/
+#if defined(USE_WIN32_IDN) || ((defined(_W32_WINCE) || defined(UNICODE)) && defined(USE_WINDOWS_SSPI))
+#define USE_WINDOWS_MULTIBYTE_CONVERSION
+#endif
+
 /* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
 #if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
 #define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c
index 0b86bbf..aae4500 100644
--- a/lib/socks_sspi.c
+++ b/lib/socks_sspi.c
@@ -36,7 +36,9 @@
 
 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
 #include <curl/mprintf.h>
-
+#if defined(UNICODE)
+#include "win32_multibyte.h"
+#endif
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -139,17 +141,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   cred_handle.dwLower = 0;
   cred_handle.dwUpper = 0;
 
-  status = s_pSecFn->AcquireCredentialsHandleA(NULL,
-                                               (char *)"Kerberos",
-                                               SECPKG_CRED_OUTBOUND,
-                                               NULL,
-                                               NULL,
-                                               NULL,
-                                               NULL,
-                                               &cred_handle,
-                                               &expiry);
-
-  if(check_sspi_err(conn, status, "AcquireCredentialsHandleA")) {
+  status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                              TEXT("Kerberos"),
+                                              SECPKG_CRED_OUTBOUND,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              &cred_handle,
+                                              &expiry);
+
+  if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) {
     failf(data, "Failed to acquire credentials.");
     Curl_safefree(service_name);
     s_pSecFn->FreeCredentialsHandle(&cred_handle);
@@ -159,22 +161,34 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   /* As long as we need to keep sending some context info, and there's no  */
   /* errors, keep sending it...                                            */
   for(;;) {
-
-    status = s_pSecFn->InitializeSecurityContextA(&cred_handle,
-                                                  context_handle,
-                                                  service_name,
-                                                  ISC_REQ_MUTUAL_AUTH |
-                                                  ISC_REQ_ALLOCATE_MEMORY |
-                                                  ISC_REQ_CONFIDENTIALITY |
-                                                  ISC_REQ_REPLAY_DETECT,
-                                                  0,
-                                                  SECURITY_NATIVE_DREP,
-                                                  &input_desc,
-                                                  0,
-                                                  &sspi_context,
-                                                  &output_desc,
-                                                  &sspi_ret_flags,
-                                                  &expiry);
+    LPTSTR sname;
+#ifdef UNICODE
+    sname = _curl_win32_UTF8_to_wchar(service_name);
+    if (!sname)
+      return CURLE_OUT_OF_MEMORY;
+#else
+    sname = service_name;
+#endif
+    status = s_pSecFn->InitializeSecurityContext(
+                                    &cred_handle,
+                                    context_handle,
+                                    sname,
+                                    ISC_REQ_MUTUAL_AUTH |
+                                    ISC_REQ_ALLOCATE_MEMORY |
+                                    ISC_REQ_CONFIDENTIALITY |
+                                    ISC_REQ_REPLAY_DETECT,
+                                    0,
+                                    SECURITY_NATIVE_DREP,
+                                    &input_desc,
+                                    0,
+                                    &sspi_context,
+                                    &output_desc,
+                                    &sspi_ret_flags,
+                                    &expiry);
+
+#ifdef UNICODE
+    free(sname);
+#endif
 
     if(sspi_recv_token.pvBuffer) {
       s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
@@ -182,7 +196,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       sspi_recv_token.cbBuffer = 0;
     }
 
-    if(check_sspi_err(conn, status, "InitializeSecurityContextA")) {
+    if(check_sspi_err(conn, status, "InitializeSecurityContext")) {
       Curl_safefree(service_name);
       s_pSecFn->FreeCredentialsHandle(&cred_handle);
       s_pSecFn->DeleteSecurityContext(&sspi_context);
@@ -365,10 +379,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     memcpy(socksreq+2, &us_length, sizeof(short));
   }
   else {
-    status = s_pSecFn->QueryContextAttributesA(&sspi_context,
+    status = s_pSecFn->QueryContextAttributes( &sspi_context,
                                                SECPKG_ATTR_SIZES,
                                                &sspi_sizes);
-    if(check_sspi_err(conn, status, "QueryContextAttributesA")) {
+    if(check_sspi_err(conn, status, "QueryContextAttributes")) {
       s_pSecFn->DeleteSecurityContext(&sspi_context);
       failf(data, "Failed to query security context attributes.");
       return CURLE_COULDNT_CONNECT;
diff --git a/lib/strerror.c b/lib/strerror.c
index 84a9000..8690b84 100644
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -635,8 +635,8 @@ const char *Curl_strerror(struct connectdata *conn, int err)
     strncpy(buf, strerror(err), max);
   else {
     if(!get_winsock_error(err, buf, max) &&
-        !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
-                       LANG_NEUTRAL, buf, (DWORD)max, NULL))
+        !FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+                        LANG_NEUTRAL, buf, (DWORD)max, NULL))
       snprintf(buf, max, "Unknown error %d (%#x)", err, err);
   }
 #endif
diff --git a/lib/telnet.c b/lib/telnet.c
index 26fa3ac..1c294e2 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -1341,7 +1341,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
 
   /* OK, so we have WinSock 2.0.  We need to dynamically */
   /* load ws2_32.dll and get the function pointers we need. */
-  wsock2 = LoadLibrary("WS2_32.DLL");
+  wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
   if(wsock2 == NULL) {
     failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
     return CURLE_FAILED_INIT;
diff --git a/lib/win32_multibyte.c b/lib/win32_multibyte.c
new file mode 100644
index 0000000..7891151
--- /dev/null
+++ b/lib/win32_multibyte.c
@@ -0,0 +1,75 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifdef USE_WINDOWS_MULTIBYTE_CONVERSION
+
+wchar_t *_curl_win32_UTF8_to_wchar(const char *str_utf8)
+{
+  wchar_t *str_w = NULL;
+
+  if(str_utf8) {
+    int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+                                        str_utf8, -1, NULL, 0);
+    if(str_w_len) {
+      str_w = malloc(str_w_len * sizeof(wchar_t));
+      if(str_w) {
+        if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
+                                str_w_len) == 0) {
+          free(str_w);
+          str_w = NULL;
+        }
+      }
+    }
+  }
+
+  return str_w;
+}
+
+const char *_curl_win32_wchar_to_UTF8(const wchar_t *str_w)
+{
+  char *str_utf8 = NULL;
+
+  if(str_w) {
+    size_t str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL,
+                                              0, NULL, NULL);
+    if(str_utf8_len) {
+      str_utf8 = malloc(str_utf8_len * sizeof(wchar_t));
+      if(str_utf8) {
+        if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len,
+                                NULL, FALSE) == 0) {
+          (void) GetLastError();
+          free((void *)str_utf8);
+          str_utf8 = NULL;
+        }
+      }
+    }
+    else {
+      (void) GetLastError();
+    }
+  }
+
+  return str_utf8;
+}
+
+#endif
diff --git a/lib/win32_multibyte.h b/lib/win32_multibyte.h
new file mode 100644
index 0000000..294ec57
--- /dev/null
+++ b/lib/win32_multibyte.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+// Generally Windows has ANSI and UNICODE versions of methods defined,
+// but when compiling on WinCE only wide character versions are available.
+
+#if defined(USE_WINDOWS_MULTIBYTE_CONVERSION)
+
+wchar_t *_curl_win32_UTF8_to_wchar(const char *str_utf8);
+const char *_curl_win32_wchar_to_UTF8(const wchar_t *str_w);
+
+#endif
-- 
1.7.4.msysgit.0

