Commit 23135afa by Edward Thomson

Introduce proper http authentication API

parent 315cb38e
...@@ -36,7 +36,7 @@ OPTION( ANDROID "Build for android NDK" OFF ) ...@@ -36,7 +36,7 @@ OPTION( ANDROID "Build for android NDK" OFF )
OPTION( USE_ICONV "Link with and use iconv library" OFF ) OPTION( USE_ICONV "Link with and use iconv library" OFF )
OPTION( USE_SSH "Link with libssh to enable SSH support" ON ) OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
OPTION( USE_GSSAPI "Link with libgssapi for SPNEGO auth" ON ) OPTION( USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF )
OPTION( VALGRIND "Configure build for valgrind" OFF ) OPTION( VALGRIND "Configure build for valgrind" OFF )
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
......
/*
* 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 "git2.h"
#include "buffer.h"
#include "auth.h"
static int basic_next_token(
git_buf *out, git_http_auth_context *ctx, git_cred *c)
{
git_cred_userpass_plaintext *cred;
git_buf raw = GIT_BUF_INIT;
int error = -1;
GIT_UNUSED(ctx);
if (c->credtype != GIT_CREDTYPE_USERPASS_PLAINTEXT) {
giterr_set(GITERR_INVALID, "invalid credential type for basic auth");
goto on_error;
}
cred = (git_cred_userpass_plaintext *)c;
git_buf_printf(&raw, "%s:%s", cred->username, cred->password);
if (git_buf_oom(&raw) ||
git_buf_puts(out, "Authorization: Basic ") < 0 ||
git_buf_encode_base64(out, git_buf_cstr(&raw), raw.size) < 0 ||
git_buf_puts(out, "\r\n") < 0)
goto on_error;
error = 0;
on_error:
if (raw.size)
git__memzero(raw.ptr, raw.size);
git_buf_free(&raw);
return error;
}
static git_http_auth_context basic_context = {
GIT_AUTHTYPE_BASIC,
GIT_CREDTYPE_USERPASS_PLAINTEXT,
NULL,
basic_next_token,
NULL
};
int git_http_auth_basic(
git_http_auth_context **out, const gitno_connection_data *connection_data)
{
GIT_UNUSED(connection_data);
*out = &basic_context;
return 0;
}
int git_http_auth_dummy(
git_http_auth_context **out, const gitno_connection_data *connection_data)
{
GIT_UNUSED(connection_data);
*out = NULL;
return 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.
*/
#ifndef INCLUDE_http_auth_h__
#define INCLUDE_http_auth_h__
#include "git2.h"
#include "netops.h"
typedef enum {
GIT_AUTHTYPE_BASIC = 1,
GIT_AUTHTYPE_NEGOTIATE = 2,
} git_http_authtype_t;
typedef struct git_http_auth_context git_http_auth_context;
struct git_http_auth_context {
/** Type of scheme */
git_http_authtype_t type;
/** Supported credentials */
git_credtype_t credtypes;
/** Sets the challenge on the authentication context */
int (*set_challenge)(git_http_auth_context *ctx, const char *challenge);
/** Gets the next authentication token from the context */
int (*next_token)(git_buf *out, git_http_auth_context *ctx, git_cred *cred);
/** Frees the authentication context */
void (*free)(git_http_auth_context *ctx);
};
typedef struct {
/** Type of scheme */
git_http_authtype_t type;
/** Name of the scheme (as used in the Authorization header) */
const char *name;
/** Credential types this scheme supports */
git_credtype_t credtypes;
/** Function to initialize an authentication context */
int (*init_context)(
git_http_auth_context **out,
const gitno_connection_data *connection_data);
} git_http_auth_scheme;
int git_http_auth_dummy(
git_http_auth_context **out,
const gitno_connection_data *connection_data);
int git_http_auth_basic(
git_http_auth_context **out,
const gitno_connection_data *connection_data);
#endif
/*
* 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.
*/
#ifdef GIT_GSSAPI
#include "git2.h"
#include "common.h"
#include "buffer.h"
#include "auth.h"
#include <gssapi.h>
#include <krb5.h>
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) {
giterr_set(GITERR_NET, "%s: %.*s (%d.%d)",
message, (int)buffer.length, (const char *)buffer.value,
status_major, status_minor);
gss_release_buffer(&status_minor, &buffer);
} else {
giterr_set(GITERR_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;
assert(ctx && ctx->configured && challenge);
git__free(ctx->challenge);
ctx->challenge = git__strdup(challenge);
GITERR_CHECK_ALLOC(ctx->challenge);
return 0;
}
static int negotiate_next_token(
git_buf *buf,
git_http_auth_context *c,
git_cred *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;
assert(buf && ctx && ctx->configured && cred && cred->credtype == GIT_CREDTYPE_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) {
giterr_set(GITERR_NET, "No negotiate challenge sent from server");
error = -1;
goto done;
} else if (challenge_len > 9) {
if (git_buf_decode_base64(&input_buf,
ctx->challenge + 10, challenge_len - 10) < 0) {
giterr_set(GITERR_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) {
giterr_set(GITERR_NET, "Could not restart authentication");
error = -1;
goto done;
}
mech = &negotiate_oid_spnego;
if (GSS_ERROR(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))) {
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) {
ctx->complete = 1;
goto done;
}
git_buf_puts(buf, "Authorization: Negotiate ");
git_buf_encode_base64(buf, output_token.value, output_token.length);
git_buf_puts(buf, "\r\n");
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_free(&input_buf);
return error;
}
static void negotiate_context_free(git_http_auth_context *c)
{
http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
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_free(&ctx->target);
git__free(ctx->challenge);
ctx->configured = 0;
ctx->complete = 0;
ctx->oid = NULL;
git__free(ctx);
}
static int negotiate_init_context(
http_auth_negotiate_context *ctx,
const gitno_connection_data *connection_data)
{
OM_uint32 status_major, status_minor;
gss_OID item, *oid;
gss_OID_set mechanism_list;
size_t i;
/* Query supported mechanisms looking for SPNEGO) */
if (GSS_ERROR(status_major =
gss_indicate_mechs(&status_minor, &mechanism_list))) {
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) {
giterr_set(GITERR_NET, "Negotiate authentication is not supported");
return -1;
}
git_buf_puts(&ctx->target, "HTTP@");
git_buf_puts(&ctx->target, connection_data->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 gitno_connection_data *connection_data)
{
http_auth_negotiate_context *ctx;
*out = NULL;
ctx = git__calloc(1, sizeof(http_auth_negotiate_context));
GITERR_CHECK_ALLOC(ctx);
if (negotiate_init_context(ctx, connection_data) < 0) {
git__free(ctx);
return -1;
}
ctx->parent.type = GIT_AUTHTYPE_NEGOTIATE;
ctx->parent.credtypes = GIT_CREDTYPE_DEFAULT;
ctx->parent.set_challenge = negotiate_set_challenge;
ctx->parent.next_token = negotiate_next_token;
ctx->parent.free = negotiate_context_free;
*out = (git_http_auth_context *)ctx;
return 0;
}
#endif /* GIT_GSSAPI */
/*
* 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.
*/
#ifndef INCLUDE_auth_negotiate_h__
#define INCLUDE_auth_negotiate_h__
#include "git2.h"
#include "auth.h"
#ifdef GIT_GSSAPI
extern int git_http_auth_negotiate(
git_http_auth_context **out,
const gitno_connection_data *connection_data);
#else
#define git_http_auth_negotiate git_http_auth_dummy
#endif /* GIT_GSSAPI */
#endif
...@@ -11,11 +11,13 @@ ...@@ -11,11 +11,13 @@
#include "buffer.h" #include "buffer.h"
#include "netops.h" #include "netops.h"
#include "smart.h" #include "smart.h"
#include "auth.h"
#include "auth_negotiate.h"
#ifdef GIT_GSSAPI git_http_auth_scheme auth_schemes[] = {
# include <gssapi.h> { GIT_AUTHTYPE_NEGOTIATE, "Negotiate", GIT_CREDTYPE_DEFAULT, git_http_auth_negotiate },
# include <krb5.h> { GIT_AUTHTYPE_BASIC, "Basic", GIT_CREDTYPE_USERPASS_PLAINTEXT, git_http_auth_basic },
#endif };
static const char *upload_pack_service = "upload-pack"; static const char *upload_pack_service = "upload-pack";
static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack"; static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
...@@ -25,18 +27,6 @@ static const char *receive_pack_ls_service_url = "/info/refs?service=git-receive ...@@ -25,18 +27,6 @@ static const char *receive_pack_ls_service_url = "/info/refs?service=git-receive
static const char *receive_pack_service_url = "/git-receive-pack"; static const char *receive_pack_service_url = "/git-receive-pack";
static const char *get_verb = "GET"; static const char *get_verb = "GET";
static const char *post_verb = "POST"; static const char *post_verb = "POST";
static const char *basic_authtype = "Basic";
static const char *negotiate_authtype = "Negotiate";
#ifdef GIT_GSSAPI
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 };
#endif
#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport) #define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
...@@ -51,11 +41,6 @@ enum last_cb { ...@@ -51,11 +41,6 @@ enum last_cb {
VALUE VALUE
}; };
typedef enum {
GIT_HTTP_AUTH_BASIC = 1,
GIT_HTTP_AUTH_NEGOTIATE = 2,
} http_authmechanism_t;
typedef struct { typedef struct {
git_smart_subtransport_stream parent; git_smart_subtransport_stream parent;
const char *service; const char *service;
...@@ -75,10 +60,6 @@ typedef struct { ...@@ -75,10 +60,6 @@ typedef struct {
transport_smart *owner; transport_smart *owner;
gitno_socket socket; gitno_socket socket;
gitno_connection_data connection_data; gitno_connection_data connection_data;
git_cred *cred;
git_cred *url_cred;
http_authmechanism_t auth_mechanism;
char *auth_challenge;
bool connected; bool connected;
/* Parser structures */ /* Parser structures */
...@@ -95,13 +76,10 @@ typedef struct { ...@@ -95,13 +76,10 @@ typedef struct {
int parse_error; int parse_error;
unsigned parse_finished : 1; unsigned parse_finished : 1;
#ifdef GIT_GSSAPI /* Authentication */
unsigned negotiate_configured : 1, git_cred *cred;
negotiate_complete : 1; git_cred *url_cred;
git_buf negotiate_target; git_vector auth_contexts;
gss_ctx_id_t negotiate_context;
gss_OID negotiate_oid;
#endif
} http_subtransport; } http_subtransport;
typedef struct { typedef struct {
...@@ -114,217 +92,93 @@ typedef struct { ...@@ -114,217 +92,93 @@ typedef struct {
size_t *bytes_read; size_t *bytes_read;
} parser_context; } parser_context;
static int apply_basic_credential( static bool credtype_match(git_http_auth_scheme *scheme, void *data)
git_buf *buf,
http_subtransport *transport,
git_cred *cred)
{ {
git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; unsigned int credtype = *(unsigned int *)data;
git_buf raw = GIT_BUF_INIT;
int error = -1;
GIT_UNUSED(transport);
git_buf_printf(&raw, "%s:%s", c->username, c->password); return !!(scheme->credtypes & credtype);
if (git_buf_oom(&raw) ||
git_buf_puts(buf, "Authorization: Basic ") < 0 ||
git_buf_encode_base64(buf, git_buf_cstr(&raw), raw.size) < 0 ||
git_buf_puts(buf, "\r\n") < 0)
goto on_error;
error = 0;
on_error:
if (raw.size)
memset(raw.ptr, 0x0, raw.size);
git_buf_free(&raw);
return error;
} }
#ifdef GIT_GSSAPI static bool challenge_match(git_http_auth_scheme *scheme, void *data)
static void negotiate_err_set(
OM_uint32 status_major,
OM_uint32 status_minor,
const char *message)
{ {
gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; const char *scheme_name = scheme->name;
OM_uint32 status_display, context = 0; const char *challenge = (const char *)data;
size_t scheme_len;
if (gss_display_status(&status_display, status_major, GSS_C_GSS_CODE,
GSS_C_NO_OID, &context, &buffer) == GSS_S_COMPLETE) { scheme_len = strlen(scheme_name);
giterr_set(GITERR_NET, "%s: %.*s (%d.%d)", return (strncmp(challenge, scheme_name, scheme_len) == 0 &&
message, (int)buffer.length, (const char *)buffer.value, (challenge[scheme_len] == '\0' || challenge[scheme_len] == ' '));
status_major, status_minor);
gss_release_buffer(&status_minor, &buffer);
} else {
giterr_set(GITERR_NET, "%s: unknown negotiate error (%d.%d)",
message, status_major, status_minor);
}
} }
static int negotiate_configure(http_subtransport *transport) static int auth_context_match(
git_http_auth_context **out,
http_subtransport *t,
bool (*scheme_match)(git_http_auth_scheme *scheme, void *data),
void *data)
{ {
OM_uint32 status_major, status_minor; git_http_auth_scheme *scheme = NULL;
gss_OID item, *oid; git_http_auth_context *context = NULL, *c;
gss_OID_set mechanism_list;
size_t i; size_t i;
/* Query supported mechanisms looking for SPNEGO) */ *out = NULL;
if (GSS_ERROR(status_major =
gss_indicate_mechs(&status_minor, &mechanism_list))) {
negotiate_err_set(status_major, status_minor,
"could not query mechanisms");
return -1;
}
if (mechanism_list) { for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
for (oid = negotiate_oids; *oid; oid++) { if (scheme_match(&auth_schemes[i], data)) {
for (i = 0; i < mechanism_list->count; i++) { scheme = &auth_schemes[i];
item = &mechanism_list->elements[i];
if (item->length == (*oid)->length &&
memcmp(item->elements, (*oid)->elements, item->length) == 0) {
transport->negotiate_oid = *oid;
break; break;
} }
} }
if (transport->negotiate_oid) if (!scheme)
return 0;
/* See if authentication has already started for this scheme */
git_vector_foreach(&t->auth_contexts, i, c) {
if (c->type == scheme->type) {
context = c;
break; break;
} }
} }
gss_release_oid_set(&status_minor, &mechanism_list); if (!context) {
if (scheme->init_context(&context, &t->connection_data) < 0)
if (!transport->negotiate_oid) { return -1;
giterr_set(GITERR_NET, "Negotiate authentication is not supported"); else if (!context)
return 0;
else if (git_vector_insert(&t->auth_contexts, context) < 0)
return -1; return -1;
} }
git_buf_puts(&transport->negotiate_target, "HTTP@"); *out = context;
git_buf_puts(&transport->negotiate_target, transport->connection_data.host);
if (git_buf_oom(&transport->negotiate_target))
return -1;
transport->negotiate_context = GSS_C_NO_CONTEXT;
transport->negotiate_configured = 1;
return 0; return 0;
} }
static int negotiate_next_token( static int apply_credentials(git_buf *buf, http_subtransport *t)
git_buf *buf,
http_subtransport *transport,
git_cred *cred)
{ {
OM_uint32 status_major, status_minor; git_cred *cred = t->cred;
gss_buffer_desc target_buffer = GSS_C_EMPTY_BUFFER, git_http_auth_context *context;
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_UNUSED(cred);
target_buffer.value = (void *)transport->negotiate_target.ptr;
target_buffer.length = transport->negotiate_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 = transport->auth_challenge ?
strlen(transport->auth_challenge) : 0;
assert(challenge_len >= 9);
if (challenge_len > 9) {
if (git_buf_decode_base64(&input_buf,
transport->auth_challenge + 10, challenge_len - 10) < 0) {
giterr_set(GITERR_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 (transport->negotiate_context != GSS_C_NO_CONTEXT) {
giterr_set(GITERR_NET, "Could not restart authentication");
error = -1;
goto done;
}
mech = &negotiate_oid_spnego; /* Apply the credentials given to us in the URL */
if (!cred && t->connection_data.user && t->connection_data.pass) {
if (GSS_ERROR(status_major = gss_init_sec_context( if (!t->url_cred &&
&status_minor, git_cred_userpass_plaintext_new(&t->url_cred,
GSS_C_NO_CREDENTIAL, t->connection_data.user, t->connection_data.pass) < 0)
&transport->negotiate_context, return -1;
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))) {
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. */ cred = t->url_cred;
if (status_major == GSS_S_COMPLETE) {
transport->negotiate_complete = 1;
goto done;
} }
git_buf_puts(buf, "Authorization: Negotiate "); if (!cred)
git_buf_encode_base64(buf, output_token.value, output_token.length); return 0;
git_buf_puts(buf, "\r\n");
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_free(&input_buf);
return error;
}
static int apply_negotiate_credential( /* Get or create a context for the best scheme for this cred type */
git_buf *buf, if (auth_context_match(&context, t, credtype_match, &cred->credtype) < 0)
http_subtransport *transport,
git_cred *cred)
{
if (!transport->negotiate_configured && negotiate_configure(transport) < 0)
return -1; return -1;
if (transport->negotiate_complete) return context->next_token(buf, context, cred);
return 0;
return negotiate_next_token(buf, transport, cred);
} }
#endif /* GIT_GSSAPI */
static int gen_request( static int gen_request(
git_buf *buf, git_buf *buf,
http_stream *s, http_stream *s,
...@@ -350,27 +204,8 @@ static int gen_request( ...@@ -350,27 +204,8 @@ static int gen_request(
git_buf_puts(buf, "Accept: */*\r\n"); git_buf_puts(buf, "Accept: */*\r\n");
/* Apply credentials to the request */ /* Apply credentials to the request */
#ifdef GIT_GSSAPI if (apply_credentials(buf, t) < 0)
if (t->cred && t->cred->credtype == GIT_CREDTYPE_DEFAULT &&
(t->auth_mechanism & GIT_HTTP_AUTH_NEGOTIATE)) {
if (apply_negotiate_credential(buf, t, t->cred) < 0)
return -1;
} else
#endif
if (t->cred && t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT &&
t->auth_mechanism == GIT_HTTP_AUTH_BASIC) {
if (apply_basic_credential(buf, t, t->cred) < 0)
return -1; return -1;
}
/* Use url-parsed basic auth if username and password are both provided */
if (!t->cred && t->connection_data.user && t->connection_data.pass) {
if (!t->url_cred && git_cred_userpass_plaintext_new(&t->url_cred,
t->connection_data.user, t->connection_data.pass) < 0)
return -1;
if (apply_basic_credential(buf, t, t->url_cred) < 0) return -1;
}
git_buf_puts(buf, "\r\n"); git_buf_puts(buf, "\r\n");
...@@ -382,31 +217,24 @@ static int gen_request( ...@@ -382,31 +217,24 @@ static int gen_request(
static int parse_authenticate_response( static int parse_authenticate_response(
git_vector *www_authenticate, git_vector *www_authenticate,
int *allowed_types, http_subtransport *t,
http_authmechanism_t *auth_mechanism, int *allowed_types)
char **auth_challenge)
{ {
unsigned i; git_http_auth_context *context;
char *entry; char *challenge;
size_t i;
git_vector_foreach(www_authenticate, i, entry) {
if (!strncmp(entry, negotiate_authtype, 9) &&
(entry[9] == '\0' || entry[9] == ' ')) {
*allowed_types |= GIT_CREDTYPE_DEFAULT;
*auth_mechanism = GIT_HTTP_AUTH_NEGOTIATE;
*auth_challenge = git__strdup(entry); git_vector_foreach(www_authenticate, i, challenge) {
GITERR_CHECK_ALLOC(*auth_challenge); if (auth_context_match(&context, t, challenge_match, challenge) < 0)
} return -1;
else if (!context)
continue;
else if (!strncmp(entry, basic_authtype, 5) && if (context->set_challenge &&
(entry[5] == '\0' || entry[5] == ' ')) { context->set_challenge(context, challenge) < 0)
*allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT; return -1;
*auth_mechanism = GIT_HTTP_AUTH_BASIC;
*auth_challenge = git__strdup(entry); *allowed_types |= context->credtypes;
GITERR_CHECK_ALLOC(*auth_challenge);
}
} }
return 0; return 0;
...@@ -495,13 +323,8 @@ static int on_headers_complete(http_parser *parser) ...@@ -495,13 +323,8 @@ static int on_headers_complete(http_parser *parser)
* is not complete) or a 200 (simply informing us that auth *is* * is not complete) or a 200 (simply informing us that auth *is*
* complete.) * complete.)
*/ */
git__free(t->auth_challenge); if (parse_authenticate_response(&t->www_authenticate, t,
t->auth_challenge = NULL; &allowed_auth_types) < 0)
if (parse_authenticate_response(&t->www_authenticate,
&allowed_auth_types,
&t->auth_mechanism,
&t->auth_challenge) < 0)
return t->parse_error = PARSE_ERROR_GENERIC; return t->parse_error = PARSE_ERROR_GENERIC;
/* Check for an authentication failure. */ /* Check for an authentication failure. */
...@@ -1089,27 +912,11 @@ static int http_action( ...@@ -1089,27 +912,11 @@ static int http_action(
return -1; return -1;
} }
static void clear_negotiate_state(http_subtransport *t)
{
#ifdef GIT_GSSAPI
OM_uint32 status_minor;
if (t->negotiate_context != GSS_C_NO_CONTEXT) {
gss_delete_sec_context(&status_minor, &t->negotiate_context, GSS_C_NO_BUFFER);
t->negotiate_context = GSS_C_NO_CONTEXT;
}
git_buf_free(&t->negotiate_target);
t->negotiate_configured = 0;
t->negotiate_complete = 0;
t->negotiate_oid = NULL;
#endif
}
static int http_close(git_smart_subtransport *subtransport) static int http_close(git_smart_subtransport *subtransport)
{ {
http_subtransport *t = (http_subtransport *) subtransport; http_subtransport *t = (http_subtransport *) subtransport;
git_http_auth_context *context;
size_t i;
clear_parser_state(t); clear_parser_state(t);
...@@ -1128,10 +935,12 @@ static int http_close(git_smart_subtransport *subtransport) ...@@ -1128,10 +935,12 @@ static int http_close(git_smart_subtransport *subtransport)
t->url_cred = NULL; t->url_cred = NULL;
} }
git__free(t->auth_challenge); git_vector_foreach(&t->auth_contexts, i, context) {
t->auth_challenge = NULL; if (context->free)
context->free(context);
}
clear_negotiate_state(t); git_vector_clear(&t->auth_contexts);
gitno_connection_data_free_ptrs(&t->connection_data); gitno_connection_data_free_ptrs(&t->connection_data);
...@@ -1144,6 +953,7 @@ static void http_free(git_smart_subtransport *subtransport) ...@@ -1144,6 +953,7 @@ static void http_free(git_smart_subtransport *subtransport)
http_close(subtransport); http_close(subtransport);
git_vector_free(&t->auth_contexts);
git__free(t); git__free(t);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment