Imported Upstream version 7.44.0
[platform/upstream/curl.git] / lib / curl_sasl_sspi.c
index 0509b75..b149530 100644 (file)
@@ -5,8 +5,8 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2014 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
  * Copyright (C) 2014, Steve Holme, <steve_holme@hotmail.com>.
- * Copyright (C) 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
 #include "urldata.h"
 #include "curl_base64.h"
 #include "warnless.h"
-#include "curl_memory.h"
 #include "curl_multibyte.h"
 #include "sendf.h"
 #include "strdup.h"
+#include "curl_printf.h"
+#include "rawstr.h"
 
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
+/* The last #include files should be: */
+#include "curl_memory.h"
 #include "memdebug.h"
 
 /*
@@ -80,7 +79,7 @@ TCHAR *Curl_sasl_build_spn(const char *service, const char *host)
   /* Allocate our TCHAR based SPN */
   tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn);
   if(!tchar_spn) {
-    Curl_safefree(utf8_spn);
+    free(utf8_spn);
 
     return NULL;
   }
@@ -156,7 +155,7 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
                                               &SecurityPackage);
   if(status != SEC_E_OK) {
-    Curl_safefree(input_token);
+    free(input_token);
 
     return CURLE_NOT_BUILT_IN;
   }
@@ -169,7 +168,7 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
   /* Allocate our response buffer */
   output_token = malloc(token_max);
   if(!output_token) {
-    Curl_safefree(input_token);
+    free(input_token);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -177,8 +176,8 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
   /* Generate our SPN */
   spn = Curl_sasl_build_spn(service, data->easy_conn->host.name);
   if(!spn) {
-    Curl_safefree(output_token);
-    Curl_safefree(input_token);
+    free(output_token);
+    free(input_token);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -187,9 +186,9 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
     /* Populate our identity structure */
     result = Curl_create_sspi_identity(userp, passwdp, &identity);
     if(result) {
-      Curl_safefree(spn);
-      Curl_safefree(output_token);
-      Curl_safefree(input_token);
+      free(spn);
+      free(output_token);
+      free(input_token);
 
       return result;
     }
@@ -210,9 +209,9 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
 
   if(status != SEC_E_OK) {
     Curl_sspi_free_identity(p_identity);
-    Curl_safefree(spn);
-    Curl_safefree(output_token);
-    Curl_safefree(input_token);
+    free(spn);
+    free(output_token);
+    free(input_token);
 
     return CURLE_LOGIN_DENIED;
   }
@@ -245,9 +244,9 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
   else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
     s_pSecFn->FreeCredentialsHandle(&credentials);
     Curl_sspi_free_identity(p_identity);
-    Curl_safefree(spn);
-    Curl_safefree(output_token);
-    Curl_safefree(input_token);
+    free(spn);
+    free(output_token);
+    free(input_token);
 
     return CURLE_RECV_ERROR;
   }
@@ -264,18 +263,86 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
   Curl_sspi_free_identity(p_identity);
 
   /* Free the SPN */
-  Curl_safefree(spn);
+  free(spn);
 
   /* Free the response buffer */
-  Curl_safefree(output_token);
+  free(output_token);
 
   /* Free the decoded challenge message */
-  Curl_safefree(input_token);
+  free(input_token);
 
   return result;
 }
 
 /*
+* Curl_override_sspi_http_realm()
+*
+* This is used to populate the domain in a SSPI identity structure
+* The realm is extracted from the challenge message and used as the
+* domain if it is not already explicitly set.
+*
+* Parameters:
+*
+* chlg     [in]     - The challenge message.
+* identity [in/out] - The identity structure.
+*
+* Returns CURLE_OK on success.
+*/
+CURLcode Curl_override_sspi_http_realm(const char *chlg,
+                                       SEC_WINNT_AUTH_IDENTITY *identity)
+{
+  xcharp_u domain, dup_domain;
+
+  /* If domain is blank or unset, check challenge message for realm */
+  if(!identity->Domain || !identity->DomainLength) {
+    for(;;) {
+      char value[DIGEST_MAX_VALUE_LENGTH];
+      char content[DIGEST_MAX_CONTENT_LENGTH];
+
+      /* Pass all additional spaces here */
+      while(*chlg && ISSPACE(*chlg))
+        chlg++;
+
+      /* Extract a value=content pair */
+      if(!Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) {
+        if(Curl_raw_equal(value, "realm")) {
+
+          /* Setup identity's domain and length */
+          domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)content);
+          if(!domain.tchar_ptr)
+            return CURLE_OUT_OF_MEMORY;
+          dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
+          if(!dup_domain.tchar_ptr) {
+            Curl_unicodefree(domain.tchar_ptr);
+            return CURLE_OUT_OF_MEMORY;
+          }
+          identity->Domain = dup_domain.tbyte_ptr;
+          identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
+          dup_domain.tchar_ptr = NULL;
+
+          Curl_unicodefree(domain.tchar_ptr);
+        }
+        else {
+          /* unknown specifier, ignore it! */
+        }
+      }
+      else
+        break; /* we're done here */
+
+      /* Pass all additional spaces here */
+      while(*chlg && ISSPACE(*chlg))
+        chlg++;
+
+      /* Allow the list to be comma-separated */
+      if(',' == *chlg)
+        chlg++;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+/*
  * Curl_sasl_decode_digest_http_message()
  *
  * This is used to decode a HTTP DIGEST challenge message into the seperate
@@ -376,6 +443,11 @@ CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data,
     if(Curl_create_sspi_identity(userp, passwdp, &identity))
       return CURLE_OUT_OF_MEMORY;
 
+    /* Populate our identity domain */
+    if(Curl_override_sspi_http_realm((const char*)digest->input_token,
+                                     &identity))
+      return CURLE_OUT_OF_MEMORY;
+
     /* Allow proper cleanup of the identity structure */
     p_identity = &identity;
   }
@@ -390,7 +462,7 @@ CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data,
                                               p_identity, NULL, NULL,
                                               &credentials, &expiry);
   if(status != SEC_E_OK) {
-    Curl_safefree(output_token);
+    free(output_token);
 
     return CURLE_LOGIN_DENIED;
   }
@@ -430,7 +502,7 @@ CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data,
   else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
     s_pSecFn->FreeCredentialsHandle(&credentials);
 
-    Curl_safefree(output_token);
+    free(output_token);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -440,7 +512,7 @@ CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data,
     s_pSecFn->DeleteSecurityContext(&context);
     s_pSecFn->FreeCredentialsHandle(&credentials);
 
-    Curl_safefree(output_token);
+    free(output_token);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -461,7 +533,7 @@ CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data,
   Curl_sspi_free_identity(p_identity);
 
   /* Free the response buffer */
-  Curl_safefree(output_token);
+  free(output_token);
 
   return CURLE_OK;
 }
@@ -912,7 +984,7 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
                                                &expiry);
 
   if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
-    Curl_safefree(chlg);
+    free(chlg);
 
     return CURLE_RECV_ERROR;
   }
@@ -930,7 +1002,7 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
   }
 
   /* Free the decoded challenge */
-  Curl_safefree(chlg);
+  free(chlg);
 
   return result;
 }
@@ -1001,7 +1073,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
                                             SECPKG_ATTR_SIZES,
                                             &sizes);
   if(status != SEC_E_OK) {
-    Curl_safefree(chlg);
+    free(chlg);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -1011,7 +1083,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
                                                 SECPKG_CRED_ATTR_NAMES,
                                                 &names);
   if(status != SEC_E_OK) {
-    Curl_safefree(chlg);
+    free(chlg);
 
     return CURLE_RECV_ERROR;
   }
@@ -1032,7 +1104,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   if(status != SEC_E_OK) {
     infof(data, "GSSAPI handshake failure (empty security message)\n");
 
-    Curl_safefree(chlg);
+    free(chlg);
 
     return CURLE_BAD_CONTENT_ENCODING;
   }
@@ -1041,7 +1113,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   if(input_buf[1].cbBuffer != 4) {
     infof(data, "GSSAPI handshake failure (invalid security data)\n");
 
-    Curl_safefree(chlg);
+    free(chlg);
 
     return CURLE_BAD_CONTENT_ENCODING;
   }
@@ -1049,7 +1121,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   /* Copy the data out and free the challenge as it is not required anymore */
   memcpy(&indata, input_buf[1].pvBuffer, 4);
   s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
-  Curl_safefree(chlg);
+  free(chlg);
 
   /* Extract the security layer */
   sec_layer = indata & 0x000000FF;
@@ -1076,7 +1148,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   /* Convert the user name to UTF8 when operating with Unicode */
   user_name = Curl_convert_tchar_to_UTF8(names.sUserName);
   if(!user_name) {
-    Curl_safefree(trailer);
+    free(trailer);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -1085,7 +1157,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   messagelen = sizeof(outdata) + strlen(user_name) + 1;
   message = malloc(messagelen);
   if(!message) {
-    Curl_safefree(trailer);
+    free(trailer);
     Curl_unicodefree(user_name);
 
     return CURLE_OUT_OF_MEMORY;
@@ -1104,8 +1176,8 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   /* Allocate the padding */
   padding = malloc(sizes.cbBlockSize);
   if(!padding) {
-    Curl_safefree(message);
-    Curl_safefree(trailer);
+    free(message);
+    free(trailer);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -1128,9 +1200,9 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
                                     &wrap_desc, 0);
   if(status != SEC_E_OK) {
-    Curl_safefree(padding);
-    Curl_safefree(message);
-    Curl_safefree(trailer);
+    free(padding);
+    free(message);
+    free(trailer);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -1140,9 +1212,9 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
                wrap_buf[2].cbBuffer;
   appdata = malloc(appdatalen);
   if(!appdata) {
-    Curl_safefree(padding);
-    Curl_safefree(message);
-    Curl_safefree(trailer);
+    free(padding);
+    free(message);
+    free(trailer);
 
     return CURLE_OUT_OF_MEMORY;
   }
@@ -1159,10 +1231,10 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
                               outlen);
 
   /* Free all of our local buffers */
-  Curl_safefree(appdata);
-  Curl_safefree(padding);
-  Curl_safefree(message);
-  Curl_safefree(trailer);
+  free(appdata);
+  free(padding);
+  free(message);
+  free(trailer);
 
   return result;
 }