diff options
-rw-r--r-- | lib/curl_sasl_gssapi.c | 128 |
1 files changed, 122 insertions, 6 deletions
diff --git a/lib/curl_sasl_gssapi.c b/lib/curl_sasl_gssapi.c index 5744c0237..0c1eaf9e1 100644 --- a/lib/curl_sasl_gssapi.c +++ b/lib/curl_sasl_gssapi.c @@ -31,6 +31,10 @@ #define NCOMPAT 1 #endif +#define GSSAUTH_P_NONE 1 +#define GSSAUTH_P_INTEGRITY 2 +#define GSSAUTH_P_PRIVACY 4 + #include <curl/curl.h> #include "curl_sasl.h" @@ -207,13 +211,125 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, char **outptr, size_t *outlen) { - (void) data; - (void) chlg64; - (void) krb5; - (void) outptr; - (void) outlen; + CURLcode result = CURLE_OK; + size_t chlglen = 0; + size_t messagelen = 0; + unsigned char *chlg = NULL; + unsigned char *message = NULL; + OM_uint32 gss_status; + OM_uint32 gss_major_status; + OM_uint32 gss_minor_status; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + unsigned int indata = 0; + unsigned int outdata = 0; + gss_qop_t qop = GSS_C_QOP_DEFAULT; + unsigned int sec_layer = 0; + unsigned int max_size = 0; + char user_name[] = "dummy.user"; /* FIX: Use real 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; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + + /* Decrypt the inbound challenge and obtain the qop */ + gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token, + &output_token, NULL, &qop); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_unwrap() failed: "); + + Curl_safefree(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } - return CURLE_NOT_BUILT_IN; + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(output_token.length != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)\n"); + + Curl_safefree(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Copy the data out and free the challenge as it is not required anymore */ + memcpy(&indata, output_token.value, 4); + gss_release_buffer(&gss_status, &output_token); + Curl_safefree(chlg); + + /* Extract the security layer */ + sec_layer = indata & 0x000000FF; + if(!(sec_layer & GSSAUTH_P_NONE)) { + 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 our message */ + messagelen = sizeof(outdata) + strlen(user_name) + 1; + message = malloc(messagelen); + if(!message) + 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); + + /* Setup the "authentication data" security buffer */ + input_token.value = message; + input_token.length = messagelen; + + /* Encrypt the data */ + gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0, + GSS_C_QOP_DEFAULT, &input_token, NULL, + &output_token); + if(GSS_ERROR(gss_major_status)) { + Curl_gss_log_error(data, gss_minor_status, "gss_wrap() failed: "); + + Curl_safefree(message); + + return CURLE_OUT_OF_MEMORY; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token.value, + output_token.length, outptr, outlen); + + /* Free the output buffer */ + gss_release_buffer(&gss_status, &output_token); + + /* Free the message buffer */ + Curl_safefree(message); + + return result; } void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) |