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