1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2015, 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 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 */
Curl_sspi_global_init(void)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
Curl_sspi_global_cleanup(void)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 */
Curl_create_sspi_identity(const char * userp,const char * passwdp,SEC_WINNT_AUTH_IDENTITY * identity)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
Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY * identity)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