From 8264474735224395e32217862a39abc1f8d0e98b Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Sun, 14 Jun 2015 18:56:01 +0300 Subject: [PATCH 1/4] Enforce GssapiAllowedMech over raw gssapi mechs Implemented by aqcuiring creds only for allowed_mechs and by explicity adding spnego to the allowed_mechs set (while still restricting spengo only to the allowed mechanism as before). --- src/mod_auth_gssapi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index f345efc..ffcd215 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -24,6 +24,10 @@ #include "mod_auth_gssapi.h" +const gss_OID_desc gss_mech_spnego = { + 6, "\x2b\x06\x01\x05\x05\x02" +}; + const gss_OID_desc gss_mech_ntlmssp = { GSS_NTLMSSP_OID_LENGTH, GSS_NTLMSSP_OID_STRING }; @@ -530,6 +534,8 @@ static int mag_auth(request_rec *req) (void)gss_release_cred(&min, &server_cred); } + desired_mechs = cfg->allowed_mechs; + /* implicit auth for subrequests if main auth already happened */ if (!ap_is_initial_req(req) && req->main != NULL) { type = ap_auth_type(req->main); @@ -1009,6 +1015,9 @@ static const char *mag_allow_mech(cmd_parms *parms, void *mconfig, sizeof(gss_OID_set_desc)); size = sizeof(gss_OID) * MAX_ALLOWED_MECHS; cfg->allowed_mechs->elements = apr_palloc(parms->pool, size); + + cfg->allowed_mechs->elements[0] = gss_mech_spnego; + cfg->allowed_mechs->count++; } if (strcmp(w, "krb5") == 0) { From bc83d036ffc844b676fce919357ebb208b4812f4 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 16 Jun 2015 15:07:37 -0400 Subject: [PATCH 2/4] Better handling of desired_mechs If no explicit allowed mechanism is set in configuration just ask gssapi for a list of known mechanisms and use that. do not try to artificially acquire credentials as ultimatily all that does is just call gss_inidicate_mechs() internally. Do not store the result of gss_inidicate_mechs() on cfg->allowed_mechs as that would lead to a leak fiven cfg->allowed_mechs is considered allocated on a memory pool, while gss_inidate_mechs()s results are not. Signed-off-by: Simo Sorce --- src/mod_auth_gssapi.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index ffcd215..e1ecc36 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -514,6 +514,7 @@ static int mag_auth(request_rec *req) char *clientname; gss_OID mech_type = GSS_C_NO_OID; gss_OID_set desired_mechs = GSS_C_NO_OID_SET; + gss_OID_set indicated_mechs = GSS_C_NO_OID_SET; gss_buffer_desc lname = GSS_C_EMPTY_BUFFER; struct mag_conn *mc = NULL; time_t expiration; @@ -526,16 +527,19 @@ static int mag_auth(request_rec *req) cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module); - if (!cfg->allowed_mechs) { + if (cfg->allowed_mechs) { + desired_mechs = cfg->allowed_mechs; + } else { /* Try to fetch the default set if not explicitly configured */ - gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL; - (void)mag_acquire_creds(req, cfg, GSS_C_NO_OID_SET, GSS_C_ACCEPT, - &server_cred, &cfg->allowed_mechs); - (void)gss_release_cred(&min, &server_cred); + maj = gss_indicate_mechs(&min, &indicated_mechs); + if (maj != GSS_S_COMPLETE) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "%s", + mag_error(req, "gss_indicate_mechs() failed", + maj, min)); + } + desired_mechs = indicated_mechs; } - desired_mechs = cfg->allowed_mechs; - /* implicit auth for subrequests if main auth already happened */ if (!ap_is_initial_req(req) && req->main != NULL) { type = ap_auth_type(req->main); @@ -827,6 +831,7 @@ static int mag_auth(request_rec *req) ap_auth_name(req))); } } + gss_release_oid_set(&min, &indicated_mechs); if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER); gss_release_cred(&min, &acquired_cred); From 12d2bb3a156a4cfcc50ce45184d547c1eb2b4ab3 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 16 Jun 2015 16:06:57 -0400 Subject: [PATCH 3/4] wip --- src/mod_auth_gssapi.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index e1ecc36..6819c80 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -361,6 +361,8 @@ static bool mag_auth_basic(request_rec *req, gss_ctx_id_t server_ctx = GSS_C_NO_CONTEXT; gss_buffer_desc input = GSS_C_EMPTY_BUFFER; gss_buffer_desc output = GSS_C_EMPTY_BUFFER; + gss_OID_set allowed_mechs = GSS_C_NO_OID_SET; + gss_OID_set_desc all_mechs_desc; uint32_t init_flags = 0; uint32_t maj, min; bool ret = false; @@ -393,9 +395,15 @@ static bool mag_auth_basic(request_rec *req, goto done; } + if (cfg->allowed_mechs && cfg->allowed_mechs->count > 1) { + all_mechs_desc.count = cfg->allowed_mechs->count - 1; + all_mechs_desc.elements = &cfg->allowed_mechs->elements[1]; + allowed_mechs = &all_mechs_desc; + } + maj = gss_acquire_cred_with_password(&min, user, &ba_pwd, GSS_C_INDEFINITE, - cfg->allowed_mechs, + allowed_mechs, GSS_C_INITIATE, &user_cred, NULL, NULL); if (GSS_ERROR(maj)) { @@ -411,7 +419,7 @@ static bool mag_auth_basic(request_rec *req, * name instead of the SPN of the server credentials. Therefore we * need to acquire a different set of credential setting * GSS_C_ACCEPT explicitly */ - if (!mag_acquire_creds(req, cfg, cfg->allowed_mechs, + if (!mag_acquire_creds(req, cfg, allowed_mechs, GSS_C_ACCEPT, &server_cred, NULL)) { goto done; } From 353a396fc6f7921e6ff5171d5826d43cb8182e86 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 16 Jun 2015 18:05:23 -0400 Subject: [PATCH 4/4] Fix Basic Auth with non-krb5 mechanisms Try each allowed mechanism explicitly in a loop including sourcing the server name per mechanism to insure the proper name type is used in the accept. Otherwise secondary mechanims will fail to work. Fixes #43 Signed-off-by: Simo Sorce --- src/mod_auth_gssapi.c | 130 ++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index 6819c80..3c578de 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -340,7 +340,6 @@ static bool mag_auth_basic(request_rec *req, struct mag_config *cfg, gss_buffer_desc ba_user, gss_buffer_desc ba_pwd, - gss_cred_id_t acquired_cred, gss_cred_usage_t cred_usage, gss_name_t *client, gss_OID *mech_type, @@ -363,6 +362,7 @@ static bool mag_auth_basic(request_rec *req, gss_buffer_desc output = GSS_C_EMPTY_BUFFER; gss_OID_set allowed_mechs = GSS_C_NO_OID_SET; gss_OID_set_desc all_mechs_desc; + gss_OID_set actual_mechs = GSS_C_NO_OID_SET; uint32_t init_flags = 0; uint32_t maj, min; bool ret = false; @@ -405,7 +405,7 @@ static bool mag_auth_basic(request_rec *req, GSS_C_INDEFINITE, allowed_mechs, GSS_C_INITIATE, - &user_cred, NULL, NULL); + &user_cred, &actual_mechs, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", @@ -414,27 +414,6 @@ static bool mag_auth_basic(request_rec *req, goto done; } - if (cred_usage == GSS_C_BOTH) { - /* If GSS_C_BOTH is used then inquire_cred will return the client - * name instead of the SPN of the server credentials. Therefore we - * need to acquire a different set of credential setting - * GSS_C_ACCEPT explicitly */ - if (!mag_acquire_creds(req, cfg, allowed_mechs, - GSS_C_ACCEPT, &server_cred, NULL)) { - goto done; - } - } else { - server_cred = acquired_cred; - } - maj = gss_inquire_cred(&min, server_cred, &server, - NULL, NULL, NULL); - if (GSS_ERROR(maj)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, - "%s", mag_error(req, "gss_inquired_cred_() " - "failed", maj, min)); - goto done; - } - #ifdef HAVE_CRED_STORE if (cfg->deleg_ccache_dir) { /* delegate ourselves credentials so we store them as requested */ @@ -442,45 +421,89 @@ static bool mag_auth_basic(request_rec *req, } #endif - do { - /* output and input are inverted here, this is intentional */ - maj = gss_init_sec_context(&min, user_cred, &user_ctx, server, - GSS_C_NO_OID, init_flags, 300, - GSS_C_NO_CHANNEL_BINDINGS, &output, - NULL, &input, NULL, NULL); - if (GSS_ERROR(maj)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, - "%s", mag_error(req, "gss_init_sec_context() " - "failed", maj, min)); - goto done; + for (int i = 0; i < actual_mechs->count; i++) { + + /* skip spnego if present (it is usually present when + * cfg->allowed_mechs is not set) */ + if (gss_oid_equal(&actual_mechs->elements[i], + &gss_mech_spnego)) { + continue; } + + /* free these if looping */ gss_release_buffer(&min, &output); - maj = gss_accept_sec_context(&min, &server_ctx, acquired_cred, - &input, GSS_C_NO_CHANNEL_BINDINGS, - client, mech_type, &output, NULL, - vtime, delegated_cred); + gss_release_buffer(&min, &input); + gss_release_name(&min, &server); + gss_release_cred(&min, &server_cred); + + all_mechs_desc.count = 1; + all_mechs_desc.elements = &actual_mechs->elements[i]; + + /* must acquire with GSS_C_ACCEPT to get the server name */ + if (!mag_acquire_creds(req, cfg, allowed_mechs, + GSS_C_ACCEPT, &server_cred, NULL)) { + continue; + } + maj = gss_inquire_cred(&min, server_cred, &server, + NULL, NULL, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, - "%s", mag_error(req, "gss_accept_sec_context()" - " failed", maj, min)); - goto done; + "%s", mag_error(req, "gss_inquired_cred_() " + "failed", maj, min)); + continue; } - gss_release_buffer(&min, &input); - } while (maj == GSS_S_CONTINUE_NEEDED); - ret = true; + if (cred_usage == GSS_C_BOTH) { + /* reacquire server creds in order to allow delegation */ + gss_release_cred(&min, &server_cred); + if (!mag_acquire_creds(req, cfg, allowed_mechs, + GSS_C_BOTH, &server_cred, NULL)) { + continue; + } + } + + do { + /* output and input are inverted here, this is intentional */ + maj = gss_init_sec_context(&min, user_cred, &user_ctx, server, + &actual_mechs->elements[i], init_flags, + 300, GSS_C_NO_CHANNEL_BINDINGS, &output, + NULL, &input, NULL, NULL); + if (GSS_ERROR(maj)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, + "%s", mag_error(req, "gss_init_sec_context() " + "failed", maj, min)); + break; + } + gss_release_buffer(&min, &output); + maj = gss_accept_sec_context(&min, &server_ctx, server_cred, + &input, GSS_C_NO_CHANNEL_BINDINGS, + client, mech_type, &output, NULL, + vtime, delegated_cred); + if (GSS_ERROR(maj)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, + "%s", mag_error(req, "gss_accept_sec_context()" + " failed", maj, min)); + break; + } + gss_release_buffer(&min, &input); + } while (maj == GSS_S_CONTINUE_NEEDED); + + if (maj == GSS_S_COMPLETE) { + ret = true; + break; + } + } done: gss_release_buffer(&min, &output); gss_release_buffer(&min, &input); gss_release_name(&min, &server); - if (server_cred != acquired_cred) { - gss_release_cred(&min, &server_cred); - } + gss_release_cred(&min, &server_cred); gss_delete_sec_context(&min, &server_ctx, GSS_C_NO_BUFFER); gss_release_name(&min, &user); gss_release_cred(&min, &user_cred); gss_delete_sec_context(&min, &user_ctx, GSS_C_NO_BUFFER); + gss_release_oid_set(&min, &actual_mechs); #ifdef HAVE_GSS_KRB5_CCACHE_NAME if (user_ccache != NULL) { maj = gss_krb5_ccache_name(&min, orig_ccache, NULL); @@ -700,21 +723,20 @@ static int mag_auth(request_rec *req) cred_usage = GSS_C_BOTH; } #endif - if (!mag_acquire_creds(req, cfg, desired_mechs, - cred_usage, &acquired_cred, NULL)) { - goto done; - } - if (auth_type == AUTH_TYPE_BASIC) { if (mag_auth_basic(req, cfg, ba_user, ba_pwd, - acquired_cred, cred_usage, - &client, &mech_type, + cred_usage, &client, &mech_type, &delegated_cred, &vtime)) { goto complete; } goto done; } + if (!mag_acquire_creds(req, cfg, desired_mechs, + cred_usage, &acquired_cred, NULL)) { + goto done; + } + if (auth_type == AUTH_TYPE_NEGOTIATE && cfg->allowed_mechs != GSS_C_NO_OID_SET) { maj = gss_set_neg_mechs(&min, acquired_cred, cfg->allowed_mechs);