static int negotiate_next_token()

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;
}