From 4572cf53f3f60abc0679d68b60ea37254c13adee Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 19 May 2020 11:07:45 -0400 Subject: [PATCH 1/4] Fix memory leak in acceptor Signed-off-by: Simo Sorce --- src/gss_sec_ctx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gss_sec_ctx.c b/src/gss_sec_ctx.c index 92276d9..4f81d52 100644 --- a/src/gss_sec_ctx.c +++ b/src/gss_sec_ctx.c @@ -996,6 +996,8 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status, if (time_rec) *time_rec = GSS_C_INDEFINITE; } *context_handle = (gss_ctx_id_t)ctx; + gssntlm_release_cred(&tmpmin, (gss_cred_id_t *)&usr_cred); + gssntlm_release_name(&tmpmin, (gss_name_t *)&gss_usrname); gssntlm_release_name(&tmpmin, (gss_name_t *)&server_name); safefree(computer_name); safefree(nb_computer_name); From 3a598f650c6a71cfb670edeead65a1e1a6804dc2 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 19 May 2020 10:19:44 -0400 Subject: [PATCH 2/4] Add server side anonymous authentication Signed-off-by: Simo Sorce --- src/gss_names.c | 2 ++ src/gss_ntlmssp.c | 13 +++++++++++++ src/gss_ntlmssp.h | 1 + src/gss_sec_ctx.c | 15 +++++++++++---- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/gss_names.c b/src/gss_names.c index 7cee38c..c909590 100644 --- a/src/gss_names.c +++ b/src/gss_names.c @@ -157,6 +157,8 @@ uint32_t gssntlm_import_name_by_mech(uint32_t *minor_status, /* TODO: check mech_type == gssntlm_oid */ if (mech_type == GSS_C_NO_OID) { return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ); + } else if (!gss_oid_equal(mech_type, &gssntlm_oid)) { + return GSSERRS(ERR_BADARG, GSS_S_BAD_MECH); } name = calloc(1, sizeof(struct gssntlm_name)); diff --git a/src/gss_ntlmssp.c b/src/gss_ntlmssp.c index 12d597a..5579dca 100644 --- a/src/gss_ntlmssp.c +++ b/src/gss_ntlmssp.c @@ -193,3 +193,16 @@ int gssntlm_get_lm_compatibility_level(void) /* use 3 by default for better compatibility */ return 3; } + +bool gssntlm_is_anonymous_allowed(void) +{ + const char *envvar; + + envvar = getenv("NTLM_ALLOW_ANONYMOUS"); + if (envvar != NULL) { + return (atoi(envvar) > 0); + } + + /* Not allowed by default */ + return false; +} diff --git a/src/gss_ntlmssp.h b/src/gss_ntlmssp.h index b01dc40..3757f57 100644 --- a/src/gss_ntlmssp.h +++ b/src/gss_ntlmssp.h @@ -178,6 +178,7 @@ uint32_t gssntlm_context_is_valid(struct gssntlm_ctx *ctx, time_t *time_now); int gssntlm_get_lm_compatibility_level(void); +bool gssntlm_is_anonymous_allowed(void); void gssntlm_int_release_name(struct gssntlm_name *name); void gssntlm_int_release_cred(struct gssntlm_cred *cred); diff --git a/src/gss_sec_ctx.c b/src/gss_sec_ctx.c index 4f81d52..e5bea7a 100644 --- a/src/gss_sec_ctx.c +++ b/src/gss_sec_ctx.c @@ -651,7 +651,6 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status, } ctx->neg_flags = NTLMSSP_DEFAULT_SERVER_FLAGS; - /* Fixme: How do we allow anonymous negotition ? */ if (gssntlm_sec_lm_ok(ctx)) { ctx->neg_flags |= NTLMSSP_REQUEST_NON_NT_SESSION_KEY; @@ -847,9 +846,17 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status, (((lm_chal_resp.length == 1) && (lm_chal_resp.data[0] == '\0')) || (lm_chal_resp.length == 0))) { /* Anonymous auth */ - /* FIXME: not supported for now */ - set_GSSERR(ERR_NOTSUPPORTED); - goto done; + if (!gssntlm_is_anonymous_allowed()) { + set_GSSERRS(ERR_NOUSRCRED, GSS_S_DEFECTIVE_CREDENTIAL); + goto done; + } + + retmaj = gssntlm_import_name(&retmin, NULL, GSS_C_NT_ANONYMOUS, + (gss_name_t *)&ctx->source_name); + if (retmaj) goto done; + + /* nullSession */ + memset(key_exchange_key.data, 0, 16); } else { From 1878ef5476d88000d7ef16b35352dc4a0073c3d4 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 19 May 2020 11:06:34 -0400 Subject: [PATCH 3/4] Add client side anonymous authentication Signed-off-by: Simo Sorce --- src/gss_auth.c | 153 ++++++++++++++++++++++++-------------------- src/gss_creds.c | 8 +++ src/gss_names.c | 1 + src/gss_sec_ctx.c | 29 +++++---- tests/ntlmssptest.c | 2 +- 5 files changed, 112 insertions(+), 81 deletions(-) diff --git a/src/gss_auth.c b/src/gss_auth.c index 3b44533..ccafa76 100644 --- a/src/gss_auth.c +++ b/src/gss_auth.c @@ -21,27 +21,55 @@ uint32_t gssntlm_cli_auth(uint32_t *minor_status, struct ntlm_buffer auth_mic = { NULL, 16 }; uint8_t micbuf[16]; struct ntlm_buffer mic = { micbuf, 16 }; + char *username; + char *domain; + bool ext_sec; bool add_mic = false; bool key_exch; uint32_t retmaj; uint32_t retmin; + ext_sec = (in_flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY); + switch (cred->type) { + case GSSNTLM_CRED_EXTERNAL: + retmin = external_cli_auth(ctx, cred, in_flags, input_chan_bindings); + if (retmin) { + set_GSSERR(retmin); + goto done; + } + set_GSSERRS(0, GSS_S_COMPLETE); + return GSSERR(); + + case GSSNTLM_CRED_ANON: + + /* Anonymous auth, empty responses */ + if (!(ctx->gss_flags & GSS_C_ANON_FLAG)) { + set_GSSERR(EINVAL); + goto done; + } + + domain = NULL; + username = NULL; + memset(&nt_chal_resp, 0, sizeof(nt_chal_resp)); + lm_chal_resp.data = malloc(1); + if (!lm_chal_resp.data) { + set_GSSERR(ENOMEM); + goto done; + } + lm_chal_resp.data[0] = 0; + lm_chal_resp.length = 1; + + memset(key_exchange_key.data, 0, 16); + break; + case GSSNTLM_CRED_USER: - if (ctx->gss_flags & GSS_C_ANON_FLAG) { - /* Anonymous auth, empty responses */ - memset(&nt_chal_resp, 0, sizeof(nt_chal_resp)); - lm_chal_resp.data = malloc(1); - if (!lm_chal_resp.data) { - set_GSSERR(ENOMEM); - goto done; - } - lm_chal_resp.data[0] = 0; - lm_chal_resp.length = 1; + domain = cred->cred.user.user.data.user.domain; + username = cred->cred.user.user.data.user.name; - } else if (gssntlm_sec_v2_ok(ctx)) { + if (gssntlm_sec_v2_ok(ctx)) { /* ### NTLMv2 ### */ uint8_t client_chal[8]; @@ -111,9 +139,7 @@ uint32_t gssntlm_cli_auth(uint32_t *minor_status, /* NTLMv2 Key */ retmin = NTOWFv2(ctx->ntlm, &cred->cred.user.nt_hash, - cred->cred.user.user.data.user.name, - cred->cred.user.user.data.user.domain, - &ntlmv2_key); + username, domain, &ntlmv2_key); if (retmin) { set_GSSERR(retmin); goto done; @@ -160,7 +186,6 @@ uint32_t gssntlm_cli_auth(uint32_t *minor_status, struct ntlm_buffer cli_chal = { client_chal, 8 }; struct ntlm_key session_base_key = { .length = 16 }; bool NoLMResponseNTLMv1 = !gssntlm_sec_lm_ok(ctx); - bool ext_sec; nt_chal_resp.length = 24; nt_chal_resp.data = calloc(1, nt_chal_resp.length); @@ -178,8 +203,6 @@ uint32_t gssntlm_cli_auth(uint32_t *minor_status, goto done; } - ext_sec = (in_flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY); - retmin = ntlm_compute_nt_response(&cred->cred.user.nt_hash, ext_sec, ctx->server_chal, client_chal, &nt_chal_resp); @@ -219,77 +242,69 @@ uint32_t gssntlm_cli_auth(uint32_t *minor_status, } } - key_exch = (in_flags & NTLMSSP_NEGOTIATE_KEY_EXCH); - - retmin = ntlm_exported_session_key(&key_exchange_key, key_exch, - &ctx->exported_session_key); - if (retmin) { - set_GSSERR(retmin); - goto done; - } + break; - if (key_exch) { - retmin = ntlm_encrypted_session_key(&key_exchange_key, - &ctx->exported_session_key, - &encrypted_random_session_key); - if (retmin) { - set_GSSERR(retmin); - goto done; - } - } + default: + set_GSSERR(ERR_NOUSRCRED); + goto done; + } - /* in_flags all verified, assign as current flags */ - ctx->neg_flags |= in_flags; + key_exch = (in_flags & NTLMSSP_NEGOTIATE_KEY_EXCH); - enc_sess_key.data = encrypted_random_session_key.data; - enc_sess_key.length = encrypted_random_session_key.length; + retmin = ntlm_exported_session_key(&key_exchange_key, key_exch, + &ctx->exported_session_key); + if (retmin) { + set_GSSERR(retmin); + goto done; + } - retmin = ntlm_encode_auth_msg(ctx->ntlm, ctx->neg_flags, - &lm_chal_resp, &nt_chal_resp, - cred->cred.user.user.data.user.domain, - cred->cred.user.user.data.user.name, - ctx->workstation, &enc_sess_key, - add_mic ? &auth_mic : NULL, - &ctx->auth_msg); + if (key_exch) { + retmin = ntlm_encrypted_session_key(&key_exchange_key, + &ctx->exported_session_key, + &encrypted_random_session_key); if (retmin) { set_GSSERR(retmin); goto done; } + } - /* Now we need to calculate the MIC, because the MIC is part of the - * message it protects, ntlm_encode_auth_msg() always add a zeroeth - * buffer, however it returns in data_mic the pointer to the actual - * area in the auth_msg that points at the mic, so we can backfill */ - if (add_mic) { - retmin = ntlm_mic(&ctx->exported_session_key, &ctx->nego_msg, - &ctx->chal_msg, &ctx->auth_msg, &mic); - if (retmin) { - set_GSSERR(retmin); - goto done; - } - /* now that we have the mic, copy it into the auth message */ - memcpy(auth_mic.data, mic.data, 16); + /* in_flags all verified, assign as current flags */ + ctx->neg_flags |= in_flags; - /* Make sure SPNEGO gets to know it has to add mechlistMIC too */ - ctx->int_flags |= NTLMSSP_CTX_FLAG_AUTH_WITH_MIC; - } + enc_sess_key.data = encrypted_random_session_key.data; + enc_sess_key.length = encrypted_random_session_key.length; - set_GSSERRS(0, GSS_S_COMPLETE); - break; + retmin = ntlm_encode_auth_msg(ctx->ntlm, ctx->neg_flags, + &lm_chal_resp, &nt_chal_resp, + domain, username, + ctx->workstation, &enc_sess_key, + add_mic ? &auth_mic : NULL, + &ctx->auth_msg); + if (retmin) { + set_GSSERR(retmin); + goto done; + } - case GSSNTLM_CRED_EXTERNAL: - retmin = external_cli_auth(ctx, cred, in_flags, input_chan_bindings); + /* Now we need to calculate the MIC, because the MIC is part of the + * message it protects, ntlm_encode_auth_msg() always add a zeroeth + * buffer, however it returns in data_mic the pointer to the actual + * area in the auth_msg that points at the mic, so we can backfill */ + if (add_mic) { + retmin = ntlm_mic(&ctx->exported_session_key, &ctx->nego_msg, + &ctx->chal_msg, &ctx->auth_msg, &mic); if (retmin) { set_GSSERR(retmin); goto done; } - set_GSSERRS(0, GSS_S_COMPLETE); - break; + /* now that we have the mic, copy it into the auth message */ + memcpy(auth_mic.data, mic.data, 16); - default: - set_GSSERR(ERR_NOUSRCRED); + /* Make sure SPNEGO gets to know it has to add mechlistMIC too */ + ctx->int_flags |= NTLMSSP_CTX_FLAG_AUTH_WITH_MIC; } + set_GSSERRS(0, GSS_S_COMPLETE); + done: ntlm_free_buffer_data(&client_target_info); ntlm_free_buffer_data(&nt_chal_resp); diff --git a/src/gss_creds.c b/src/gss_creds.c index 5d279aa..f911bce 100644 --- a/src/gss_creds.c +++ b/src/gss_creds.c @@ -430,6 +430,14 @@ uint32_t gssntlm_acquire_cred_from(uint32_t *minor_status, } if (cred_usage == GSS_C_INITIATE) { + if (name != NULL && name->type == GSSNTLM_NAME_ANON) { + cred->type = GSSNTLM_CRED_ANON; + cred->cred.anon.dummy = 0; + retmin = 0; + retmaj = 0; + goto done; + } + if (name != NULL && name->type != GSSNTLM_NAME_USER) { set_GSSERRS(ERR_NOUSRNAME, GSS_S_BAD_NAMETYPE); goto done; diff --git a/src/gss_names.c b/src/gss_names.c index c909590..45ba84b 100644 --- a/src/gss_names.c +++ b/src/gss_names.c @@ -761,6 +761,7 @@ static uint32_t make_ma_oid_set(uint32_t *minor_status, gss_OID_set *ma_set, GSS_C_MA_OOS_DET, GSS_C_MA_CBINDINGS, GSS_C_MA_CTX_TRANS, + GSS_C_MA_AUTH_INIT_ANON, NULL }; uint32_t maj = 0; diff --git a/src/gss_sec_ctx.c b/src/gss_sec_ctx.c index e5bea7a..72086a4 100644 --- a/src/gss_sec_ctx.c +++ b/src/gss_sec_ctx.c @@ -40,6 +40,7 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status, { struct gssntlm_ctx *ctx; struct gssntlm_name *server = NULL; + struct gssntlm_name *anonymous = NULL; struct gssntlm_cred *cred = NULL; char *computer_name = NULL; char *nb_computer_name = NULL; @@ -79,16 +80,16 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status, if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { if (req_flags & GSS_C_ANON_FLAG) { - set_GSSERRS(ERR_NOARG, GSS_S_UNAVAILABLE); - goto done; - } else { - retmaj = gssntlm_acquire_cred(&retmin, - NULL, time_req, - NULL, GSS_C_INITIATE, - (gss_cred_id_t *)&cred, - NULL, time_rec); + retmaj = gssntlm_import_name(&retmin, NULL, GSS_C_NT_ANONYMOUS, + (gss_name_t *)&anonymous); if (retmaj) goto done; } + retmaj = gssntlm_acquire_cred(&retmin, + (gss_name_t)anonymous, time_req, + NULL, GSS_C_INITIATE, + (gss_cred_id_t *)&cred, + NULL, time_rec); + if (retmaj) goto done; } else { cred = (struct gssntlm_cred *)claimant_cred_handle; if (cred->type != GSSNTLM_CRED_USER && @@ -107,8 +108,13 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status, goto done; } - retmin = gssntlm_copy_name(&cred->cred.user.user, - &ctx->source_name); + if (req_flags & GSS_C_ANON_FLAG) { + retmin = gssntlm_copy_name(anonymous, + &ctx->source_name); + } else { + retmin = gssntlm_copy_name(&cred->cred.user.user, + &ctx->source_name); + } if (retmin) { set_GSSERR(retmin); goto done; @@ -388,7 +394,7 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status, * negotiated flags */ ctx->neg_flags &= in_flags; - retmaj = gssntlm_cli_auth(&retmin, ctx, cred, &target_info, + retmaj = gssntlm_cli_auth(&retmin, ctx, cred, &target_info, in_flags, input_chan_bindings); if (retmaj) goto done; @@ -441,6 +447,7 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status, gssntlm_release_cred(&tmpmin, (gss_cred_id_t *)&cred); } gssntlm_release_name(&tmpmin, (gss_name_t *)&client_name); + gssntlm_release_name(&tmpmin, (gss_name_t *)&anonymous); safefree(computer_name); safefree(nb_computer_name); safefree(nb_domain_name); diff --git a/tests/ntlmssptest.c b/tests/ntlmssptest.c index f7cb0b7..b9bef3e 100644 --- a/tests/ntlmssptest.c +++ b/tests/ntlmssptest.c @@ -2153,7 +2153,7 @@ int test_gssapi_rfc5587(void) return EINVAL; } - if (mech_attrs->count != 9) { + if (mech_attrs->count != 10) { fprintf(stderr, "expected 9 mech_attr oids, got %lu\n", mech_attrs->count); return EINVAL; From d3c6ec4a589ea6ea429daa5fe213ef7e67a91ec2 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 19 May 2020 12:09:47 -0400 Subject: [PATCH 4/4] Test anonymous authentication Signed-off-by: Simo Sorce --- tests/ntlmssptest.c | 239 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) diff --git a/tests/ntlmssptest.c b/tests/ntlmssptest.c index b9bef3e..d552686 100644 --- a/tests/ntlmssptest.c +++ b/tests/ntlmssptest.c @@ -2261,6 +2261,240 @@ int test_ZERO_LMKEY(struct ntlm_ctx *ctx) return test_keys("results", &MS_SessionKey, &result); } +int test_gssapi_anon(void) +{ + gss_ctx_id_t cli_ctx = GSS_C_NO_CONTEXT; + gss_ctx_id_t srv_ctx = GSS_C_NO_CONTEXT; + gss_buffer_desc cli_token = { 0 }; + gss_buffer_desc srv_token = { 0 }; + gss_buffer_desc ctx_token; + gss_cred_id_t cli_cred = GSS_C_NO_CREDENTIAL; + gss_cred_id_t srv_cred = GSS_C_NO_CREDENTIAL; + const char *srvname = "test@testserver"; + gss_name_t gss_username = NULL; + gss_name_t gss_srvname = NULL; + gss_buffer_desc nbuf; + uint32_t retmin, retmaj; + const char *msg = "Sample, payload checking, message."; + gss_buffer_desc message = { strlen(msg), discard_const(msg) }; + int ret; + + setenv("NTLM_ALLOW_ANONYMOUS", "1", 1); + + retmaj = gssntlm_import_name(&retmin, &nbuf, + GSS_C_NT_ANONYMOUS, + &gss_username); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_import_name(anonymous) failed!", + retmaj, retmin); + return EINVAL; + } + + nbuf.value = discard_const(srvname); + nbuf.length = strlen(srvname); + retmaj = gssntlm_import_name(&retmin, &nbuf, + GSS_C_NT_HOSTBASED_SERVICE, + &gss_srvname); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_import_name(srvname) failed!", + retmaj, retmin); + return EINVAL; + } + + retmaj = gssntlm_acquire_cred(&retmin, (gss_name_t)gss_srvname, + GSS_C_INDEFINITE, GSS_C_NO_OID_SET, + GSS_C_ACCEPT, &srv_cred, NULL, NULL); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_acquire_cred(srvname) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + retmaj = gssntlm_init_sec_context(&retmin, cli_cred, &cli_ctx, + gss_srvname, GSS_C_NO_OID, + GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG, + 0, GSS_C_NO_CHANNEL_BINDINGS, + GSS_C_NO_BUFFER, NULL, &cli_token, + NULL, NULL); + if (retmaj != GSS_S_CONTINUE_NEEDED) { + print_gss_error("gssntlm_init_sec_context 1 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + retmaj = gssntlm_accept_sec_context(&retmin, &srv_ctx, srv_cred, + &cli_token, GSS_C_NO_CHANNEL_BINDINGS, + NULL, NULL, &srv_token, + NULL, NULL, NULL); + if (retmaj != GSS_S_CONTINUE_NEEDED) { + print_gss_error("gssntlm_accept_sec_context 1 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + gss_release_buffer(&retmin, &cli_token); + + /* test importing and exporting context before it is fully estabished */ + retmaj = gssntlm_export_sec_context(&retmin, &srv_ctx, &ctx_token); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_export_sec_context 1 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + retmaj = gssntlm_import_sec_context(&retmin, &ctx_token, &srv_ctx); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_import_sec_context 1 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + gss_release_buffer(&retmin, &ctx_token); + + retmaj = gssntlm_init_sec_context(&retmin, cli_cred, &cli_ctx, + gss_srvname, GSS_C_NO_OID, + GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG, + 0, GSS_C_NO_CHANNEL_BINDINGS, + &srv_token, NULL, &cli_token, + NULL, NULL); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_init_sec_context 2 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + gss_release_buffer(&retmin, &srv_token); + + retmaj = gssntlm_accept_sec_context(&retmin, &srv_ctx, srv_cred, + &cli_token, GSS_C_NO_CHANNEL_BINDINGS, + NULL, NULL, &srv_token, + NULL, NULL, NULL); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_accept_sec_context 2 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + gss_release_buffer(&retmin, &cli_token); + gss_release_buffer(&retmin, &srv_token); + + /* test importing and exporting context after it is fully estabished */ + retmaj = gssntlm_export_sec_context(&retmin, &cli_ctx, &ctx_token); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_export_sec_context 2 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + retmaj = gssntlm_import_sec_context(&retmin, &ctx_token, &cli_ctx); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_import_sec_context 2 failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + gss_release_buffer(&retmin, &ctx_token); + + retmaj = gssntlm_get_mic(&retmin, cli_ctx, 0, &message, &cli_token); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_get_mic(cli) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + retmaj = gssntlm_verify_mic(&retmin, srv_ctx, &message, &cli_token, NULL); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_verify_mic(srv) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + gss_release_buffer(&retmin, &cli_token); + + retmaj = gssntlm_get_mic(&retmin, srv_ctx, 0, &message, &srv_token); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_get_mic(srv) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + retmaj = gssntlm_verify_mic(&retmin, cli_ctx, &message, &srv_token, NULL); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_verify_mic(cli) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + gss_release_buffer(&retmin, &srv_token); + + retmaj = gssntlm_wrap(&retmin, cli_ctx, 1, 0, &message, NULL, &cli_token); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_wrap(cli) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + retmaj = gssntlm_unwrap(&retmin, srv_ctx, &cli_token, &srv_token, + NULL, NULL); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_unwrap(srv) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + gss_release_buffer(&retmin, &cli_token); + gss_release_buffer(&retmin, &srv_token); + + retmaj = gssntlm_wrap(&retmin, srv_ctx, 1, 0, &message, NULL, &srv_token); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_wrap(srv) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + retmaj = gssntlm_unwrap(&retmin, cli_ctx, &srv_token, &cli_token, + NULL, NULL); + if (retmaj != GSS_S_COMPLETE) { + print_gss_error("gssntlm_unwrap(cli) failed!", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + if (memcmp(message.value, cli_token.value, cli_token.length) != 0) { + print_gss_error("sealing and unsealing failed to return the " + "same result", + retmaj, retmin); + ret = EINVAL; + goto done; + } + + ret = 0; + +done: + gssntlm_delete_sec_context(&retmin, &cli_ctx, GSS_C_NO_BUFFER); + gssntlm_delete_sec_context(&retmin, &srv_ctx, GSS_C_NO_BUFFER); + gssntlm_release_name(&retmin, &gss_username); + gssntlm_release_name(&retmin, &gss_srvname); + gssntlm_release_cred(&retmin, &cli_cred); + gssntlm_release_cred(&retmin, &srv_cred); + gss_release_buffer(&retmin, &cli_token); + gss_release_buffer(&retmin, &srv_token); + return ret; +} + int main(int argc, const char *argv[]) { struct ntlm_ctx *ctx; @@ -2479,6 +2713,11 @@ int main(int argc, const char *argv[]) fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS")); if (ret) gret++; + fprintf(stderr, "Test Anonymous Auth\n"); + ret = test_gssapi_anon(); + fprintf(stderr, "Test: %s\n", (ret ? "FAIL":"SUCCESS")); + if (ret) gret++; + done: ntlm_free_ctx(&ctx); return gret;