ntlm_sspi.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM)
00026 
00027 #include <curl/curl.h>
00028 
00029 #include "vauth/vauth.h"
00030 #include "urldata.h"
00031 #include "curl_base64.h"
00032 #include "warnless.h"
00033 #include "curl_multibyte.h"
00034 #include "sendf.h"
00035 
00036 /* The last #include files should be: */
00037 #include "curl_memory.h"
00038 #include "memdebug.h"
00039 
00040 /*
00041  * Curl_auth_is_ntlm_supported()
00042  *
00043  * This is used to evaluate if NTLM is supported.
00044  *
00045  * Parameters: None
00046  *
00047  * Returns TRUE if NTLM is supported by Windows SSPI.
00048  */
00049 bool Curl_auth_is_ntlm_supported(void)
00050 {
00051   PSecPkgInfo SecurityPackage;
00052   SECURITY_STATUS status;
00053 
00054   /* Query the security package for NTLM */
00055   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
00056                                               &SecurityPackage);
00057 
00058   return (status == SEC_E_OK ? TRUE : FALSE);
00059 }
00060 
00061 /*
00062  * Curl_auth_create_ntlm_type1_message()
00063  *
00064  * This is used to generate an already encoded NTLM type-1 message ready for
00065  * sending to the recipient.
00066  *
00067  * Parameters:
00068  *
00069  * userp   [in]     - The user name in the format User or Domain\User.
00070  * passdwp [in]     - The user's password.
00071  * ntlm    [in/out] - The NTLM data struct being used and modified.
00072  * outptr  [in/out] - The address where a pointer to newly allocated memory
00073  *                    holding the result will be stored upon completion.
00074  * outlen  [out]    - The length of the output message.
00075  *
00076  * Returns CURLE_OK on success.
00077  */
00078 CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
00079                                              const char *passwdp,
00080                                              struct ntlmdata *ntlm,
00081                                              char **outptr, size_t *outlen)
00082 {
00083   PSecPkgInfo SecurityPackage;
00084   SecBuffer type_1_buf;
00085   SecBufferDesc type_1_desc;
00086   SECURITY_STATUS status;
00087   unsigned long attrs;
00088   TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
00089 
00090   /* Clean up any former leftovers and initialise to defaults */
00091   Curl_auth_ntlm_cleanup(ntlm);
00092 
00093   /* Query the security package for NTLM */
00094   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
00095                                               &SecurityPackage);
00096   if(status != SEC_E_OK)
00097     return CURLE_NOT_BUILT_IN;
00098 
00099   ntlm->token_max = SecurityPackage->cbMaxToken;
00100 
00101   /* Release the package buffer as it is not required anymore */
00102   s_pSecFn->FreeContextBuffer(SecurityPackage);
00103 
00104   /* Allocate our output buffer */
00105   ntlm->output_token = malloc(ntlm->token_max);
00106   if(!ntlm->output_token)
00107     return CURLE_OUT_OF_MEMORY;
00108 
00109   if(userp && *userp) {
00110     CURLcode result;
00111 
00112     /* Populate our identity structure */
00113     result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity);
00114     if(result)
00115       return result;
00116 
00117     /* Allow proper cleanup of the identity structure */
00118     ntlm->p_identity = &ntlm->identity;
00119   }
00120   else
00121     /* Use the current Windows user */
00122     ntlm->p_identity = NULL;
00123 
00124   /* Allocate our credentials handle */
00125   ntlm->credentials = malloc(sizeof(CredHandle));
00126   if(!ntlm->credentials)
00127     return CURLE_OUT_OF_MEMORY;
00128 
00129   memset(ntlm->credentials, 0, sizeof(CredHandle));
00130 
00131   /* Acquire our credentials handle */
00132   status = s_pSecFn->AcquireCredentialsHandle(NULL,
00133                                               (TCHAR *) TEXT(SP_NAME_NTLM),
00134                                               SECPKG_CRED_OUTBOUND, NULL,
00135                                               ntlm->p_identity, NULL, NULL,
00136                                               ntlm->credentials, &expiry);
00137   if(status != SEC_E_OK)
00138     return CURLE_LOGIN_DENIED;
00139 
00140   /* Allocate our new context handle */
00141   ntlm->context = malloc(sizeof(CtxtHandle));
00142   if(!ntlm->context)
00143     return CURLE_OUT_OF_MEMORY;
00144 
00145   memset(ntlm->context, 0, sizeof(CtxtHandle));
00146 
00147   /* Setup the type-1 "output" security buffer */
00148   type_1_desc.ulVersion = SECBUFFER_VERSION;
00149   type_1_desc.cBuffers  = 1;
00150   type_1_desc.pBuffers  = &type_1_buf;
00151   type_1_buf.BufferType = SECBUFFER_TOKEN;
00152   type_1_buf.pvBuffer   = ntlm->output_token;
00153   type_1_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
00154 
00155   /* Generate our type-1 message */
00156   status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
00157                                                (TCHAR *) TEXT(""),
00158                                                0, 0, SECURITY_NETWORK_DREP,
00159                                                NULL, 0,
00160                                                ntlm->context, &type_1_desc,
00161                                                &attrs, &expiry);
00162   if(status == SEC_I_COMPLETE_NEEDED ||
00163     status == SEC_I_COMPLETE_AND_CONTINUE)
00164     s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
00165   else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
00166     return CURLE_RECV_ERROR;
00167 
00168   /* Base64 encode the response */
00169   return Curl_base64_encode(NULL, (char *) ntlm->output_token,
00170                             type_1_buf.cbBuffer, outptr, outlen);
00171 }
00172 
00173 /*
00174  * Curl_auth_decode_ntlm_type2_message()
00175  *
00176  * This is used to decode an already encoded NTLM type-2 message.
00177  *
00178  * Parameters:
00179  *
00180  * data     [in]     - The session handle.
00181  * type2msg [in]     - The base64 encoded type-2 message.
00182  * ntlm     [in/out] - The NTLM data struct being used and modified.
00183  *
00184  * Returns CURLE_OK on success.
00185  */
00186 CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
00187                                              const char *type2msg,
00188                                              struct ntlmdata *ntlm)
00189 {
00190   CURLcode result = CURLE_OK;
00191   unsigned char *type2 = NULL;
00192   size_t type2_len = 0;
00193 
00194 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
00195   (void) data;
00196 #endif
00197 
00198   /* Decode the base-64 encoded type-2 message */
00199   if(strlen(type2msg) && *type2msg != '=') {
00200     result = Curl_base64_decode(type2msg, &type2, &type2_len);
00201     if(result)
00202       return result;
00203   }
00204 
00205   /* Ensure we have a valid type-2 message */
00206   if(!type2) {
00207     infof(data, "NTLM handshake failure (empty type-2 message)\n");
00208 
00209     return CURLE_BAD_CONTENT_ENCODING;
00210   }
00211 
00212   /* Simply store the challenge for use later */
00213   ntlm->input_token = type2;
00214   ntlm->input_token_len = type2_len;
00215 
00216   return result;
00217 }
00218 
00219 /*
00220 * Curl_auth_create_ntlm_type3_message()
00221  * Curl_auth_create_ntlm_type3_message()
00222  *
00223  * This is used to generate an already encoded NTLM type-3 message ready for
00224  * sending to the recipient.
00225  *
00226  * Parameters:
00227  *
00228  * data    [in]     - The session handle.
00229  * userp   [in]     - The user name in the format User or Domain\User.
00230  * passdwp [in]     - The user's password.
00231  * ntlm    [in/out] - The NTLM data struct being used and modified.
00232  * outptr  [in/out] - The address where a pointer to newly allocated memory
00233  *                    holding the result will be stored upon completion.
00234  * outlen  [out]    - The length of the output message.
00235  *
00236  * Returns CURLE_OK on success.
00237  */
00238 CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
00239                                              const char *userp,
00240                                              const char *passwdp,
00241                                              struct ntlmdata *ntlm,
00242                                              char **outptr, size_t *outlen)
00243 {
00244   CURLcode result = CURLE_OK;
00245   SecBuffer type_2_buf;
00246   SecBuffer type_3_buf;
00247   SecBufferDesc type_2_desc;
00248   SecBufferDesc type_3_desc;
00249   SECURITY_STATUS status;
00250   unsigned long attrs;
00251   TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
00252 
00253   (void) passwdp;
00254   (void) userp;
00255 
00256   /* Setup the type-2 "input" security buffer */
00257   type_2_desc.ulVersion = SECBUFFER_VERSION;
00258   type_2_desc.cBuffers  = 1;
00259   type_2_desc.pBuffers  = &type_2_buf;
00260   type_2_buf.BufferType = SECBUFFER_TOKEN;
00261   type_2_buf.pvBuffer   = ntlm->input_token;
00262   type_2_buf.cbBuffer   = curlx_uztoul(ntlm->input_token_len);
00263 
00264   /* Setup the type-3 "output" security buffer */
00265   type_3_desc.ulVersion = SECBUFFER_VERSION;
00266   type_3_desc.cBuffers  = 1;
00267   type_3_desc.pBuffers  = &type_3_buf;
00268   type_3_buf.BufferType = SECBUFFER_TOKEN;
00269   type_3_buf.pvBuffer   = ntlm->output_token;
00270   type_3_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
00271 
00272   /* Generate our type-3 message */
00273   status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
00274                                                ntlm->context,
00275                                                (TCHAR *) TEXT(""),
00276                                                0, 0, SECURITY_NETWORK_DREP,
00277                                                &type_2_desc,
00278                                                0, ntlm->context,
00279                                                &type_3_desc,
00280                                                &attrs, &expiry);
00281   if(status != SEC_E_OK) {
00282     infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
00283           status);
00284 
00285     return CURLE_RECV_ERROR;
00286   }
00287 
00288   /* Base64 encode the response */
00289   result = Curl_base64_encode(data, (char *) ntlm->output_token,
00290                               type_3_buf.cbBuffer, outptr, outlen);
00291 
00292   Curl_auth_ntlm_cleanup(ntlm);
00293 
00294   return result;
00295 }
00296 
00297 /*
00298  * Curl_auth_ntlm_cleanup()
00299  *
00300  * This is used to clean up the NTLM specific data.
00301  *
00302  * Parameters:
00303  *
00304  * ntlm    [in/out] - The NTLM data struct being cleaned up.
00305  *
00306  */
00307 void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
00308 {
00309   /* Free our security context */
00310   if(ntlm->context) {
00311     s_pSecFn->DeleteSecurityContext(ntlm->context);
00312     free(ntlm->context);
00313     ntlm->context = NULL;
00314   }
00315 
00316   /* Free our credentials handle */
00317   if(ntlm->credentials) {
00318     s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
00319     free(ntlm->credentials);
00320     ntlm->credentials = NULL;
00321   }
00322 
00323   /* Free our identity */
00324   Curl_sspi_free_identity(ntlm->p_identity);
00325   ntlm->p_identity = NULL;
00326 
00327   /* Free the input and output tokens */
00328   Curl_safefree(ntlm->input_token);
00329   Curl_safefree(ntlm->output_token);
00330 
00331   /* Reset any variables */
00332   ntlm->token_max = 0;
00333 }
00334 
00335 #endif /* USE_WINDOWS_SSPI && USE_NTLM */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:05