Skip to content

Commit db999f9

Browse files
committed
Add GssapiBasicAuthMech option
This option allows to set a different list of mechanisms to use with Basic Auth (Basic Auth must be explicitly enabled) than the list of mechs that are allowed with Negotiate or Raw GSSAPI Client authentication. Signed-off-by: Simo Sorce <simo@redhat.com>
1 parent 79cb8bb commit db999f9

File tree

3 files changed

+157
-22
lines changed

3 files changed

+157
-22
lines changed

README

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,16 @@ are allowed. The recognized mechanism names are: krb5, iakerb, ntlmssp
216216
Example:
217217
GssapiAllowedMech krb5
218218
GssapiAllowedMech ntlmssp
219+
220+
221+
### GssapiBasicAuthMech
222+
223+
List of mechanisms against which Basic Auth is attempted. This is useful to
224+
restrict the mechanisms that can be used to attaempt password auth.
225+
By default no mechanism is set, this means all locally available mechanisms
226+
are allowed, unless GssapiAllowedMech is set, in which case those are used.
227+
GssapiBasicAuthMech always takes precendence over GssapiAllowedMech.
228+
The recognized mechanism names are: krb5, iakerb, ntlmssp
229+
230+
Example:
231+
GssapiBasicAuthMech krb5

src/mod_auth_gssapi.c

Lines changed: 142 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,50 @@ static void mag_set_req_data(request_rec *req,
336336
}
337337
}
338338

339+
gss_OID_set mag_filter_unwanted_mechs(gss_OID_set src)
340+
{
341+
gss_const_OID unwanted_mechs[] = {
342+
&gss_mech_spnego,
343+
gss_mech_krb5_old,
344+
gss_mech_krb5_wrong,
345+
gss_mech_iakerb,
346+
GSS_C_NO_OID
347+
};
348+
gss_OID_set dst;
349+
uint32_t maj, min;
350+
int present = 0;
351+
352+
for (int i = 0; unwanted_mechs[i] != GSS_C_NO_OID; i++) {
353+
maj = gss_test_oid_set_member(&min,
354+
discard_const(unwanted_mechs[i]),
355+
src, &present);
356+
if (present) break;
357+
}
358+
if (present) {
359+
maj = gss_create_empty_oid_set(&min, &dst);
360+
if (maj != GSS_S_COMPLETE) {
361+
return GSS_C_NO_OID_SET;
362+
}
363+
for (int i = 0; i < src->count; i++) {
364+
present = 0;
365+
for (int j = 0; unwanted_mechs[j] != GSS_C_NO_OID; j++) {
366+
if (gss_oid_equal(&src->elements[i], unwanted_mechs[j])) {
367+
present = 1;
368+
break;
369+
}
370+
}
371+
if (present) continue;
372+
maj = gss_add_oid_set_member(&min, &src->elements[i], &dst);
373+
if (maj != GSS_S_COMPLETE) {
374+
gss_release_oid_set(&min, &dst);
375+
return GSS_C_NO_OID_SET;
376+
}
377+
}
378+
return dst;
379+
}
380+
return src;
381+
}
382+
339383
static bool mag_auth_basic(request_rec *req,
340384
struct mag_config *cfg,
341385
gss_buffer_desc ba_user,
@@ -360,7 +404,9 @@ static bool mag_auth_basic(request_rec *req,
360404
gss_ctx_id_t server_ctx = GSS_C_NO_CONTEXT;
361405
gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
362406
gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
363-
gss_OID_set allowed_mechs = GSS_C_NO_OID_SET;
407+
gss_OID_set indicated_mechs = GSS_C_NO_OID_SET;
408+
gss_OID_set allowed_mechs;
409+
gss_OID_set filtered_mechs;
364410
gss_OID_set_desc all_mechs_desc;
365411
gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
366412
uint32_t init_flags = 0;
@@ -395,10 +441,56 @@ static bool mag_auth_basic(request_rec *req,
395441
goto done;
396442
}
397443

398-
if (cfg->allowed_mechs && cfg->allowed_mechs->count > 1) {
399-
all_mechs_desc.count = cfg->allowed_mechs->count - 1;
400-
all_mechs_desc.elements = &cfg->allowed_mechs->elements[1];
401-
allowed_mechs = &all_mechs_desc;
444+
if (cfg->basic_mechs) {
445+
allowed_mechs = cfg->basic_mechs;
446+
} else if (cfg->allowed_mechs) {
447+
allowed_mechs = cfg->allowed_mechs;
448+
} else {
449+
/* Try to fetch the default set if not explicitly configured,
450+
* We need to do this because gss_acquire_cred_with_password()
451+
* is currently limited to acquire creds for a single "default"
452+
* mechanism if no desired mechanisms are passed in. This causes
453+
* authentication to fail for secondary mechanisms as no user
454+
* credentials are generated for those. */
455+
maj = gss_indicate_mechs(&min, &indicated_mechs);
456+
if (maj != GSS_S_COMPLETE) {
457+
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "%s",
458+
mag_error(req, "gss_indicate_mechs() failed",
459+
maj, min));
460+
/* if indicated _mechs failed, set GSS_C_NO_OID_SET. This
461+
* generally causes only the krb5 mechanism to be tried due
462+
* to implementation constraints, but may change in future. */
463+
allowed_mechs = GSS_C_NO_OID_SET;
464+
} else {
465+
allowed_mechs = indicated_mechs;
466+
}
467+
}
468+
469+
/* Remove Spnego if present, or we'd repeat failed authentiations
470+
* multiple times, one within Spnego and then again with an explicit
471+
* mechanism. We would normally just force Spnego and use
472+
* gss_set_neg_mechs, but due to the way we source the server name
473+
* and the fact MIT up to 1.14 at least does no handle union names,
474+
* we can't provide spnego with a server name that can be used by
475+
* multiple mechanisms, causing any but the first mechanism to fail.
476+
* Also remove unwanted krb mechs, or AS requests will be repeated
477+
* multiple times uselessly.
478+
*/
479+
filtered_mechs = mag_filter_unwanted_mechs(allowed_mechs);
480+
if (filtered_mechs == GSS_C_NO_OID_SET) {
481+
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "Fatal "
482+
"failure while filtering mechs, aborting");
483+
goto done;
484+
} else if (filtered_mechs != allowed_mechs) {
485+
/* if indicated_mechs where sourced then free them here before
486+
* reusing the pointer */
487+
gss_release_oid_set(&min, &indicated_mechs);
488+
489+
/* mark the list of mechs needs to be freed */
490+
indicated_mechs = filtered_mechs;
491+
492+
/* use the filtered list */
493+
allowed_mechs = filtered_mechs;
402494
}
403495

404496
maj = gss_acquire_cred_with_password(&min, user, &ba_pwd,
@@ -423,8 +515,7 @@ static bool mag_auth_basic(request_rec *req,
423515

424516
for (int i = 0; i < actual_mechs->count; i++) {
425517

426-
/* skip spnego if present (it is usually present when
427-
* cfg->allowed_mechs is not set) */
518+
/* skip spnego if present */
428519
if (gss_oid_equal(&actual_mechs->elements[i],
429520
&gss_mech_spnego)) {
430521
continue;
@@ -438,6 +529,7 @@ static bool mag_auth_basic(request_rec *req,
438529

439530
all_mechs_desc.count = 1;
440531
all_mechs_desc.elements = &actual_mechs->elements[i];
532+
allowed_mechs = &all_mechs_desc;
441533

442534
/* must acquire with GSS_C_ACCEPT to get the server name */
443535
if (!mag_acquire_creds(req, cfg, allowed_mechs,
@@ -504,6 +596,7 @@ static bool mag_auth_basic(request_rec *req,
504596
gss_release_cred(&min, &user_cred);
505597
gss_delete_sec_context(&min, &user_ctx, GSS_C_NO_BUFFER);
506598
gss_release_oid_set(&min, &actual_mechs);
599+
gss_release_oid_set(&min, &indicated_mechs);
507600
#ifdef HAVE_GSS_KRB5_CCACHE_NAME
508601
if (user_ccache != NULL) {
509602
maj = gss_krb5_ccache_name(&min, orig_ccache, NULL);
@@ -1028,31 +1121,36 @@ static const char *mag_deleg_ccache_dir(cmd_parms *parms, void *mconfig,
10281121
}
10291122
#endif
10301123

1124+
#ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
10311125
static const char *mag_use_basic_auth(cmd_parms *parms, void *mconfig, int on)
10321126
{
10331127
struct mag_config *cfg = (struct mag_config *)mconfig;
10341128

10351129
cfg->use_basic_auth = on ? true : false;
10361130
return NULL;
10371131
}
1132+
#endif
10381133

10391134
#define MAX_ALLOWED_MECHS 10
10401135

1041-
static const char *mag_allow_mech(cmd_parms *parms, void *mconfig,
1042-
const char *w)
1136+
static void mag_list_of_mechs(cmd_parms *parms, gss_OID_set *oidset,
1137+
bool add_spnego, const char *w)
10431138
{
1044-
struct mag_config *cfg = (struct mag_config *)mconfig;
10451139
gss_const_OID oid;
1140+
gss_OID_set set;
10461141
size_t size;
10471142

1048-
if (!cfg->allowed_mechs) {
1049-
cfg->allowed_mechs = apr_pcalloc(parms->pool,
1050-
sizeof(gss_OID_set_desc));
1143+
if (NULL == *oidset) {
1144+
set = apr_pcalloc(parms->pool, sizeof(gss_OID_set_desc));
10511145
size = sizeof(gss_OID) * MAX_ALLOWED_MECHS;
1052-
cfg->allowed_mechs->elements = apr_palloc(parms->pool, size);
1053-
1054-
cfg->allowed_mechs->elements[0] = gss_mech_spnego;
1055-
cfg->allowed_mechs->count++;
1146+
set->elements = apr_palloc(parms->pool, size);
1147+
if (add_spnego) {
1148+
set->elements[0] = gss_mech_spnego;
1149+
set->count++;
1150+
}
1151+
*oidset = set;
1152+
} else {
1153+
set = *oidset;
10561154
}
10571155

10581156
if (strcmp(w, "krb5") == 0) {
@@ -1064,21 +1162,41 @@ static const char *mag_allow_mech(cmd_parms *parms, void *mconfig,
10641162
} else {
10651163
ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server,
10661164
"Unrecognized GSSAPI Mechanism: %s", w);
1067-
return NULL;
1165+
return;
10681166
}
10691167

1070-
if (cfg->allowed_mechs->count >= MAX_ALLOWED_MECHS) {
1168+
if (set->count >= MAX_ALLOWED_MECHS) {
10711169
ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server,
10721170
"Too many GssapiAllowedMech options (MAX: %d)",
10731171
MAX_ALLOWED_MECHS);
1074-
return NULL;
1172+
return;
10751173
}
1076-
cfg->allowed_mechs->elements[cfg->allowed_mechs->count] = *oid;
1077-
cfg->allowed_mechs->count++;
1174+
set->elements[set->count] = *oid;
1175+
set->count++;
1176+
}
1177+
1178+
static const char *mag_allow_mech(cmd_parms *parms, void *mconfig,
1179+
const char *w)
1180+
{
1181+
struct mag_config *cfg = (struct mag_config *)mconfig;
1182+
1183+
mag_list_of_mechs(parms, &cfg->allowed_mechs, true, w);
10781184

10791185
return NULL;
10801186
}
10811187

1188+
#ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
1189+
static const char *mag_basic_auth_mechs(cmd_parms *parms, void *mconfig,
1190+
const char *w)
1191+
{
1192+
struct mag_config *cfg = (struct mag_config *)mconfig;
1193+
1194+
mag_list_of_mechs(parms, &cfg->basic_mechs, false, w);
1195+
1196+
return NULL;
1197+
}
1198+
#endif
1199+
10821200
static const command_rec mag_commands[] = {
10831201
AP_INIT_FLAG("GssapiSSLonly", mag_ssl_only, NULL, OR_AUTHCFG,
10841202
"Work only if connection is SSL Secured"),
@@ -1103,6 +1221,8 @@ static const command_rec mag_commands[] = {
11031221
#ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
11041222
AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG,
11051223
"Allows use of Basic Auth for authentication"),
1224+
AP_INIT_ITERATE("GssapiBasicAuthMech", mag_basic_auth_mechs, NULL,
1225+
OR_AUTHCFG, "Mechanisms to use for basic auth"),
11061226
#endif
11071227
AP_INIT_ITERATE("GssapiAllowedMech", mag_allow_mech, NULL, OR_AUTHCFG,
11081228
"Allowed Mechanisms"),

src/mod_auth_gssapi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ struct mag_config {
5555
gss_key_value_set_desc *cred_store;
5656
#endif
5757
struct seal_key *mag_skey;
58+
5859
bool use_basic_auth;
5960
gss_OID_set_desc *allowed_mechs;
61+
gss_OID_set_desc *basic_mechs;
6062
};
6163

6264
struct mag_conn {

0 commit comments

Comments
 (0)