@@ -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+
339383static 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
10311125static 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+
10821200static 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" ),
0 commit comments