ntlm_sspi.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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  return (status == SEC_E_OK ? TRUE : FALSE);
60 }
61 
62 /*
63  * Curl_auth_create_ntlm_type1_message()
64  *
65  * This is used to generate an already encoded NTLM type-1 message ready for
66  * sending to the recipient.
67  *
68  * Parameters:
69  *
70  * data [in] - The session handle.
71  * userp [in] - The user name in the format User or Domain\User.
72  * passdwp [in] - The user's password.
73  * ntlm [in/out] - The NTLM data struct being used and modified.
74  * outptr [in/out] - The address where a pointer to newly allocated memory
75  * holding the result will be stored upon completion.
76  * outlen [out] - The length of the output message.
77  *
78  * Returns CURLE_OK on success.
79  */
80 CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
81  const char *userp,
82  const char *passwdp,
83  struct ntlmdata *ntlm,
84  char **outptr, size_t *outlen)
85 {
86  PSecPkgInfo SecurityPackage;
87  SecBuffer type_1_buf;
88  SecBufferDesc type_1_desc;
89  SECURITY_STATUS status;
90  unsigned long attrs;
91  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
92 
93  /* Clean up any former leftovers and initialise to defaults */
94  Curl_auth_ntlm_cleanup(ntlm);
95 
96  /* Query the security package for NTLM */
97  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
98  &SecurityPackage);
99  if(status != SEC_E_OK)
100  return CURLE_NOT_BUILT_IN;
101 
102  ntlm->token_max = SecurityPackage->cbMaxToken;
103 
104  /* Release the package buffer as it is not required anymore */
105  s_pSecFn->FreeContextBuffer(SecurityPackage);
106 
107  /* Allocate our output buffer */
108  ntlm->output_token = malloc(ntlm->token_max);
109  if(!ntlm->output_token)
110  return CURLE_OUT_OF_MEMORY;
111 
112  if(userp && *userp) {
114 
115  /* Populate our identity structure */
116  result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity);
117  if(result)
118  return result;
119 
120  /* Allow proper cleanup of the identity structure */
121  ntlm->p_identity = &ntlm->identity;
122  }
123  else
124  /* Use the current Windows user */
125  ntlm->p_identity = NULL;
126 
127  /* Allocate our credentials handle */
128  ntlm->credentials = malloc(sizeof(CredHandle));
129  if(!ntlm->credentials)
130  return CURLE_OUT_OF_MEMORY;
131 
132  memset(ntlm->credentials, 0, sizeof(CredHandle));
133 
134  /* Acquire our credentials handle */
135  status = s_pSecFn->AcquireCredentialsHandle(NULL,
136  (TCHAR *) TEXT(SP_NAME_NTLM),
137  SECPKG_CRED_OUTBOUND, NULL,
138  ntlm->p_identity, NULL, NULL,
139  ntlm->credentials, &expiry);
140  if(status != SEC_E_OK)
141  return CURLE_LOGIN_DENIED;
142 
143  /* Allocate our new context handle */
144  ntlm->context = malloc(sizeof(CtxtHandle));
145  if(!ntlm->context)
146  return CURLE_OUT_OF_MEMORY;
147 
148  memset(ntlm->context, 0, sizeof(CtxtHandle));
149 
150  /* Setup the type-1 "output" security buffer */
151  type_1_desc.ulVersion = SECBUFFER_VERSION;
152  type_1_desc.cBuffers = 1;
153  type_1_desc.pBuffers = &type_1_buf;
154  type_1_buf.BufferType = SECBUFFER_TOKEN;
155  type_1_buf.pvBuffer = ntlm->output_token;
156  type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
157 
158  /* Generate our type-1 message */
159  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
160  (TCHAR *) TEXT(""),
161  0, 0, SECURITY_NETWORK_DREP,
162  NULL, 0,
163  ntlm->context, &type_1_desc,
164  &attrs, &expiry);
165  if(status == SEC_I_COMPLETE_NEEDED ||
166  status == SEC_I_COMPLETE_AND_CONTINUE)
167  s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
168  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
169  return CURLE_RECV_ERROR;
170 
171  /* Base64 encode the response */
172  return Curl_base64_encode(data, (char *) ntlm->output_token,
173  type_1_buf.cbBuffer, outptr, outlen);
174 }
175 
176 /*
177  * Curl_auth_decode_ntlm_type2_message()
178  *
179  * This is used to decode an already encoded NTLM type-2 message.
180  *
181  * Parameters:
182  *
183  * data [in] - The session handle.
184  * type2msg [in] - The base64 encoded type-2 message.
185  * ntlm [in/out] - The NTLM data struct being used and modified.
186  *
187  * Returns CURLE_OK on success.
188  */
189 CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
190  const char *type2msg,
191  struct ntlmdata *ntlm)
192 {
193  CURLcode result = CURLE_OK;
194  unsigned char *type2 = NULL;
195  size_t type2_len = 0;
196 
197 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
198  (void) data;
199 #endif
200 
201  /* Decode the base-64 encoded type-2 message */
202  if(strlen(type2msg) && *type2msg != '=') {
203  result = Curl_base64_decode(type2msg, &type2, &type2_len);
204  if(result)
205  return result;
206  }
207 
208  /* Ensure we have a valid type-2 message */
209  if(!type2) {
210  infof(data, "NTLM handshake failure (empty type-2 message)\n");
211 
213  }
214 
215  /* Simply store the challenge for use later */
216  ntlm->input_token = type2;
217  ntlm->input_token_len = type2_len;
218 
219  return result;
220 }
221 
222 /*
223 * Curl_auth_create_ntlm_type3_message()
224  * Curl_auth_create_ntlm_type3_message()
225  *
226  * This is used to generate an already encoded NTLM type-3 message ready for
227  * sending to the recipient.
228  *
229  * Parameters:
230  *
231  * data [in] - The session handle.
232  * userp [in] - The user name in the format User or Domain\User.
233  * passdwp [in] - The user's password.
234  * ntlm [in/out] - The NTLM data struct being used and modified.
235  * outptr [in/out] - The address where a pointer to newly allocated memory
236  * holding the result will be stored upon completion.
237  * outlen [out] - The length of the output message.
238  *
239  * Returns CURLE_OK on success.
240  */
241 CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
242  const char *userp,
243  const char *passwdp,
244  struct ntlmdata *ntlm,
245  char **outptr, size_t *outlen)
246 {
247  CURLcode result = CURLE_OK;
248  SecBuffer type_2_buf;
249  SecBuffer type_3_buf;
250  SecBufferDesc type_2_desc;
251  SecBufferDesc type_3_desc;
252  SECURITY_STATUS status;
253  unsigned long attrs;
254  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
255 
256  (void) passwdp;
257  (void) userp;
258 
259  /* Setup the type-2 "input" security buffer */
260  type_2_desc.ulVersion = SECBUFFER_VERSION;
261  type_2_desc.cBuffers = 1;
262  type_2_desc.pBuffers = &type_2_buf;
263  type_2_buf.BufferType = SECBUFFER_TOKEN;
264  type_2_buf.pvBuffer = ntlm->input_token;
265  type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len);
266 
267  /* Setup the type-3 "output" security buffer */
268  type_3_desc.ulVersion = SECBUFFER_VERSION;
269  type_3_desc.cBuffers = 1;
270  type_3_desc.pBuffers = &type_3_buf;
271  type_3_buf.BufferType = SECBUFFER_TOKEN;
272  type_3_buf.pvBuffer = ntlm->output_token;
273  type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
274 
275  /* Generate our type-3 message */
276  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
277  ntlm->context,
278  (TCHAR *) TEXT(""),
279  0, 0, SECURITY_NETWORK_DREP,
280  &type_2_desc,
281  0, ntlm->context,
282  &type_3_desc,
283  &attrs, &expiry);
284  if(status != SEC_E_OK) {
285  infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
286  status);
287 
288  return CURLE_RECV_ERROR;
289  }
290 
291  /* Base64 encode the response */
292  result = Curl_base64_encode(data, (char *) ntlm->output_token,
293  type_3_buf.cbBuffer, outptr, outlen);
294 
295  Curl_auth_ntlm_cleanup(ntlm);
296 
297  return result;
298 }
299 
300 /*
301  * Curl_auth_ntlm_cleanup()
302  *
303  * This is used to clean up the NTLM specific data.
304  *
305  * Parameters:
306  *
307  * ntlm [in/out] - The NTLM data struct being cleaned up.
308  *
309  */
310 void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
311 {
312  /* Free our security context */
313  if(ntlm->context) {
314  s_pSecFn->DeleteSecurityContext(ntlm->context);
315  free(ntlm->context);
316  ntlm->context = NULL;
317  }
318 
319  /* Free our credentials handle */
320  if(ntlm->credentials) {
321  s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
322  free(ntlm->credentials);
323  ntlm->credentials = NULL;
324  }
325 
326  /* Free our identity */
327  Curl_sspi_free_identity(ntlm->p_identity);
328  ntlm->p_identity = NULL;
329 
330  /* Free the input and output tokens */
331  Curl_safefree(ntlm->input_token);
332  Curl_safefree(ntlm->output_token);
333 
334  /* Reset any variables */
335  ntlm->token_max = 0;
336 }
337 
338 #endif /* USE_WINDOWS_SSPI && USE_NTLM */
#define free(ptr)
Definition: curl_memory.h:130
CURLcode Curl_base64_decode(const char *src, unsigned char **outptr, size_t *outlen)
Definition: base64.c:100
CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen)
Definition: base64.c:291
CURLcode
Definition: curl.h:454
#define malloc(size)
Definition: curl_memory.h:124
UNITTEST_START int result
Definition: unit1304.c:49
unsigned long curlx_uztoul(size_t uznum)
Definition: warnless.c:222
#define FALSE
Definition: curl.h:455
#define Curl_safefree(ptr)
Definition: memdebug.h:170
#define infof
Definition: sendf.h:44
#define TRUE
Definition: debug.c:29


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16