Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at http://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #ifdef USE_WINDOWS_SSPI
     26 
     27 #include <curl/curl.h>
     28 #include "curl_sspi.h"
     29 #include "curl_multibyte.h"
     30 #include "warnless.h"
     31 
     32 /* The last #include files should be: */
     33 #include "curl_memory.h"
     34 #include "memdebug.h"
     35 
     36 /* We use our own typedef here since some headers might lack these */
     37 typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
     38 
     39 /* See definition of SECURITY_ENTRYPOINT in sspi.h */
     40 #ifdef UNICODE
     41 #  ifdef _WIN32_WCE
     42 #    define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
     43 #  else
     44 #    define SECURITYENTRYPOINT "InitSecurityInterfaceW"
     45 #  endif
     46 #else
     47 #  define SECURITYENTRYPOINT "InitSecurityInterfaceA"
     48 #endif
     49 
     50 /* Handle of security.dll or secur32.dll, depending on Windows version */
     51 HMODULE s_hSecDll = NULL;
     52 
     53 /* Pointer to SSPI dispatch table */
     54 PSecurityFunctionTable s_pSecFn = NULL;
     55 
     56 /*
     57  * Curl_sspi_global_init()
     58  *
     59  * This is used to load the Security Service Provider Interface (SSPI)
     60  * dynamic link library portably across all Windows versions, without
     61  * the need to directly link libcurl, nor the application using it, at
     62  * build time.
     63  *
     64  * Once this function has been executed, Windows SSPI functions can be
     65  * called through the Security Service Provider Interface dispatch table.
     66  */
     67 CURLcode Curl_sspi_global_init(void)
     68 {
     69   bool securityDll = FALSE;
     70   INITSECURITYINTERFACE_FN pInitSecurityInterface;
     71 
     72   /* If security interface is not yet initialized try to do this */
     73   if(!s_hSecDll) {
     74     /* Security Service Provider Interface (SSPI) functions are located in
     75      * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
     76      * have both these DLLs (security.dll forwards calls to secur32.dll) */
     77     DWORD majorVersion = 4;
     78     DWORD platformId = VER_PLATFORM_WIN32_NT;
     79 
     80 #if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
     81     (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
     82     OSVERSIONINFO osver;
     83 
     84     memset(&osver, 0, sizeof(osver));
     85     osver.dwOSVersionInfoSize = sizeof(osver);
     86 
     87     /* Find out Windows version */
     88     if(!GetVersionEx(&osver))
     89       return CURLE_FAILED_INIT;
     90 
     91     /* Verify the major version number == 4 and platform id == WIN_NT */
     92     if(osver.dwMajorVersion == majorVersion &&
     93        osver.dwPlatformId == platformId)
     94       securityDll = TRUE;
     95 #else
     96     ULONGLONG majorVersionMask;
     97     ULONGLONG platformIdMask;
     98     OSVERSIONINFOEX osver;
     99 
    100     memset(&osver, 0, sizeof(osver));
    101     osver.dwOSVersionInfoSize = sizeof(osver);
    102     osver.dwMajorVersion = majorVersion;
    103     osver.dwPlatformId = platformId;
    104     majorVersionMask = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
    105     platformIdMask = VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL);
    106 
    107     /* Verify the major version number == 4 and platform id == WIN_NT */
    108     if(VerifyVersionInfo(&osver, VER_MAJORVERSION, majorVersionMask) &&
    109        VerifyVersionInfo(&osver, VER_PLATFORMID, platformIdMask))
    110       securityDll = TRUE;
    111 #endif
    112 
    113     /* Load SSPI dll into the address space of the calling process */
    114     if(securityDll)
    115       s_hSecDll = LoadLibrary(TEXT("security.dll"));
    116     else
    117       s_hSecDll = LoadLibrary(TEXT("secur32.dll"));
    118     if(!s_hSecDll)
    119       return CURLE_FAILED_INIT;
    120 
    121     /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
    122     pInitSecurityInterface = (INITSECURITYINTERFACE_FN)
    123       GetProcAddress(s_hSecDll, SECURITYENTRYPOINT);
    124     if(!pInitSecurityInterface)
    125       return CURLE_FAILED_INIT;
    126 
    127     /* Get pointer to Security Service Provider Interface dispatch table */
    128     s_pSecFn = pInitSecurityInterface();
    129     if(!s_pSecFn)
    130       return CURLE_FAILED_INIT;
    131   }
    132 
    133   return CURLE_OK;
    134 }
    135 
    136 /*
    137  * Curl_sspi_global_cleanup()
    138  *
    139  * This deinitializes the Security Service Provider Interface from libcurl.
    140  */
    141 
    142 void Curl_sspi_global_cleanup(void)
    143 {
    144   if(s_hSecDll) {
    145     FreeLibrary(s_hSecDll);
    146     s_hSecDll = NULL;
    147     s_pSecFn = NULL;
    148   }
    149 }
    150 
    151 /*
    152  * Curl_create_sspi_identity()
    153  *
    154  * This is used to populate a SSPI identity structure based on the supplied
    155  * username and password.
    156  *
    157  * Parameters:
    158  *
    159  * userp    [in]     - The user name in the format User or Domain\User.
    160  * passdwp  [in]     - The user's password.
    161  * identity [in/out] - The identity structure.
    162  *
    163  * Returns CURLE_OK on success.
    164  */
    165 CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
    166                                    SEC_WINNT_AUTH_IDENTITY *identity)
    167 {
    168   xcharp_u useranddomain;
    169   xcharp_u user, dup_user;
    170   xcharp_u domain, dup_domain;
    171   xcharp_u passwd, dup_passwd;
    172   size_t domlen = 0;
    173 
    174   domain.const_tchar_ptr = TEXT("");
    175 
    176   /* Initialize the identity */
    177   memset(identity, 0, sizeof(*identity));
    178 
    179   useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
    180   if(!useranddomain.tchar_ptr)
    181     return CURLE_OUT_OF_MEMORY;
    182 
    183   user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
    184   if(!user.const_tchar_ptr)
    185     user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
    186 
    187   if(user.tchar_ptr) {
    188     domain.tchar_ptr = useranddomain.tchar_ptr;
    189     domlen = user.tchar_ptr - useranddomain.tchar_ptr;
    190     user.tchar_ptr++;
    191   }
    192   else {
    193     user.tchar_ptr = useranddomain.tchar_ptr;
    194     domain.const_tchar_ptr = TEXT("");
    195     domlen = 0;
    196   }
    197 
    198   /* Setup the identity's user and length */
    199   dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
    200   if(!dup_user.tchar_ptr) {
    201     Curl_unicodefree(useranddomain.tchar_ptr);
    202     return CURLE_OUT_OF_MEMORY;
    203   }
    204   identity->User = dup_user.tbyte_ptr;
    205   identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
    206   dup_user.tchar_ptr = NULL;
    207 
    208   /* Setup the identity's domain and length */
    209   dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
    210   if(!dup_domain.tchar_ptr) {
    211     Curl_unicodefree(useranddomain.tchar_ptr);
    212     return CURLE_OUT_OF_MEMORY;
    213   }
    214   _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
    215   *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
    216   identity->Domain = dup_domain.tbyte_ptr;
    217   identity->DomainLength = curlx_uztoul(domlen);
    218   dup_domain.tchar_ptr = NULL;
    219 
    220   Curl_unicodefree(useranddomain.tchar_ptr);
    221 
    222   /* Setup ntlm identity's password and length */
    223   passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
    224   if(!passwd.tchar_ptr)
    225     return CURLE_OUT_OF_MEMORY;
    226   dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
    227   if(!dup_passwd.tchar_ptr) {
    228     Curl_unicodefree(passwd.tchar_ptr);
    229     return CURLE_OUT_OF_MEMORY;
    230   }
    231   identity->Password = dup_passwd.tbyte_ptr;
    232   identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
    233   dup_passwd.tchar_ptr = NULL;
    234 
    235   Curl_unicodefree(passwd.tchar_ptr);
    236 
    237   /* Setup the identity's flags */
    238   identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY;
    239 
    240   return CURLE_OK;
    241 }
    242 
    243 void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity)
    244 {
    245   if(identity) {
    246     Curl_safefree(identity->User);
    247     Curl_safefree(identity->Password);
    248     Curl_safefree(identity->Domain);
    249   }
    250 }
    251 
    252 #endif /* USE_WINDOWS_SSPI */
    253