xref: /third_party/curl/lib/vauth/krb5_sspi.c (revision 13498266)
113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
2413498266Sopenharmony_ci *
2513498266Sopenharmony_ci ***************************************************************************/
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#include "curl_setup.h"
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5)
3013498266Sopenharmony_ci
3113498266Sopenharmony_ci#include <curl/curl.h>
3213498266Sopenharmony_ci
3313498266Sopenharmony_ci#include "vauth/vauth.h"
3413498266Sopenharmony_ci#include "urldata.h"
3513498266Sopenharmony_ci#include "warnless.h"
3613498266Sopenharmony_ci#include "curl_multibyte.h"
3713498266Sopenharmony_ci#include "sendf.h"
3813498266Sopenharmony_ci
3913498266Sopenharmony_ci/* The last #include files should be: */
4013498266Sopenharmony_ci#include "curl_memory.h"
4113498266Sopenharmony_ci#include "memdebug.h"
4213498266Sopenharmony_ci
4313498266Sopenharmony_ci/*
4413498266Sopenharmony_ci * Curl_auth_is_gssapi_supported()
4513498266Sopenharmony_ci *
4613498266Sopenharmony_ci * This is used to evaluate if GSSAPI (Kerberos V5) is supported.
4713498266Sopenharmony_ci *
4813498266Sopenharmony_ci * Parameters: None
4913498266Sopenharmony_ci *
5013498266Sopenharmony_ci * Returns TRUE if Kerberos V5 is supported by Windows SSPI.
5113498266Sopenharmony_ci */
5213498266Sopenharmony_cibool Curl_auth_is_gssapi_supported(void)
5313498266Sopenharmony_ci{
5413498266Sopenharmony_ci  PSecPkgInfo SecurityPackage;
5513498266Sopenharmony_ci  SECURITY_STATUS status;
5613498266Sopenharmony_ci
5713498266Sopenharmony_ci  /* Query the security package for Kerberos */
5813498266Sopenharmony_ci  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
5913498266Sopenharmony_ci                                              TEXT(SP_NAME_KERBEROS),
6013498266Sopenharmony_ci                                              &SecurityPackage);
6113498266Sopenharmony_ci
6213498266Sopenharmony_ci  /* Release the package buffer as it is not required anymore */
6313498266Sopenharmony_ci  if(status == SEC_E_OK) {
6413498266Sopenharmony_ci    s_pSecFn->FreeContextBuffer(SecurityPackage);
6513498266Sopenharmony_ci  }
6613498266Sopenharmony_ci
6713498266Sopenharmony_ci  return (status == SEC_E_OK ? TRUE : FALSE);
6813498266Sopenharmony_ci}
6913498266Sopenharmony_ci
7013498266Sopenharmony_ci/*
7113498266Sopenharmony_ci * Curl_auth_create_gssapi_user_message()
7213498266Sopenharmony_ci *
7313498266Sopenharmony_ci * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
7413498266Sopenharmony_ci * message ready for sending to the recipient.
7513498266Sopenharmony_ci *
7613498266Sopenharmony_ci * Parameters:
7713498266Sopenharmony_ci *
7813498266Sopenharmony_ci * data        [in]     - The session handle.
7913498266Sopenharmony_ci * userp       [in]     - The user name in the format User or Domain\User.
8013498266Sopenharmony_ci * passwdp     [in]     - The user's password.
8113498266Sopenharmony_ci * service     [in]     - The service type such as http, smtp, pop or imap.
8213498266Sopenharmony_ci * host        [in]     - The host name.
8313498266Sopenharmony_ci * mutual_auth [in]     - Flag specifying whether or not mutual authentication
8413498266Sopenharmony_ci *                        is enabled.
8513498266Sopenharmony_ci * chlg        [in]     - Optional challenge message.
8613498266Sopenharmony_ci * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
8713498266Sopenharmony_ci * out         [out]    - The result storage.
8813498266Sopenharmony_ci *
8913498266Sopenharmony_ci * Returns CURLE_OK on success.
9013498266Sopenharmony_ci */
9113498266Sopenharmony_ciCURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
9213498266Sopenharmony_ci                                              const char *userp,
9313498266Sopenharmony_ci                                              const char *passwdp,
9413498266Sopenharmony_ci                                              const char *service,
9513498266Sopenharmony_ci                                              const char *host,
9613498266Sopenharmony_ci                                              const bool mutual_auth,
9713498266Sopenharmony_ci                                              const struct bufref *chlg,
9813498266Sopenharmony_ci                                              struct kerberos5data *krb5,
9913498266Sopenharmony_ci                                              struct bufref *out)
10013498266Sopenharmony_ci{
10113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
10213498266Sopenharmony_ci  CtxtHandle context;
10313498266Sopenharmony_ci  PSecPkgInfo SecurityPackage;
10413498266Sopenharmony_ci  SecBuffer chlg_buf;
10513498266Sopenharmony_ci  SecBuffer resp_buf;
10613498266Sopenharmony_ci  SecBufferDesc chlg_desc;
10713498266Sopenharmony_ci  SecBufferDesc resp_desc;
10813498266Sopenharmony_ci  SECURITY_STATUS status;
10913498266Sopenharmony_ci  unsigned long attrs;
11013498266Sopenharmony_ci  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
11113498266Sopenharmony_ci
11213498266Sopenharmony_ci  if(!krb5->spn) {
11313498266Sopenharmony_ci    /* Generate our SPN */
11413498266Sopenharmony_ci    krb5->spn = Curl_auth_build_spn(service, host, NULL);
11513498266Sopenharmony_ci    if(!krb5->spn)
11613498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
11713498266Sopenharmony_ci  }
11813498266Sopenharmony_ci
11913498266Sopenharmony_ci  if(!krb5->output_token) {
12013498266Sopenharmony_ci    /* Query the security package for Kerberos */
12113498266Sopenharmony_ci    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
12213498266Sopenharmony_ci                                                TEXT(SP_NAME_KERBEROS),
12313498266Sopenharmony_ci                                                &SecurityPackage);
12413498266Sopenharmony_ci    if(status != SEC_E_OK) {
12513498266Sopenharmony_ci      failf(data, "SSPI: couldn't get auth info");
12613498266Sopenharmony_ci      return CURLE_AUTH_ERROR;
12713498266Sopenharmony_ci    }
12813498266Sopenharmony_ci
12913498266Sopenharmony_ci    krb5->token_max = SecurityPackage->cbMaxToken;
13013498266Sopenharmony_ci
13113498266Sopenharmony_ci    /* Release the package buffer as it is not required anymore */
13213498266Sopenharmony_ci    s_pSecFn->FreeContextBuffer(SecurityPackage);
13313498266Sopenharmony_ci
13413498266Sopenharmony_ci    /* Allocate our response buffer */
13513498266Sopenharmony_ci    krb5->output_token = malloc(krb5->token_max);
13613498266Sopenharmony_ci    if(!krb5->output_token)
13713498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
13813498266Sopenharmony_ci  }
13913498266Sopenharmony_ci
14013498266Sopenharmony_ci  if(!krb5->credentials) {
14113498266Sopenharmony_ci    /* Do we have credentials to use or are we using single sign-on? */
14213498266Sopenharmony_ci    if(userp && *userp) {
14313498266Sopenharmony_ci      /* Populate our identity structure */
14413498266Sopenharmony_ci      result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
14513498266Sopenharmony_ci      if(result)
14613498266Sopenharmony_ci        return result;
14713498266Sopenharmony_ci
14813498266Sopenharmony_ci      /* Allow proper cleanup of the identity structure */
14913498266Sopenharmony_ci      krb5->p_identity = &krb5->identity;
15013498266Sopenharmony_ci    }
15113498266Sopenharmony_ci    else
15213498266Sopenharmony_ci      /* Use the current Windows user */
15313498266Sopenharmony_ci      krb5->p_identity = NULL;
15413498266Sopenharmony_ci
15513498266Sopenharmony_ci    /* Allocate our credentials handle */
15613498266Sopenharmony_ci    krb5->credentials = calloc(1, sizeof(CredHandle));
15713498266Sopenharmony_ci    if(!krb5->credentials)
15813498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
15913498266Sopenharmony_ci
16013498266Sopenharmony_ci    /* Acquire our credentials handle */
16113498266Sopenharmony_ci    status = s_pSecFn->AcquireCredentialsHandle(NULL,
16213498266Sopenharmony_ci                                                (TCHAR *)
16313498266Sopenharmony_ci                                                TEXT(SP_NAME_KERBEROS),
16413498266Sopenharmony_ci                                                SECPKG_CRED_OUTBOUND, NULL,
16513498266Sopenharmony_ci                                                krb5->p_identity, NULL, NULL,
16613498266Sopenharmony_ci                                                krb5->credentials, &expiry);
16713498266Sopenharmony_ci    if(status != SEC_E_OK)
16813498266Sopenharmony_ci      return CURLE_LOGIN_DENIED;
16913498266Sopenharmony_ci
17013498266Sopenharmony_ci    /* Allocate our new context handle */
17113498266Sopenharmony_ci    krb5->context = calloc(1, sizeof(CtxtHandle));
17213498266Sopenharmony_ci    if(!krb5->context)
17313498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
17413498266Sopenharmony_ci  }
17513498266Sopenharmony_ci
17613498266Sopenharmony_ci  if(chlg) {
17713498266Sopenharmony_ci    if(!Curl_bufref_len(chlg)) {
17813498266Sopenharmony_ci      infof(data, "GSSAPI handshake failure (empty challenge message)");
17913498266Sopenharmony_ci      return CURLE_BAD_CONTENT_ENCODING;
18013498266Sopenharmony_ci    }
18113498266Sopenharmony_ci
18213498266Sopenharmony_ci    /* Setup the challenge "input" security buffer */
18313498266Sopenharmony_ci    chlg_desc.ulVersion = SECBUFFER_VERSION;
18413498266Sopenharmony_ci    chlg_desc.cBuffers  = 1;
18513498266Sopenharmony_ci    chlg_desc.pBuffers  = &chlg_buf;
18613498266Sopenharmony_ci    chlg_buf.BufferType = SECBUFFER_TOKEN;
18713498266Sopenharmony_ci    chlg_buf.pvBuffer   = (void *) Curl_bufref_ptr(chlg);
18813498266Sopenharmony_ci    chlg_buf.cbBuffer   = curlx_uztoul(Curl_bufref_len(chlg));
18913498266Sopenharmony_ci  }
19013498266Sopenharmony_ci
19113498266Sopenharmony_ci  /* Setup the response "output" security buffer */
19213498266Sopenharmony_ci  resp_desc.ulVersion = SECBUFFER_VERSION;
19313498266Sopenharmony_ci  resp_desc.cBuffers  = 1;
19413498266Sopenharmony_ci  resp_desc.pBuffers  = &resp_buf;
19513498266Sopenharmony_ci  resp_buf.BufferType = SECBUFFER_TOKEN;
19613498266Sopenharmony_ci  resp_buf.pvBuffer   = krb5->output_token;
19713498266Sopenharmony_ci  resp_buf.cbBuffer   = curlx_uztoul(krb5->token_max);
19813498266Sopenharmony_ci
19913498266Sopenharmony_ci  /* Generate our challenge-response message */
20013498266Sopenharmony_ci  status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
20113498266Sopenharmony_ci                                               chlg ? krb5->context : NULL,
20213498266Sopenharmony_ci                                               krb5->spn,
20313498266Sopenharmony_ci                                               (mutual_auth ?
20413498266Sopenharmony_ci                                                ISC_REQ_MUTUAL_AUTH : 0),
20513498266Sopenharmony_ci                                               0, SECURITY_NATIVE_DREP,
20613498266Sopenharmony_ci                                               chlg ? &chlg_desc : NULL, 0,
20713498266Sopenharmony_ci                                               &context,
20813498266Sopenharmony_ci                                               &resp_desc, &attrs,
20913498266Sopenharmony_ci                                               &expiry);
21013498266Sopenharmony_ci
21113498266Sopenharmony_ci  if(status == SEC_E_INSUFFICIENT_MEMORY)
21213498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
21313498266Sopenharmony_ci
21413498266Sopenharmony_ci  if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
21513498266Sopenharmony_ci    return CURLE_AUTH_ERROR;
21613498266Sopenharmony_ci
21713498266Sopenharmony_ci  if(memcmp(&context, krb5->context, sizeof(context))) {
21813498266Sopenharmony_ci    s_pSecFn->DeleteSecurityContext(krb5->context);
21913498266Sopenharmony_ci
22013498266Sopenharmony_ci    memcpy(krb5->context, &context, sizeof(context));
22113498266Sopenharmony_ci  }
22213498266Sopenharmony_ci
22313498266Sopenharmony_ci  if(resp_buf.cbBuffer) {
22413498266Sopenharmony_ci    result = Curl_bufref_memdup(out, resp_buf.pvBuffer, resp_buf.cbBuffer);
22513498266Sopenharmony_ci  }
22613498266Sopenharmony_ci  else if(mutual_auth)
22713498266Sopenharmony_ci    Curl_bufref_set(out, "", 0, NULL);
22813498266Sopenharmony_ci  else
22913498266Sopenharmony_ci    Curl_bufref_set(out, NULL, 0, NULL);
23013498266Sopenharmony_ci
23113498266Sopenharmony_ci  return result;
23213498266Sopenharmony_ci}
23313498266Sopenharmony_ci
23413498266Sopenharmony_ci/*
23513498266Sopenharmony_ci * Curl_auth_create_gssapi_security_message()
23613498266Sopenharmony_ci *
23713498266Sopenharmony_ci * This is used to generate an already encoded GSSAPI (Kerberos V5) security
23813498266Sopenharmony_ci * token message ready for sending to the recipient.
23913498266Sopenharmony_ci *
24013498266Sopenharmony_ci * Parameters:
24113498266Sopenharmony_ci *
24213498266Sopenharmony_ci * data    [in]     - The session handle.
24313498266Sopenharmony_ci * authzid [in]     - The authorization identity if some.
24413498266Sopenharmony_ci * chlg    [in]     - The optional challenge message.
24513498266Sopenharmony_ci * krb5    [in/out] - The Kerberos 5 data struct being used and modified.
24613498266Sopenharmony_ci * out     [out]    - The result storage.
24713498266Sopenharmony_ci *
24813498266Sopenharmony_ci * Returns CURLE_OK on success.
24913498266Sopenharmony_ci */
25013498266Sopenharmony_ciCURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
25113498266Sopenharmony_ci                                                  const char *authzid,
25213498266Sopenharmony_ci                                                  const struct bufref *chlg,
25313498266Sopenharmony_ci                                                  struct kerberos5data *krb5,
25413498266Sopenharmony_ci                                                  struct bufref *out)
25513498266Sopenharmony_ci{
25613498266Sopenharmony_ci  size_t offset = 0;
25713498266Sopenharmony_ci  size_t messagelen = 0;
25813498266Sopenharmony_ci  size_t appdatalen = 0;
25913498266Sopenharmony_ci  unsigned char *trailer = NULL;
26013498266Sopenharmony_ci  unsigned char *message = NULL;
26113498266Sopenharmony_ci  unsigned char *padding = NULL;
26213498266Sopenharmony_ci  unsigned char *appdata = NULL;
26313498266Sopenharmony_ci  SecBuffer input_buf[2];
26413498266Sopenharmony_ci  SecBuffer wrap_buf[3];
26513498266Sopenharmony_ci  SecBufferDesc input_desc;
26613498266Sopenharmony_ci  SecBufferDesc wrap_desc;
26713498266Sopenharmony_ci  unsigned char *indata;
26813498266Sopenharmony_ci  unsigned long qop = 0;
26913498266Sopenharmony_ci  unsigned long sec_layer = 0;
27013498266Sopenharmony_ci  unsigned long max_size = 0;
27113498266Sopenharmony_ci  SecPkgContext_Sizes sizes;
27213498266Sopenharmony_ci  SECURITY_STATUS status;
27313498266Sopenharmony_ci
27413498266Sopenharmony_ci#if defined(CURL_DISABLE_VERBOSE_STRINGS)
27513498266Sopenharmony_ci  (void) data;
27613498266Sopenharmony_ci#endif
27713498266Sopenharmony_ci
27813498266Sopenharmony_ci  /* Ensure we have a valid challenge message */
27913498266Sopenharmony_ci  if(!Curl_bufref_len(chlg)) {
28013498266Sopenharmony_ci    infof(data, "GSSAPI handshake failure (empty security message)");
28113498266Sopenharmony_ci    return CURLE_BAD_CONTENT_ENCODING;
28213498266Sopenharmony_ci  }
28313498266Sopenharmony_ci
28413498266Sopenharmony_ci  /* Get our response size information */
28513498266Sopenharmony_ci  status = s_pSecFn->QueryContextAttributes(krb5->context,
28613498266Sopenharmony_ci                                            SECPKG_ATTR_SIZES,
28713498266Sopenharmony_ci                                            &sizes);
28813498266Sopenharmony_ci
28913498266Sopenharmony_ci  if(status == SEC_E_INSUFFICIENT_MEMORY)
29013498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
29113498266Sopenharmony_ci
29213498266Sopenharmony_ci  if(status != SEC_E_OK)
29313498266Sopenharmony_ci    return CURLE_AUTH_ERROR;
29413498266Sopenharmony_ci
29513498266Sopenharmony_ci  /* Setup the "input" security buffer */
29613498266Sopenharmony_ci  input_desc.ulVersion = SECBUFFER_VERSION;
29713498266Sopenharmony_ci  input_desc.cBuffers = 2;
29813498266Sopenharmony_ci  input_desc.pBuffers = input_buf;
29913498266Sopenharmony_ci  input_buf[0].BufferType = SECBUFFER_STREAM;
30013498266Sopenharmony_ci  input_buf[0].pvBuffer = (void *) Curl_bufref_ptr(chlg);
30113498266Sopenharmony_ci  input_buf[0].cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
30213498266Sopenharmony_ci  input_buf[1].BufferType = SECBUFFER_DATA;
30313498266Sopenharmony_ci  input_buf[1].pvBuffer = NULL;
30413498266Sopenharmony_ci  input_buf[1].cbBuffer = 0;
30513498266Sopenharmony_ci
30613498266Sopenharmony_ci  /* Decrypt the inbound challenge and obtain the qop */
30713498266Sopenharmony_ci  status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
30813498266Sopenharmony_ci  if(status != SEC_E_OK) {
30913498266Sopenharmony_ci    infof(data, "GSSAPI handshake failure (empty security message)");
31013498266Sopenharmony_ci    return CURLE_BAD_CONTENT_ENCODING;
31113498266Sopenharmony_ci  }
31213498266Sopenharmony_ci
31313498266Sopenharmony_ci  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
31413498266Sopenharmony_ci  if(input_buf[1].cbBuffer != 4) {
31513498266Sopenharmony_ci    infof(data, "GSSAPI handshake failure (invalid security data)");
31613498266Sopenharmony_ci    return CURLE_BAD_CONTENT_ENCODING;
31713498266Sopenharmony_ci  }
31813498266Sopenharmony_ci
31913498266Sopenharmony_ci  /* Extract the security layer and the maximum message size */
32013498266Sopenharmony_ci  indata = input_buf[1].pvBuffer;
32113498266Sopenharmony_ci  sec_layer = indata[0];
32213498266Sopenharmony_ci  max_size = ((unsigned long)indata[1] << 16) |
32313498266Sopenharmony_ci             ((unsigned long)indata[2] << 8) | indata[3];
32413498266Sopenharmony_ci
32513498266Sopenharmony_ci  /* Free the challenge as it is not required anymore */
32613498266Sopenharmony_ci  s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
32713498266Sopenharmony_ci
32813498266Sopenharmony_ci  /* Process the security layer */
32913498266Sopenharmony_ci  if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
33013498266Sopenharmony_ci    infof(data, "GSSAPI handshake failure (invalid security layer)");
33113498266Sopenharmony_ci    return CURLE_BAD_CONTENT_ENCODING;
33213498266Sopenharmony_ci  }
33313498266Sopenharmony_ci  sec_layer &= KERB_WRAP_NO_ENCRYPT;  /* We do not support a security layer */
33413498266Sopenharmony_ci
33513498266Sopenharmony_ci  /* Process the maximum message size the server can receive */
33613498266Sopenharmony_ci  if(max_size > 0) {
33713498266Sopenharmony_ci    /* The server has told us it supports a maximum receive buffer, however, as
33813498266Sopenharmony_ci       we don't require one unless we are encrypting data, we tell the server
33913498266Sopenharmony_ci       our receive buffer is zero. */
34013498266Sopenharmony_ci    max_size = 0;
34113498266Sopenharmony_ci  }
34213498266Sopenharmony_ci
34313498266Sopenharmony_ci  /* Allocate the trailer */
34413498266Sopenharmony_ci  trailer = malloc(sizes.cbSecurityTrailer);
34513498266Sopenharmony_ci  if(!trailer)
34613498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
34713498266Sopenharmony_ci
34813498266Sopenharmony_ci  /* Allocate our message */
34913498266Sopenharmony_ci  messagelen = 4;
35013498266Sopenharmony_ci  if(authzid)
35113498266Sopenharmony_ci    messagelen += strlen(authzid);
35213498266Sopenharmony_ci  message = malloc(messagelen);
35313498266Sopenharmony_ci  if(!message) {
35413498266Sopenharmony_ci    free(trailer);
35513498266Sopenharmony_ci
35613498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
35713498266Sopenharmony_ci  }
35813498266Sopenharmony_ci
35913498266Sopenharmony_ci  /* Populate the message with the security layer and client supported receive
36013498266Sopenharmony_ci     message size. */
36113498266Sopenharmony_ci  message[0] = sec_layer & 0xFF;
36213498266Sopenharmony_ci  message[1] = (max_size >> 16) & 0xFF;
36313498266Sopenharmony_ci  message[2] = (max_size >> 8) & 0xFF;
36413498266Sopenharmony_ci  message[3] = max_size & 0xFF;
36513498266Sopenharmony_ci
36613498266Sopenharmony_ci  /* If given, append the authorization identity. */
36713498266Sopenharmony_ci
36813498266Sopenharmony_ci  if(authzid && *authzid)
36913498266Sopenharmony_ci    memcpy(message + 4, authzid, messagelen - 4);
37013498266Sopenharmony_ci
37113498266Sopenharmony_ci  /* Allocate the padding */
37213498266Sopenharmony_ci  padding = malloc(sizes.cbBlockSize);
37313498266Sopenharmony_ci  if(!padding) {
37413498266Sopenharmony_ci    free(message);
37513498266Sopenharmony_ci    free(trailer);
37613498266Sopenharmony_ci
37713498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
37813498266Sopenharmony_ci  }
37913498266Sopenharmony_ci
38013498266Sopenharmony_ci  /* Setup the "authentication data" security buffer */
38113498266Sopenharmony_ci  wrap_desc.ulVersion    = SECBUFFER_VERSION;
38213498266Sopenharmony_ci  wrap_desc.cBuffers     = 3;
38313498266Sopenharmony_ci  wrap_desc.pBuffers     = wrap_buf;
38413498266Sopenharmony_ci  wrap_buf[0].BufferType = SECBUFFER_TOKEN;
38513498266Sopenharmony_ci  wrap_buf[0].pvBuffer   = trailer;
38613498266Sopenharmony_ci  wrap_buf[0].cbBuffer   = sizes.cbSecurityTrailer;
38713498266Sopenharmony_ci  wrap_buf[1].BufferType = SECBUFFER_DATA;
38813498266Sopenharmony_ci  wrap_buf[1].pvBuffer   = message;
38913498266Sopenharmony_ci  wrap_buf[1].cbBuffer   = curlx_uztoul(messagelen);
39013498266Sopenharmony_ci  wrap_buf[2].BufferType = SECBUFFER_PADDING;
39113498266Sopenharmony_ci  wrap_buf[2].pvBuffer   = padding;
39213498266Sopenharmony_ci  wrap_buf[2].cbBuffer   = sizes.cbBlockSize;
39313498266Sopenharmony_ci
39413498266Sopenharmony_ci  /* Encrypt the data */
39513498266Sopenharmony_ci  status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
39613498266Sopenharmony_ci                                    &wrap_desc, 0);
39713498266Sopenharmony_ci  if(status != SEC_E_OK) {
39813498266Sopenharmony_ci    free(padding);
39913498266Sopenharmony_ci    free(message);
40013498266Sopenharmony_ci    free(trailer);
40113498266Sopenharmony_ci
40213498266Sopenharmony_ci    if(status == SEC_E_INSUFFICIENT_MEMORY)
40313498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
40413498266Sopenharmony_ci
40513498266Sopenharmony_ci    return CURLE_AUTH_ERROR;
40613498266Sopenharmony_ci  }
40713498266Sopenharmony_ci
40813498266Sopenharmony_ci  /* Allocate the encryption (wrap) buffer */
40913498266Sopenharmony_ci  appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
41013498266Sopenharmony_ci               wrap_buf[2].cbBuffer;
41113498266Sopenharmony_ci  appdata = malloc(appdatalen);
41213498266Sopenharmony_ci  if(!appdata) {
41313498266Sopenharmony_ci    free(padding);
41413498266Sopenharmony_ci    free(message);
41513498266Sopenharmony_ci    free(trailer);
41613498266Sopenharmony_ci
41713498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
41813498266Sopenharmony_ci  }
41913498266Sopenharmony_ci
42013498266Sopenharmony_ci  /* Populate the encryption buffer */
42113498266Sopenharmony_ci  memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
42213498266Sopenharmony_ci  offset += wrap_buf[0].cbBuffer;
42313498266Sopenharmony_ci  memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
42413498266Sopenharmony_ci  offset += wrap_buf[1].cbBuffer;
42513498266Sopenharmony_ci  memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
42613498266Sopenharmony_ci
42713498266Sopenharmony_ci  /* Free all of our local buffers */
42813498266Sopenharmony_ci  free(padding);
42913498266Sopenharmony_ci  free(message);
43013498266Sopenharmony_ci  free(trailer);
43113498266Sopenharmony_ci
43213498266Sopenharmony_ci  /* Return the response. */
43313498266Sopenharmony_ci  Curl_bufref_set(out, appdata, appdatalen, curl_free);
43413498266Sopenharmony_ci  return CURLE_OK;
43513498266Sopenharmony_ci}
43613498266Sopenharmony_ci
43713498266Sopenharmony_ci/*
43813498266Sopenharmony_ci * Curl_auth_cleanup_gssapi()
43913498266Sopenharmony_ci *
44013498266Sopenharmony_ci * This is used to clean up the GSSAPI (Kerberos V5) specific data.
44113498266Sopenharmony_ci *
44213498266Sopenharmony_ci * Parameters:
44313498266Sopenharmony_ci *
44413498266Sopenharmony_ci * krb5     [in/out] - The Kerberos 5 data struct being cleaned up.
44513498266Sopenharmony_ci *
44613498266Sopenharmony_ci */
44713498266Sopenharmony_civoid Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
44813498266Sopenharmony_ci{
44913498266Sopenharmony_ci  /* Free our security context */
45013498266Sopenharmony_ci  if(krb5->context) {
45113498266Sopenharmony_ci    s_pSecFn->DeleteSecurityContext(krb5->context);
45213498266Sopenharmony_ci    free(krb5->context);
45313498266Sopenharmony_ci    krb5->context = NULL;
45413498266Sopenharmony_ci  }
45513498266Sopenharmony_ci
45613498266Sopenharmony_ci  /* Free our credentials handle */
45713498266Sopenharmony_ci  if(krb5->credentials) {
45813498266Sopenharmony_ci    s_pSecFn->FreeCredentialsHandle(krb5->credentials);
45913498266Sopenharmony_ci    free(krb5->credentials);
46013498266Sopenharmony_ci    krb5->credentials = NULL;
46113498266Sopenharmony_ci  }
46213498266Sopenharmony_ci
46313498266Sopenharmony_ci  /* Free our identity */
46413498266Sopenharmony_ci  Curl_sspi_free_identity(krb5->p_identity);
46513498266Sopenharmony_ci  krb5->p_identity = NULL;
46613498266Sopenharmony_ci
46713498266Sopenharmony_ci  /* Free the SPN and output token */
46813498266Sopenharmony_ci  Curl_safefree(krb5->spn);
46913498266Sopenharmony_ci  Curl_safefree(krb5->output_token);
47013498266Sopenharmony_ci
47113498266Sopenharmony_ci  /* Reset any variables */
47213498266Sopenharmony_ci  krb5->token_max = 0;
47313498266Sopenharmony_ci}
47413498266Sopenharmony_ci
47513498266Sopenharmony_ci#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5 */
476