xref: /curl/lib/curl_sspi.c (revision bca9c771)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@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 https://curl.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #ifdef USE_WINDOWS_SSPI
28 
29 #include <curl/curl.h>
30 #include "curl_sspi.h"
31 #include "curl_multibyte.h"
32 #include "system_win32.h"
33 #include "version_win32.h"
34 #include "warnless.h"
35 
36 /* The last #include files should be: */
37 #include "curl_memory.h"
38 #include "memdebug.h"
39 
40 /* We use our own typedef here since some headers might lack these */
41 typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
42 
43 /* See definition of SECURITY_ENTRYPOINT in sspi.h */
44 #ifdef UNICODE
45 #  ifdef _WIN32_WCE
46 #    define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
47 #  else
48 #    define SECURITYENTRYPOINT "InitSecurityInterfaceW"
49 #  endif
50 #else
51 #  define SECURITYENTRYPOINT "InitSecurityInterfaceA"
52 #endif
53 
54 /* Handle of security.dll or secur32.dll, depending on Windows version */
55 HMODULE Curl_hSecDll = NULL;
56 
57 /* Pointer to SSPI dispatch table */
58 PSecurityFunctionTable Curl_pSecFn = NULL;
59 
60 /*
61  * Curl_sspi_global_init()
62  *
63  * This is used to load the Security Service Provider Interface (SSPI)
64  * dynamic link library portably across all Windows versions, without
65  * the need to directly link libcurl, nor the application using it, at
66  * build time.
67  *
68  * Once this function has been executed, Windows SSPI functions can be
69  * called through the Security Service Provider Interface dispatch table.
70  *
71  * Parameters:
72  *
73  * None.
74  *
75  * Returns CURLE_OK on success.
76  */
Curl_sspi_global_init(void)77 CURLcode Curl_sspi_global_init(void)
78 {
79   INITSECURITYINTERFACE_FN pInitSecurityInterface;
80 
81   /* If security interface is not yet initialized try to do this */
82   if(!Curl_hSecDll) {
83     /* Security Service Provider Interface (SSPI) functions are located in
84      * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
85      * have both these DLLs (security.dll forwards calls to secur32.dll) */
86 
87     /* Load SSPI dll into the address space of the calling process */
88     if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
89       Curl_hSecDll = Curl_load_library(TEXT("security.dll"));
90     else
91       Curl_hSecDll = Curl_load_library(TEXT("secur32.dll"));
92     if(!Curl_hSecDll)
93       return CURLE_FAILED_INIT;
94 
95     /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
96     pInitSecurityInterface =
97       CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
98                           (GetProcAddress(Curl_hSecDll, SECURITYENTRYPOINT)));
99     if(!pInitSecurityInterface)
100       return CURLE_FAILED_INIT;
101 
102     /* Get pointer to Security Service Provider Interface dispatch table */
103     Curl_pSecFn = pInitSecurityInterface();
104     if(!Curl_pSecFn)
105       return CURLE_FAILED_INIT;
106   }
107 
108   return CURLE_OK;
109 }
110 
111 /*
112  * Curl_sspi_global_cleanup()
113  *
114  * This deinitializes the Security Service Provider Interface from libcurl.
115  *
116  * Parameters:
117  *
118  * None.
119  */
Curl_sspi_global_cleanup(void)120 void Curl_sspi_global_cleanup(void)
121 {
122   if(Curl_hSecDll) {
123     FreeLibrary(Curl_hSecDll);
124     Curl_hSecDll = NULL;
125     Curl_pSecFn = NULL;
126   }
127 }
128 
129 /*
130  * Curl_create_sspi_identity()
131  *
132  * This is used to populate a SSPI identity structure based on the supplied
133  * username and password.
134  *
135  * Parameters:
136  *
137  * userp    [in]     - The username in the format User or Domain\User.
138  * passwdp  [in]     - The user's password.
139  * identity [in/out] - The identity structure.
140  *
141  * Returns CURLE_OK on success.
142  */
Curl_create_sspi_identity(const char * userp,const char * passwdp,SEC_WINNT_AUTH_IDENTITY * identity)143 CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
144                                    SEC_WINNT_AUTH_IDENTITY *identity)
145 {
146   xcharp_u useranddomain;
147   xcharp_u user, dup_user;
148   xcharp_u domain, dup_domain;
149   xcharp_u passwd, dup_passwd;
150   size_t domlen = 0;
151 
152   domain.const_tchar_ptr = TEXT("");
153 
154   /* Initialize the identity */
155   memset(identity, 0, sizeof(*identity));
156 
157   useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)userp);
158   if(!useranddomain.tchar_ptr)
159     return CURLE_OUT_OF_MEMORY;
160 
161   user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
162   if(!user.const_tchar_ptr)
163     user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
164 
165   if(user.tchar_ptr) {
166     domain.tchar_ptr = useranddomain.tchar_ptr;
167     domlen = user.tchar_ptr - useranddomain.tchar_ptr;
168     user.tchar_ptr++;
169   }
170   else {
171     user.tchar_ptr = useranddomain.tchar_ptr;
172     domain.const_tchar_ptr = TEXT("");
173     domlen = 0;
174   }
175 
176   /* Setup the identity's user and length */
177   dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
178   if(!dup_user.tchar_ptr) {
179     curlx_unicodefree(useranddomain.tchar_ptr);
180     return CURLE_OUT_OF_MEMORY;
181   }
182   identity->User = dup_user.tbyte_ptr;
183   identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
184   dup_user.tchar_ptr = NULL;
185 
186   /* Setup the identity's domain and length */
187   dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
188   if(!dup_domain.tchar_ptr) {
189     curlx_unicodefree(useranddomain.tchar_ptr);
190     return CURLE_OUT_OF_MEMORY;
191   }
192   _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
193   *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
194   identity->Domain = dup_domain.tbyte_ptr;
195   identity->DomainLength = curlx_uztoul(domlen);
196   dup_domain.tchar_ptr = NULL;
197 
198   curlx_unicodefree(useranddomain.tchar_ptr);
199 
200   /* Setup the identity's password and length */
201   passwd.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)passwdp);
202   if(!passwd.tchar_ptr)
203     return CURLE_OUT_OF_MEMORY;
204   dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
205   if(!dup_passwd.tchar_ptr) {
206     curlx_unicodefree(passwd.tchar_ptr);
207     return CURLE_OUT_OF_MEMORY;
208   }
209   identity->Password = dup_passwd.tbyte_ptr;
210   identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
211   dup_passwd.tchar_ptr = NULL;
212 
213   curlx_unicodefree(passwd.tchar_ptr);
214 
215   /* Setup the identity's flags */
216   identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY;
217 
218   return CURLE_OK;
219 }
220 
221 /*
222  * Curl_sspi_free_identity()
223  *
224  * This is used to free the contents of a SSPI identifier structure.
225  *
226  * Parameters:
227  *
228  * identity [in/out] - The identity structure.
229  */
Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY * identity)230 void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity)
231 {
232   if(identity) {
233     Curl_safefree(identity->User);
234     Curl_safefree(identity->Password);
235     Curl_safefree(identity->Domain);
236   }
237 }
238 
239 #endif /* USE_WINDOWS_SSPI */
240