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 s_hSecDll = NULL; |
56 | |
57 | /* Pointer to SSPI dispatch table */ |
58 | PSecurityFunctionTable s_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 | */ |
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(!s_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 | s_hSecDll = Curl_load_library(TEXT("security.dll" )); |
90 | else |
91 | s_hSecDll = Curl_load_library(TEXT("secur32.dll" )); |
92 | if(!s_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(s_hSecDll, SECURITYENTRYPOINT))); |
99 | if(!pInitSecurityInterface) |
100 | return CURLE_FAILED_INIT; |
101 | |
102 | /* Get pointer to Security Service Provider Interface dispatch table */ |
103 | s_pSecFn = pInitSecurityInterface(); |
104 | if(!s_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 | */ |
120 | void Curl_sspi_global_cleanup(void) |
121 | { |
122 | if(s_hSecDll) { |
123 | FreeLibrary(s_hSecDll); |
124 | s_hSecDll = NULL; |
125 | s_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 user name 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 | */ |
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 | */ |
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 | |