diff options
Diffstat (limited to 'src/transports/auth_negotiate.c')
-rw-r--r-- | src/transports/auth_negotiate.c | 315 |
1 files changed, 0 insertions, 315 deletions
diff --git a/src/transports/auth_negotiate.c b/src/transports/auth_negotiate.c deleted file mode 100644 index 31469933e..000000000 --- a/src/transports/auth_negotiate.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "auth_negotiate.h" - -#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) - -#include "git2.h" -#include "buffer.h" -#include "auth.h" -#include "git2/sys/credential.h" - -#ifdef GIT_GSSFRAMEWORK -#import <GSS/GSS.h> -#elif defined(GIT_GSSAPI) -#include <gssapi.h> -#include <krb5.h> -#endif - -static gss_OID_desc negotiate_oid_spnego = - { 6, (void *) "\x2b\x06\x01\x05\x05\x02" }; -static gss_OID_desc negotiate_oid_krb5 = - { 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; - -static gss_OID negotiate_oids[] = - { &negotiate_oid_spnego, &negotiate_oid_krb5, NULL }; - -typedef struct { - git_http_auth_context parent; - unsigned configured : 1, - complete : 1; - git_buf target; - char *challenge; - gss_ctx_id_t gss_context; - gss_OID oid; -} http_auth_negotiate_context; - -static void negotiate_err_set( - OM_uint32 status_major, - OM_uint32 status_minor, - const char *message) -{ - gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; - OM_uint32 status_display, context = 0; - - if (gss_display_status(&status_display, status_major, GSS_C_GSS_CODE, - GSS_C_NO_OID, &context, &buffer) == GSS_S_COMPLETE) { - git_error_set(GIT_ERROR_NET, "%s: %.*s (%d.%d)", - message, (int)buffer.length, (const char *)buffer.value, - status_major, status_minor); - gss_release_buffer(&status_minor, &buffer); - } else { - git_error_set(GIT_ERROR_NET, "%s: unknown negotiate error (%d.%d)", - message, status_major, status_minor); - } -} - -static int negotiate_set_challenge( - git_http_auth_context *c, - const char *challenge) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(challenge); - GIT_ASSERT(ctx->configured); - - git__free(ctx->challenge); - - ctx->challenge = git__strdup(challenge); - GIT_ERROR_CHECK_ALLOC(ctx->challenge); - - return 0; -} - -static void negotiate_context_dispose(http_auth_negotiate_context *ctx) -{ - OM_uint32 status_minor; - - if (ctx->gss_context != GSS_C_NO_CONTEXT) { - gss_delete_sec_context( - &status_minor, &ctx->gss_context, GSS_C_NO_BUFFER); - ctx->gss_context = GSS_C_NO_CONTEXT; - } - - git_buf_dispose(&ctx->target); - - git__free(ctx->challenge); - ctx->challenge = NULL; -} - -static int negotiate_next_token( - git_buf *buf, - git_http_auth_context *c, - git_credential *cred) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - OM_uint32 status_major, status_minor; - gss_buffer_desc target_buffer = GSS_C_EMPTY_BUFFER, - input_token = GSS_C_EMPTY_BUFFER, - output_token = GSS_C_EMPTY_BUFFER; - gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER; - git_buf input_buf = GIT_BUF_INIT; - gss_name_t server = NULL; - gss_OID mech; - size_t challenge_len; - int error = 0; - - GIT_ASSERT_ARG(buf); - GIT_ASSERT_ARG(ctx); - GIT_ASSERT_ARG(cred); - - GIT_ASSERT(ctx->configured); - GIT_ASSERT(cred->credtype == GIT_CREDENTIAL_DEFAULT); - - if (ctx->complete) - return 0; - - target_buffer.value = (void *)ctx->target.ptr; - target_buffer.length = ctx->target.size; - - status_major = gss_import_name(&status_minor, &target_buffer, - GSS_C_NT_HOSTBASED_SERVICE, &server); - - if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, - "could not parse principal"); - error = -1; - goto done; - } - - challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0; - - if (challenge_len < 9 || memcmp(ctx->challenge, "Negotiate", 9) != 0) { - git_error_set(GIT_ERROR_NET, "server did not request negotiate"); - error = -1; - goto done; - } - - if (challenge_len > 9) { - if (git_buf_decode_base64(&input_buf, - ctx->challenge + 10, challenge_len - 10) < 0) { - git_error_set(GIT_ERROR_NET, "invalid negotiate challenge from server"); - error = -1; - goto done; - } - - input_token.value = input_buf.ptr; - input_token.length = input_buf.size; - input_token_ptr = &input_token; - } else if (ctx->gss_context != GSS_C_NO_CONTEXT) { - negotiate_context_dispose(ctx); - } - - mech = &negotiate_oid_spnego; - - status_major = gss_init_sec_context( - &status_minor, - GSS_C_NO_CREDENTIAL, - &ctx->gss_context, - server, - mech, - GSS_C_DELEG_FLAG | GSS_C_MUTUAL_FLAG, - GSS_C_INDEFINITE, - GSS_C_NO_CHANNEL_BINDINGS, - input_token_ptr, - NULL, - &output_token, - NULL, - NULL); - - if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, "negotiate failure"); - error = -1; - goto done; - } - - /* This message merely told us auth was complete; we do not respond. */ - if (status_major == GSS_S_COMPLETE) { - negotiate_context_dispose(ctx); - ctx->complete = 1; - goto done; - } - - if (output_token.length == 0) { - git_error_set(GIT_ERROR_NET, "GSSAPI did not return token"); - error = -1; - goto done; - } - - git_buf_puts(buf, "Negotiate "); - git_buf_encode_base64(buf, output_token.value, output_token.length); - - if (git_buf_oom(buf)) - error = -1; - -done: - gss_release_name(&status_minor, &server); - gss_release_buffer(&status_minor, (gss_buffer_t) &output_token); - git_buf_dispose(&input_buf); - return error; -} - -static int negotiate_is_complete(git_http_auth_context *c) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - - GIT_ASSERT_ARG(ctx); - - return (ctx->complete == 1); -} - -static void negotiate_context_free(git_http_auth_context *c) -{ - http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c; - - negotiate_context_dispose(ctx); - - ctx->configured = 0; - ctx->complete = 0; - ctx->oid = NULL; - - git__free(ctx); -} - -static int negotiate_init_context( - http_auth_negotiate_context *ctx, - const git_net_url *url) -{ - OM_uint32 status_major, status_minor; - gss_OID item, *oid; - gss_OID_set mechanism_list; - size_t i; - - /* Query supported mechanisms looking for SPNEGO) */ - status_major = gss_indicate_mechs(&status_minor, &mechanism_list); - - if (GSS_ERROR(status_major)) { - negotiate_err_set(status_major, status_minor, - "could not query mechanisms"); - return -1; - } - - if (mechanism_list) { - for (oid = negotiate_oids; *oid; oid++) { - for (i = 0; i < mechanism_list->count; i++) { - item = &mechanism_list->elements[i]; - - if (item->length == (*oid)->length && - memcmp(item->elements, (*oid)->elements, item->length) == 0) { - ctx->oid = *oid; - break; - } - - } - - if (ctx->oid) - break; - } - } - - gss_release_oid_set(&status_minor, &mechanism_list); - - if (!ctx->oid) { - git_error_set(GIT_ERROR_NET, "negotiate authentication is not supported"); - return GIT_EAUTH; - } - - git_buf_puts(&ctx->target, "HTTP@"); - git_buf_puts(&ctx->target, url->host); - - if (git_buf_oom(&ctx->target)) - return -1; - - ctx->gss_context = GSS_C_NO_CONTEXT; - ctx->configured = 1; - - return 0; -} - -int git_http_auth_negotiate( - git_http_auth_context **out, - const git_net_url *url) -{ - http_auth_negotiate_context *ctx; - - *out = NULL; - - ctx = git__calloc(1, sizeof(http_auth_negotiate_context)); - GIT_ERROR_CHECK_ALLOC(ctx); - - if (negotiate_init_context(ctx, url) < 0) { - git__free(ctx); - return -1; - } - - ctx->parent.type = GIT_HTTP_AUTH_NEGOTIATE; - ctx->parent.credtypes = GIT_CREDENTIAL_DEFAULT; - ctx->parent.connection_affinity = 1; - ctx->parent.set_challenge = negotiate_set_challenge; - ctx->parent.next_token = negotiate_next_token; - ctx->parent.is_complete = negotiate_is_complete; - ctx->parent.free = negotiate_context_free; - - *out = (git_http_auth_context *)ctx; - - return 0; -} - -#endif /* GIT_GSSAPI */ - |