in src/transports/auth_negotiate.c [94:199]
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;
assert(buf && ctx && ctx->configured && cred && 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;
}