Annotation of embedaddon/curl/lib/vauth/ntlm_sspi.c, revision 1.1.1.1
1.1 misho 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: #if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM)
26:
27: #include <curl/curl.h>
28:
29: #include "vauth/vauth.h"
30: #include "urldata.h"
31: #include "curl_base64.h"
32: #include "curl_ntlm_core.h"
33: #include "warnless.h"
34: #include "curl_multibyte.h"
35: #include "sendf.h"
36:
37: /* The last #include files should be: */
38: #include "curl_memory.h"
39: #include "memdebug.h"
40:
41: /*
42: * Curl_auth_is_ntlm_supported()
43: *
44: * This is used to evaluate if NTLM is supported.
45: *
46: * Parameters: None
47: *
48: * Returns TRUE if NTLM is supported by Windows SSPI.
49: */
50: bool Curl_auth_is_ntlm_supported(void)
51: {
52: PSecPkgInfo SecurityPackage;
53: SECURITY_STATUS status;
54:
55: /* Query the security package for NTLM */
56: status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
57: &SecurityPackage);
58:
59: /* Release the package buffer as it is not required anymore */
60: if(status == SEC_E_OK) {
61: s_pSecFn->FreeContextBuffer(SecurityPackage);
62: }
63:
64: return (status == SEC_E_OK ? TRUE : FALSE);
65: }
66:
67: /*
68: * Curl_auth_create_ntlm_type1_message()
69: *
70: * This is used to generate an already encoded NTLM type-1 message ready for
71: * sending to the recipient.
72: *
73: * Parameters:
74: *
75: * data [in] - The session handle.
76: * userp [in] - The user name in the format User or Domain\User.
77: * passwdp [in] - The user's password.
78: * service [in] - The service type such as http, smtp, pop or imap.
79: * host [in] - The host name.
80: * ntlm [in/out] - The NTLM data struct being used and modified.
81: * outptr [in/out] - The address where a pointer to newly allocated memory
82: * holding the result will be stored upon completion.
83: * outlen [out] - The length of the output message.
84: *
85: * Returns CURLE_OK on success.
86: */
87: CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
88: const char *userp,
89: const char *passwdp,
90: const char *service,
91: const char *host,
92: struct ntlmdata *ntlm,
93: char **outptr, size_t *outlen)
94: {
95: PSecPkgInfo SecurityPackage;
96: SecBuffer type_1_buf;
97: SecBufferDesc type_1_desc;
98: SECURITY_STATUS status;
99: unsigned long attrs;
100: TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
101:
102: /* Clean up any former leftovers and initialise to defaults */
103: Curl_auth_cleanup_ntlm(ntlm);
104:
105: /* Query the security package for NTLM */
106: status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
107: &SecurityPackage);
108: if(status != SEC_E_OK)
109: return CURLE_NOT_BUILT_IN;
110:
111: ntlm->token_max = SecurityPackage->cbMaxToken;
112:
113: /* Release the package buffer as it is not required anymore */
114: s_pSecFn->FreeContextBuffer(SecurityPackage);
115:
116: /* Allocate our output buffer */
117: ntlm->output_token = malloc(ntlm->token_max);
118: if(!ntlm->output_token)
119: return CURLE_OUT_OF_MEMORY;
120:
121: if(userp && *userp) {
122: CURLcode result;
123:
124: /* Populate our identity structure */
125: result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity);
126: if(result)
127: return result;
128:
129: /* Allow proper cleanup of the identity structure */
130: ntlm->p_identity = &ntlm->identity;
131: }
132: else
133: /* Use the current Windows user */
134: ntlm->p_identity = NULL;
135:
136: /* Allocate our credentials handle */
137: ntlm->credentials = calloc(1, sizeof(CredHandle));
138: if(!ntlm->credentials)
139: return CURLE_OUT_OF_MEMORY;
140:
141: /* Acquire our credentials handle */
142: status = s_pSecFn->AcquireCredentialsHandle(NULL,
143: (TCHAR *) TEXT(SP_NAME_NTLM),
144: SECPKG_CRED_OUTBOUND, NULL,
145: ntlm->p_identity, NULL, NULL,
146: ntlm->credentials, &expiry);
147: if(status != SEC_E_OK)
148: return CURLE_LOGIN_DENIED;
149:
150: /* Allocate our new context handle */
151: ntlm->context = calloc(1, sizeof(CtxtHandle));
152: if(!ntlm->context)
153: return CURLE_OUT_OF_MEMORY;
154:
155: ntlm->spn = Curl_auth_build_spn(service, host, NULL);
156: if(!ntlm->spn)
157: return CURLE_OUT_OF_MEMORY;
158:
159: /* Setup the type-1 "output" security buffer */
160: type_1_desc.ulVersion = SECBUFFER_VERSION;
161: type_1_desc.cBuffers = 1;
162: type_1_desc.pBuffers = &type_1_buf;
163: type_1_buf.BufferType = SECBUFFER_TOKEN;
164: type_1_buf.pvBuffer = ntlm->output_token;
165: type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
166:
167: /* Generate our type-1 message */
168: status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
169: ntlm->spn,
170: 0, 0, SECURITY_NETWORK_DREP,
171: NULL, 0,
172: ntlm->context, &type_1_desc,
173: &attrs, &expiry);
174: if(status == SEC_I_COMPLETE_NEEDED ||
175: status == SEC_I_COMPLETE_AND_CONTINUE)
176: s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
177: else if(status == SEC_E_INSUFFICIENT_MEMORY)
178: return CURLE_OUT_OF_MEMORY;
179: else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
180: return CURLE_AUTH_ERROR;
181:
182: /* Base64 encode the response */
183: return Curl_base64_encode(data, (char *) ntlm->output_token,
184: type_1_buf.cbBuffer, outptr, outlen);
185: }
186:
187: /*
188: * Curl_auth_decode_ntlm_type2_message()
189: *
190: * This is used to decode an already encoded NTLM type-2 message.
191: *
192: * Parameters:
193: *
194: * data [in] - The session handle.
195: * type2msg [in] - The base64 encoded type-2 message.
196: * ntlm [in/out] - The NTLM data struct being used and modified.
197: *
198: * Returns CURLE_OK on success.
199: */
200: CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
201: const char *type2msg,
202: struct ntlmdata *ntlm)
203: {
204: CURLcode result = CURLE_OK;
205: unsigned char *type2 = NULL;
206: size_t type2_len = 0;
207:
208: #if defined(CURL_DISABLE_VERBOSE_STRINGS)
209: (void) data;
210: #endif
211:
212: /* Decode the base-64 encoded type-2 message */
213: if(strlen(type2msg) && *type2msg != '=') {
214: result = Curl_base64_decode(type2msg, &type2, &type2_len);
215: if(result)
216: return result;
217: }
218:
219: /* Ensure we have a valid type-2 message */
220: if(!type2) {
221: infof(data, "NTLM handshake failure (empty type-2 message)\n");
222:
223: return CURLE_BAD_CONTENT_ENCODING;
224: }
225:
226: /* Simply store the challenge for use later */
227: ntlm->input_token = type2;
228: ntlm->input_token_len = type2_len;
229:
230: return result;
231: }
232:
233: /*
234: * Curl_auth_create_ntlm_type3_message()
235: * Curl_auth_create_ntlm_type3_message()
236: *
237: * This is used to generate an already encoded NTLM type-3 message ready for
238: * sending to the recipient.
239: *
240: * Parameters:
241: *
242: * data [in] - The session handle.
243: * userp [in] - The user name in the format User or Domain\User.
244: * passwdp [in] - The user's password.
245: * ntlm [in/out] - The NTLM data struct being used and modified.
246: * outptr [in/out] - The address where a pointer to newly allocated memory
247: * holding the result will be stored upon completion.
248: * outlen [out] - The length of the output message.
249: *
250: * Returns CURLE_OK on success.
251: */
252: CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
253: const char *userp,
254: const char *passwdp,
255: struct ntlmdata *ntlm,
256: char **outptr, size_t *outlen)
257: {
258: CURLcode result = CURLE_OK;
259: SecBuffer type_2_bufs[2];
260: SecBuffer type_3_buf;
261: SecBufferDesc type_2_desc;
262: SecBufferDesc type_3_desc;
263: SECURITY_STATUS status;
264: unsigned long attrs;
265: TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
266:
267: (void) passwdp;
268: (void) userp;
269:
270: /* Setup the type-2 "input" security buffer */
271: type_2_desc.ulVersion = SECBUFFER_VERSION;
272: type_2_desc.cBuffers = 1;
273: type_2_desc.pBuffers = &type_2_bufs[0];
274: type_2_bufs[0].BufferType = SECBUFFER_TOKEN;
275: type_2_bufs[0].pvBuffer = ntlm->input_token;
276: type_2_bufs[0].cbBuffer = curlx_uztoul(ntlm->input_token_len);
277:
278: #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
279: /* ssl context comes from schannel.
280: * When extended protection is used in IIS server,
281: * we have to pass a second SecBuffer to the SecBufferDesc
282: * otherwise IIS will not pass the authentication (401 response).
283: * Minimum supported version is Windows 7.
284: * https://docs.microsoft.com/en-us/security-updates
285: * /SecurityAdvisories/2009/973811
286: */
287: if(ntlm->sslContext) {
288: SEC_CHANNEL_BINDINGS channelBindings;
289: SecPkgContext_Bindings pkgBindings;
290: pkgBindings.Bindings = &channelBindings;
291: status = s_pSecFn->QueryContextAttributes(
292: ntlm->sslContext,
293: SECPKG_ATTR_ENDPOINT_BINDINGS,
294: &pkgBindings
295: );
296: if(status == SEC_E_OK) {
297: type_2_desc.cBuffers++;
298: type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
299: type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength;
300: type_2_bufs[1].pvBuffer = pkgBindings.Bindings;
301: }
302: }
303: #endif
304:
305: /* Setup the type-3 "output" security buffer */
306: type_3_desc.ulVersion = SECBUFFER_VERSION;
307: type_3_desc.cBuffers = 1;
308: type_3_desc.pBuffers = &type_3_buf;
309: type_3_buf.BufferType = SECBUFFER_TOKEN;
310: type_3_buf.pvBuffer = ntlm->output_token;
311: type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
312:
313: /* Generate our type-3 message */
314: status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
315: ntlm->context,
316: ntlm->spn,
317: 0, 0, SECURITY_NETWORK_DREP,
318: &type_2_desc,
319: 0, ntlm->context,
320: &type_3_desc,
321: &attrs, &expiry);
322: if(status != SEC_E_OK) {
323: infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
324: status);
325:
326: if(status == SEC_E_INSUFFICIENT_MEMORY)
327: return CURLE_OUT_OF_MEMORY;
328:
329: return CURLE_AUTH_ERROR;
330: }
331:
332: /* Base64 encode the response */
333: result = Curl_base64_encode(data, (char *) ntlm->output_token,
334: type_3_buf.cbBuffer, outptr, outlen);
335:
336: Curl_auth_cleanup_ntlm(ntlm);
337:
338: return result;
339: }
340:
341: /*
342: * Curl_auth_cleanup_ntlm()
343: *
344: * This is used to clean up the NTLM specific data.
345: *
346: * Parameters:
347: *
348: * ntlm [in/out] - The NTLM data struct being cleaned up.
349: *
350: */
351: void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
352: {
353: /* Free our security context */
354: if(ntlm->context) {
355: s_pSecFn->DeleteSecurityContext(ntlm->context);
356: free(ntlm->context);
357: ntlm->context = NULL;
358: }
359:
360: /* Free our credentials handle */
361: if(ntlm->credentials) {
362: s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
363: free(ntlm->credentials);
364: ntlm->credentials = NULL;
365: }
366:
367: /* Free our identity */
368: Curl_sspi_free_identity(ntlm->p_identity);
369: ntlm->p_identity = NULL;
370:
371: /* Free the input and output tokens */
372: Curl_safefree(ntlm->input_token);
373: Curl_safefree(ntlm->output_token);
374:
375: /* Reset any variables */
376: ntlm->token_max = 0;
377:
378: Curl_safefree(ntlm->spn);
379: }
380:
381: #endif /* USE_WINDOWS_SSPI && USE_NTLM */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>