* a Linking Exception. For full terms see the included COPYING file.
*/
-#ifdef GIT_GSSAPI
+#include "auth_negotiate.h"
+
+#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK)
#include "git2.h"
-#include "common.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" };
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)",
+ 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 {
- giterr_set(GITERR_NET, "%s: unknown negotiate error (%d.%d)",
+ git_error_set(GIT_ERROR_NET, "%s: unknown negotiate error (%d.%d)",
message, status_major, status_minor);
}
}
git__free(ctx->challenge);
ctx->challenge = git__strdup(challenge);
- GITERR_CHECK_ALLOC(ctx->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_cred *cred)
+ git_credential *cred)
{
http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
OM_uint32 status_major, status_minor;
size_t challenge_len;
int error = 0;
- assert(buf && ctx && ctx->configured && cred && cred->credtype == GIT_CREDTYPE_DEFAULT);
+ assert(buf && ctx && ctx->configured && cred && cred->credtype == GIT_CREDENTIAL_DEFAULT);
if (ctx->complete)
return 0;
if (GSS_ERROR(status_major)) {
negotiate_err_set(status_major, status_minor,
- "Could not parse principal");
+ "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");
+ 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;
- } else if (challenge_len > 9) {
+ }
+
+ 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");
+ git_error_set(GIT_ERROR_NET, "invalid negotiate challenge from server");
error = -1;
goto done;
}
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;
+ negotiate_context_dispose(ctx);
}
mech = &negotiate_oid_spnego;
- if (GSS_ERROR(status_major = gss_init_sec_context(
+ status_major = gss_init_sec_context(
&status_minor,
GSS_C_NO_CREDENTIAL,
&ctx->gss_context,
NULL,
&output_token,
NULL,
- NULL))) {
- negotiate_err_set(status_major, status_minor, "Negotiate failure");
+ 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;
}
- git_buf_puts(buf, "Authorization: Negotiate ");
+ 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);
- 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);
+ git_buf_dispose(&input_buf);
return error;
}
-static void negotiate_context_free(git_http_auth_context *c)
+static int negotiate_is_complete(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;
- }
+ assert(ctx);
- git_buf_free(&ctx->target);
+ return (ctx->complete == 1);
+}
- git__free(ctx->challenge);
+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;
static int negotiate_init_context(
http_auth_negotiate_context *ctx,
- const gitno_connection_data *connection_data)
+ const git_net_url *url)
{
OM_uint32 status_major, status_minor;
gss_OID item, *oid;
size_t i;
/* Query supported mechanisms looking for SPNEGO) */
- if (GSS_ERROR(status_major =
- gss_indicate_mechs(&status_minor, &mechanism_list))) {
+ 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;
gss_release_oid_set(&status_minor, &mechanism_list);
if (!ctx->oid) {
- giterr_set(GITERR_NET, "negotiate authentication is not supported");
+ git_error_set(GIT_ERROR_NET, "negotiate authentication is not supported");
return -1;
}
git_buf_puts(&ctx->target, "HTTP@");
- git_buf_puts(&ctx->target, connection_data->host);
+ git_buf_puts(&ctx->target, url->host);
if (git_buf_oom(&ctx->target))
return -1;
int git_http_auth_negotiate(
git_http_auth_context **out,
- const gitno_connection_data *connection_data)
+ const git_net_url *url)
{
http_auth_negotiate_context *ctx;
*out = NULL;
ctx = git__calloc(1, sizeof(http_auth_negotiate_context));
- GITERR_CHECK_ALLOC(ctx);
+ GIT_ERROR_CHECK_ALLOC(ctx);
- if (negotiate_init_context(ctx, connection_data) < 0) {
+ if (negotiate_init_context(ctx, url) < 0) {
git__free(ctx);
return -1;
}
- ctx->parent.type = GIT_AUTHTYPE_NEGOTIATE;
- ctx->parent.credtypes = GIT_CREDTYPE_DEFAULT;
+ 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;