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