Loading lib/Makefile.inc +3 −3 Original line number Diff line number Diff line Loading @@ -21,7 +21,8 @@ ########################################################################### LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ vauth/digest.c vauth/digest_sspi.c vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ vauth/krb5_sspi.c LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h Loading Loading @@ -52,8 +53,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c \ hostcheck.c conncache.c pipeline.c dotdot.c x509asn1.c \ http2.c curl_sasl_sspi.c smb.c curl_sasl_gssapi.c curl_endian.c \ curl_des.c http2.c curl_sasl_sspi.c smb.c curl_endian.c curl_des.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ Loading lib/Makefile.vc6 +2 −1 Original line number Diff line number Diff line Loading @@ -546,7 +546,6 @@ X_OBJS= \ $(DIROBJ)\curl_ntlm_wb.obj \ $(DIROBJ)\curl_rtmp.obj \ $(DIROBJ)\curl_sasl.obj \ $(DIROBJ)\curl_sasl_gssapi.obj \ $(DIROBJ)\curl_sasl_sspi.obj \ $(DIROBJ)\curl_sspi.obj \ $(DIROBJ)\curl_threads.obj \ Loading Loading @@ -625,6 +624,8 @@ X_OBJS= \ $(DIROBJ)\cram.obj \ $(DIROBJ)\digest.obj \ $(DIROBJ)\digest_sspi.obj \ $(DIROBJ)\krb5_gssapi.obj \ $(DIROBJ)\krb5_sspi.obj \ $(DIROBJ)\vtls.obj \ $(DIROBJ)\openssl.obj \ $(DIROBJ)\strdup.obj \ Loading lib/curl_sasl.h +0 −28 Original line number Diff line number Diff line Loading @@ -31,10 +31,6 @@ struct connectdata; struct ntlmdata; #endif #if defined(USE_KERBEROS5) struct kerberos5data; #endif /* Authentication mechanism flags */ #define SASL_MECH_LOGIN (1 << 0) #define SASL_MECH_PLAIN (1 << 1) Loading Loading @@ -147,30 +143,6 @@ void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm); #endif /* USE_NTLM */ #if defined(USE_KERBEROS5) /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token message */ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, const char *userp, const char *passwdp, const char *service, const bool mutual, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security token message */ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, const char *input, struct kerberos5data *krb5, char **outptr, size_t *outlen); /* This is used to clean up the gssapi specific data */ void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); #endif /* USE_KERBEROS5 */ /* This is used to cleanup any libraries or curl modules used by the sasl functions */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); Loading lib/curl_sasl_sspi.c +0 −445 Original line number Diff line number Diff line Loading @@ -322,449 +322,4 @@ void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) } #endif /* USE_NTLM */ #if defined(USE_KERBEROS5) /* * Curl_sasl_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token * message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. * service [in] - The service type such as www, smtp, pop or imap. * mutual_auth [in] - Flag specifing whether or not mutual authentication * is enabled. * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, const char *userp, const char *passwdp, const char *service, const bool mutual_auth, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; CtxtHandle context; PSecPkgInfo SecurityPackage; SecBuffer chlg_buf; SecBuffer resp_buf; SecBufferDesc chlg_desc; SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ if(!krb5->credentials) { /* Query the security package for Kerberos */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_KERBEROS), &SecurityPackage); if(status != SEC_E_OK) { return CURLE_NOT_BUILT_IN; } krb5->token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate our response buffer */ krb5->output_token = malloc(krb5->token_max); if(!krb5->output_token) return CURLE_OUT_OF_MEMORY; /* Generate our SPN */ krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); if(!krb5->spn) return CURLE_OUT_OF_MEMORY; if(userp && *userp) { /* Populate our identity structure */ result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); if(result) return result; /* Allow proper cleanup of the identity structure */ krb5->p_identity = &krb5->identity; } else /* Use the current Windows user */ krb5->p_identity = NULL; /* Allocate our credentials handle */ krb5->credentials = malloc(sizeof(CredHandle)); if(!krb5->credentials) return CURLE_OUT_OF_MEMORY; memset(krb5->credentials, 0, sizeof(CredHandle)); /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT(SP_NAME_KERBEROS), SECPKG_CRED_OUTBOUND, NULL, krb5->p_identity, NULL, NULL, krb5->credentials, &expiry); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; /* Allocate our new context handle */ krb5->context = malloc(sizeof(CtxtHandle)); if(!krb5->context) return CURLE_OUT_OF_MEMORY; memset(krb5->context, 0, sizeof(CtxtHandle)); } else { /* Decode the base-64 encoded challenge message */ if(strlen(chlg64) && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty challenge message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Setup the challenge "input" security buffer */ chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 1; chlg_desc.pBuffers = &chlg_buf; chlg_buf.BufferType = SECBUFFER_TOKEN; chlg_buf.pvBuffer = chlg; chlg_buf.cbBuffer = curlx_uztoul(chlglen); } /* Setup the response "output" security buffer */ resp_desc.ulVersion = SECBUFFER_VERSION; resp_desc.cBuffers = 1; resp_desc.pBuffers = &resp_buf; resp_buf.BufferType = SECBUFFER_TOKEN; resp_buf.pvBuffer = krb5->output_token; resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); /* Generate our challenge-response message */ status = s_pSecFn->InitializeSecurityContext(krb5->credentials, chlg ? krb5->context : NULL, krb5->spn, (mutual_auth ? ISC_REQ_MUTUAL_AUTH : 0), 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, &context, &resp_desc, &attrs, &expiry); if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { free(chlg); return CURLE_RECV_ERROR; } if(memcmp(&context, krb5->context, sizeof(context))) { s_pSecFn->DeleteSecurityContext(krb5->context); memcpy(krb5->context, &context, sizeof(context)); } if(resp_buf.cbBuffer) { /* Base64 encode the response */ result = Curl_base64_encode(data, (char *)resp_buf.pvBuffer, resp_buf.cbBuffer, outptr, outlen); } /* Free the decoded challenge */ free(chlg); return result; } /* * Curl_sasl_create_gssapi_security_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) security * token message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t offset = 0; size_t chlglen = 0; size_t messagelen = 0; size_t appdatalen = 0; unsigned char *chlg = NULL; unsigned char *trailer = NULL; unsigned char *message = NULL; unsigned char *padding = NULL; unsigned char *appdata = NULL; SecBuffer input_buf[2]; SecBuffer wrap_buf[3]; SecBufferDesc input_desc; SecBufferDesc wrap_desc; unsigned long indata = 0; unsigned long outdata = 0; unsigned long qop = 0; unsigned long sec_layer = 0; unsigned long max_size = 0; SecPkgContext_Sizes sizes; SecPkgCredentials_Names names; SECURITY_STATUS status; char *user_name; /* Decode the base-64 encoded input message */ if(strlen(chlg64) && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty security message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Get our response size information */ status = s_pSecFn->QueryContextAttributes(krb5->context, SECPKG_ATTR_SIZES, &sizes); if(status != SEC_E_OK) { free(chlg); return CURLE_OUT_OF_MEMORY; } /* Get the fully qualified username back from the context */ status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, SECPKG_CRED_ATTR_NAMES, &names); if(status != SEC_E_OK) { free(chlg); return CURLE_RECV_ERROR; } /* Setup the "input" security buffer */ input_desc.ulVersion = SECBUFFER_VERSION; input_desc.cBuffers = 2; input_desc.pBuffers = input_buf; input_buf[0].BufferType = SECBUFFER_STREAM; input_buf[0].pvBuffer = chlg; input_buf[0].cbBuffer = curlx_uztoul(chlglen); input_buf[1].BufferType = SECBUFFER_DATA; input_buf[1].pvBuffer = NULL; input_buf[1].cbBuffer = 0; /* Decrypt the inbound challenge and obtain the qop */ status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); if(status != SEC_E_OK) { infof(data, "GSSAPI handshake failure (empty security message)\n"); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ if(input_buf[1].cbBuffer != 4) { infof(data, "GSSAPI handshake failure (invalid security data)\n"); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* 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); free(chlg); /* Extract the security layer */ sec_layer = indata & 0x000000FF; if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { infof(data, "GSSAPI handshake failure (invalid security layer)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Extract the maximum message size the server can receive */ max_size = ntohl(indata & 0xFFFFFF00); if(max_size > 0) { /* The server has told us it supports a maximum receive buffer, however, as we don't require one unless we are encrypting data, we tell the server our receive buffer is zero. */ max_size = 0; } /* Allocate the trailer */ trailer = malloc(sizes.cbSecurityTrailer); if(!trailer) return CURLE_OUT_OF_MEMORY; /* Convert the user name to UTF8 when operating with Unicode */ user_name = Curl_convert_tchar_to_UTF8(names.sUserName); if(!user_name) { free(trailer); return CURLE_OUT_OF_MEMORY; } /* Allocate our message */ messagelen = sizeof(outdata) + strlen(user_name) + 1; message = malloc(messagelen); if(!message) { free(trailer); Curl_unicodefree(user_name); return CURLE_OUT_OF_MEMORY; } /* Populate the message with the security layer, client supported receive message size and authorization identity including the 0x00 based terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization identity is not terminated with the zero-valued (%x00) octet." it seems necessary to include it. */ outdata = htonl(max_size) | sec_layer; memcpy(message, &outdata, sizeof(outdata)); strcpy((char *) message + sizeof(outdata), user_name); Curl_unicodefree(user_name); /* Allocate the padding */ padding = malloc(sizes.cbBlockSize); if(!padding) { free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Setup the "authentication data" security buffer */ wrap_desc.ulVersion = SECBUFFER_VERSION; wrap_desc.cBuffers = 3; wrap_desc.pBuffers = wrap_buf; wrap_buf[0].BufferType = SECBUFFER_TOKEN; wrap_buf[0].pvBuffer = trailer; wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; wrap_buf[1].BufferType = SECBUFFER_DATA; wrap_buf[1].pvBuffer = message; wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); wrap_buf[2].BufferType = SECBUFFER_PADDING; wrap_buf[2].pvBuffer = padding; wrap_buf[2].cbBuffer = sizes.cbBlockSize; /* Encrypt the data */ status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, &wrap_desc, 0); if(status != SEC_E_OK) { free(padding); free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Allocate the encryption (wrap) buffer */ appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + wrap_buf[2].cbBuffer; appdata = malloc(appdatalen); if(!appdata) { free(padding); free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Populate the encryption buffer */ memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); offset += wrap_buf[0].cbBuffer; memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); offset += wrap_buf[1].cbBuffer; memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); /* Base64 encode the response */ result = Curl_base64_encode(data, (char *)appdata, appdatalen, outptr, outlen); /* Free all of our local buffers */ free(appdata); free(padding); free(message); free(trailer); return result; } /* * Curl_sasl_gssapi_cleanup() * * This is used to clean up the GSSAPI (Kerberos V5) specific data. * * Parameters: * * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. * */ void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) { /* Free our security context */ if(krb5->context) { s_pSecFn->DeleteSecurityContext(krb5->context); free(krb5->context); krb5->context = NULL; } /* Free our credentials handle */ if(krb5->credentials) { s_pSecFn->FreeCredentialsHandle(krb5->credentials); free(krb5->credentials); krb5->credentials = NULL; } /* Free our identity */ Curl_sspi_free_identity(krb5->p_identity); krb5->p_identity = NULL; /* Free the SPN and output token */ Curl_safefree(krb5->spn); Curl_safefree(krb5->output_token); /* Reset any variables */ krb5->token_max = 0; } #endif /* USE_KERBEROS5 */ #endif /* USE_WINDOWS_SSPI */ lib/curl_sasl_gssapi.c→lib/vauth/krb5_gssapi.c +0 −0 File moved. View file Loading
lib/Makefile.inc +3 −3 Original line number Diff line number Diff line Loading @@ -21,7 +21,8 @@ ########################################################################### LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ vauth/digest.c vauth/digest_sspi.c vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ vauth/krb5_sspi.c LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h Loading Loading @@ -52,8 +53,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c \ hostcheck.c conncache.c pipeline.c dotdot.c x509asn1.c \ http2.c curl_sasl_sspi.c smb.c curl_sasl_gssapi.c curl_endian.c \ curl_des.c http2.c curl_sasl_sspi.c smb.c curl_endian.c curl_des.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ Loading
lib/Makefile.vc6 +2 −1 Original line number Diff line number Diff line Loading @@ -546,7 +546,6 @@ X_OBJS= \ $(DIROBJ)\curl_ntlm_wb.obj \ $(DIROBJ)\curl_rtmp.obj \ $(DIROBJ)\curl_sasl.obj \ $(DIROBJ)\curl_sasl_gssapi.obj \ $(DIROBJ)\curl_sasl_sspi.obj \ $(DIROBJ)\curl_sspi.obj \ $(DIROBJ)\curl_threads.obj \ Loading Loading @@ -625,6 +624,8 @@ X_OBJS= \ $(DIROBJ)\cram.obj \ $(DIROBJ)\digest.obj \ $(DIROBJ)\digest_sspi.obj \ $(DIROBJ)\krb5_gssapi.obj \ $(DIROBJ)\krb5_sspi.obj \ $(DIROBJ)\vtls.obj \ $(DIROBJ)\openssl.obj \ $(DIROBJ)\strdup.obj \ Loading
lib/curl_sasl.h +0 −28 Original line number Diff line number Diff line Loading @@ -31,10 +31,6 @@ struct connectdata; struct ntlmdata; #endif #if defined(USE_KERBEROS5) struct kerberos5data; #endif /* Authentication mechanism flags */ #define SASL_MECH_LOGIN (1 << 0) #define SASL_MECH_PLAIN (1 << 1) Loading Loading @@ -147,30 +143,6 @@ void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm); #endif /* USE_NTLM */ #if defined(USE_KERBEROS5) /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token message */ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, const char *userp, const char *passwdp, const char *service, const bool mutual, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security token message */ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, const char *input, struct kerberos5data *krb5, char **outptr, size_t *outlen); /* This is used to clean up the gssapi specific data */ void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); #endif /* USE_KERBEROS5 */ /* This is used to cleanup any libraries or curl modules used by the sasl functions */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); Loading
lib/curl_sasl_sspi.c +0 −445 Original line number Diff line number Diff line Loading @@ -322,449 +322,4 @@ void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) } #endif /* USE_NTLM */ #if defined(USE_KERBEROS5) /* * Curl_sasl_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token * message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. * service [in] - The service type such as www, smtp, pop or imap. * mutual_auth [in] - Flag specifing whether or not mutual authentication * is enabled. * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, const char *userp, const char *passwdp, const char *service, const bool mutual_auth, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; CtxtHandle context; PSecPkgInfo SecurityPackage; SecBuffer chlg_buf; SecBuffer resp_buf; SecBufferDesc chlg_desc; SecBufferDesc resp_desc; SECURITY_STATUS status; unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ if(!krb5->credentials) { /* Query the security package for Kerberos */ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_KERBEROS), &SecurityPackage); if(status != SEC_E_OK) { return CURLE_NOT_BUILT_IN; } krb5->token_max = SecurityPackage->cbMaxToken; /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); /* Allocate our response buffer */ krb5->output_token = malloc(krb5->token_max); if(!krb5->output_token) return CURLE_OUT_OF_MEMORY; /* Generate our SPN */ krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); if(!krb5->spn) return CURLE_OUT_OF_MEMORY; if(userp && *userp) { /* Populate our identity structure */ result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); if(result) return result; /* Allow proper cleanup of the identity structure */ krb5->p_identity = &krb5->identity; } else /* Use the current Windows user */ krb5->p_identity = NULL; /* Allocate our credentials handle */ krb5->credentials = malloc(sizeof(CredHandle)); if(!krb5->credentials) return CURLE_OUT_OF_MEMORY; memset(krb5->credentials, 0, sizeof(CredHandle)); /* Acquire our credentials handle */ status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *) TEXT(SP_NAME_KERBEROS), SECPKG_CRED_OUTBOUND, NULL, krb5->p_identity, NULL, NULL, krb5->credentials, &expiry); if(status != SEC_E_OK) return CURLE_LOGIN_DENIED; /* Allocate our new context handle */ krb5->context = malloc(sizeof(CtxtHandle)); if(!krb5->context) return CURLE_OUT_OF_MEMORY; memset(krb5->context, 0, sizeof(CtxtHandle)); } else { /* Decode the base-64 encoded challenge message */ if(strlen(chlg64) && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty challenge message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Setup the challenge "input" security buffer */ chlg_desc.ulVersion = SECBUFFER_VERSION; chlg_desc.cBuffers = 1; chlg_desc.pBuffers = &chlg_buf; chlg_buf.BufferType = SECBUFFER_TOKEN; chlg_buf.pvBuffer = chlg; chlg_buf.cbBuffer = curlx_uztoul(chlglen); } /* Setup the response "output" security buffer */ resp_desc.ulVersion = SECBUFFER_VERSION; resp_desc.cBuffers = 1; resp_desc.pBuffers = &resp_buf; resp_buf.BufferType = SECBUFFER_TOKEN; resp_buf.pvBuffer = krb5->output_token; resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); /* Generate our challenge-response message */ status = s_pSecFn->InitializeSecurityContext(krb5->credentials, chlg ? krb5->context : NULL, krb5->spn, (mutual_auth ? ISC_REQ_MUTUAL_AUTH : 0), 0, SECURITY_NATIVE_DREP, chlg ? &chlg_desc : NULL, 0, &context, &resp_desc, &attrs, &expiry); if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { free(chlg); return CURLE_RECV_ERROR; } if(memcmp(&context, krb5->context, sizeof(context))) { s_pSecFn->DeleteSecurityContext(krb5->context); memcpy(krb5->context, &context, sizeof(context)); } if(resp_buf.cbBuffer) { /* Base64 encode the response */ result = Curl_base64_encode(data, (char *)resp_buf.pvBuffer, resp_buf.cbBuffer, outptr, outlen); } /* Free the decoded challenge */ free(chlg); return result; } /* * Curl_sasl_create_gssapi_security_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) security * token message ready for sending to the recipient. * * Parameters: * * data [in] - The session handle. * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. * outlen [out] - The length of the output message. * * Returns CURLE_OK on success. */ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, size_t *outlen) { CURLcode result = CURLE_OK; size_t offset = 0; size_t chlglen = 0; size_t messagelen = 0; size_t appdatalen = 0; unsigned char *chlg = NULL; unsigned char *trailer = NULL; unsigned char *message = NULL; unsigned char *padding = NULL; unsigned char *appdata = NULL; SecBuffer input_buf[2]; SecBuffer wrap_buf[3]; SecBufferDesc input_desc; SecBufferDesc wrap_desc; unsigned long indata = 0; unsigned long outdata = 0; unsigned long qop = 0; unsigned long sec_layer = 0; unsigned long max_size = 0; SecPkgContext_Sizes sizes; SecPkgCredentials_Names names; SECURITY_STATUS status; char *user_name; /* Decode the base-64 encoded input message */ if(strlen(chlg64) && *chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; } /* Ensure we have a valid challenge message */ if(!chlg) { infof(data, "GSSAPI handshake failure (empty security message)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Get our response size information */ status = s_pSecFn->QueryContextAttributes(krb5->context, SECPKG_ATTR_SIZES, &sizes); if(status != SEC_E_OK) { free(chlg); return CURLE_OUT_OF_MEMORY; } /* Get the fully qualified username back from the context */ status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, SECPKG_CRED_ATTR_NAMES, &names); if(status != SEC_E_OK) { free(chlg); return CURLE_RECV_ERROR; } /* Setup the "input" security buffer */ input_desc.ulVersion = SECBUFFER_VERSION; input_desc.cBuffers = 2; input_desc.pBuffers = input_buf; input_buf[0].BufferType = SECBUFFER_STREAM; input_buf[0].pvBuffer = chlg; input_buf[0].cbBuffer = curlx_uztoul(chlglen); input_buf[1].BufferType = SECBUFFER_DATA; input_buf[1].pvBuffer = NULL; input_buf[1].cbBuffer = 0; /* Decrypt the inbound challenge and obtain the qop */ status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); if(status != SEC_E_OK) { infof(data, "GSSAPI handshake failure (empty security message)\n"); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ if(input_buf[1].cbBuffer != 4) { infof(data, "GSSAPI handshake failure (invalid security data)\n"); free(chlg); return CURLE_BAD_CONTENT_ENCODING; } /* 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); free(chlg); /* Extract the security layer */ sec_layer = indata & 0x000000FF; if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { infof(data, "GSSAPI handshake failure (invalid security layer)\n"); return CURLE_BAD_CONTENT_ENCODING; } /* Extract the maximum message size the server can receive */ max_size = ntohl(indata & 0xFFFFFF00); if(max_size > 0) { /* The server has told us it supports a maximum receive buffer, however, as we don't require one unless we are encrypting data, we tell the server our receive buffer is zero. */ max_size = 0; } /* Allocate the trailer */ trailer = malloc(sizes.cbSecurityTrailer); if(!trailer) return CURLE_OUT_OF_MEMORY; /* Convert the user name to UTF8 when operating with Unicode */ user_name = Curl_convert_tchar_to_UTF8(names.sUserName); if(!user_name) { free(trailer); return CURLE_OUT_OF_MEMORY; } /* Allocate our message */ messagelen = sizeof(outdata) + strlen(user_name) + 1; message = malloc(messagelen); if(!message) { free(trailer); Curl_unicodefree(user_name); return CURLE_OUT_OF_MEMORY; } /* Populate the message with the security layer, client supported receive message size and authorization identity including the 0x00 based terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization identity is not terminated with the zero-valued (%x00) octet." it seems necessary to include it. */ outdata = htonl(max_size) | sec_layer; memcpy(message, &outdata, sizeof(outdata)); strcpy((char *) message + sizeof(outdata), user_name); Curl_unicodefree(user_name); /* Allocate the padding */ padding = malloc(sizes.cbBlockSize); if(!padding) { free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Setup the "authentication data" security buffer */ wrap_desc.ulVersion = SECBUFFER_VERSION; wrap_desc.cBuffers = 3; wrap_desc.pBuffers = wrap_buf; wrap_buf[0].BufferType = SECBUFFER_TOKEN; wrap_buf[0].pvBuffer = trailer; wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; wrap_buf[1].BufferType = SECBUFFER_DATA; wrap_buf[1].pvBuffer = message; wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); wrap_buf[2].BufferType = SECBUFFER_PADDING; wrap_buf[2].pvBuffer = padding; wrap_buf[2].cbBuffer = sizes.cbBlockSize; /* Encrypt the data */ status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, &wrap_desc, 0); if(status != SEC_E_OK) { free(padding); free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Allocate the encryption (wrap) buffer */ appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + wrap_buf[2].cbBuffer; appdata = malloc(appdatalen); if(!appdata) { free(padding); free(message); free(trailer); return CURLE_OUT_OF_MEMORY; } /* Populate the encryption buffer */ memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); offset += wrap_buf[0].cbBuffer; memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); offset += wrap_buf[1].cbBuffer; memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); /* Base64 encode the response */ result = Curl_base64_encode(data, (char *)appdata, appdatalen, outptr, outlen); /* Free all of our local buffers */ free(appdata); free(padding); free(message); free(trailer); return result; } /* * Curl_sasl_gssapi_cleanup() * * This is used to clean up the GSSAPI (Kerberos V5) specific data. * * Parameters: * * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. * */ void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) { /* Free our security context */ if(krb5->context) { s_pSecFn->DeleteSecurityContext(krb5->context); free(krb5->context); krb5->context = NULL; } /* Free our credentials handle */ if(krb5->credentials) { s_pSecFn->FreeCredentialsHandle(krb5->credentials); free(krb5->credentials); krb5->credentials = NULL; } /* Free our identity */ Curl_sspi_free_identity(krb5->p_identity); krb5->p_identity = NULL; /* Free the SPN and output token */ Curl_safefree(krb5->spn); Curl_safefree(krb5->output_token); /* Reset any variables */ krb5->token_max = 0; } #endif /* USE_KERBEROS5 */ #endif /* USE_WINDOWS_SSPI */