int nktypes, krb5_enctype *ktype)
{
int i;
- krb5_enctype first_permitted = 0;
for (i = 0; i < nktypes; i++) {
if (!krb5_c_valid_enctype(ktype[i]))
if (!krb5_is_permitted_enctype(context, ktype[i]))
continue;
- if (first_permitted == 0)
- first_permitted = ktype[i];
-
if (dbentry_supports_enctype(context, server, ktype[i]))
return ktype[i];
}
- /*
- * If we didn't find a match and the server is the local TGS server, this
- * could be a keytab-based AS request where the keytab enctypes don't
- * overlap the TGT principal enctypes. Try to make this work by using the
- * first permitted enctype in the request, even though we can't be certain
- * that other KDCs in the realm support it.
- */
- if (krb5_principal_compare(context, server->princ, tgs_server))
- return first_permitted;
-
return 0;
}
return ret;
}
-/* Return true if search_for is in etype_list. */
-static krb5_boolean
-check_etypes_have(krb5_enctype *etype_list, krb5_enctype search_for)
+/* Move the entries in keytab_list (zero-terminated) to the front of req_list
+ * (of length req_len), preserving order otherwise. */
+static krb5_error_code
+sort_enctypes(krb5_enctype *req_list, int req_len, krb5_enctype *keytab_list)
{
- int i;
-
- if (!etype_list)
- return FALSE;
-
- for (i = 0; etype_list[i] != 0; i++) {
- if (etype_list[i] == search_for)
- return TRUE;
+ krb5_enctype *save_list;
+ int save_pos, req_pos, i;
+
+ save_list = malloc(req_len * sizeof(*save_list));
+ if (save_list == NULL)
+ return ENOMEM;
+
+ /* Sort req_list entries into the front of req_list or into save_list. */
+ req_pos = save_pos = 0;
+ for (i = 0; i < req_len; i++) {
+ if (k5_etypes_contains(keytab_list, req_list[i]))
+ req_list[req_pos++] = req_list[i];
+ else
+ save_list[save_pos++] = req_list[i];
}
- return FALSE;
+ /* Put the entries we saved back in at the end, in order. */
+ for (i = 0; i < save_pos; i++)
+ req_list[req_pos++] = save_list[i];
+ assert(req_pos == req_len);
+
+ free(save_list);
+ return 0;
}
krb5_error_code KRB5_CALLCONV
{
krb5_enctype *etype_list;
krb5_error_code ret;
- int i, j;
char *name;
ctx->gak_fct = get_as_key_keytab;
TRACE_INIT_CREDS_KEYTAB_LOOKUP_FAILED(context, ret);
return 0;
}
-
TRACE_INIT_CREDS_KEYTAB_LOOKUP(context, etype_list);
- /* Filter the ktypes list based on what's in the keytab */
- for (i = 0, j = 0; i < ctx->request->nktypes; i++) {
- if (check_etypes_have(etype_list, ctx->request->ktype[i])) {
- ctx->request->ktype[j] = ctx->request->ktype[i];
- j++;
- }
- }
- ctx->request->nktypes = j;
- free(etype_list);
-
- /* Error out now if there's no overlap. */
- if (ctx->request->nktypes == 0) {
+ /* Error out if we have no keys for the client principal. */
+ if (etype_list == NULL) {
ret = krb5_unparse_name(context, ctx->request->client, &name);
if (ret == 0) {
krb5_set_error_message(context, KRB5_KT_NOTFOUND,
return KRB5_KT_NOTFOUND;
}
+ /* Sort the request enctypes so the ones in the keytab appear first. */
+ sort_enctypes(ctx->request->ktype, ctx->request->nktypes, etype_list);
+ free(etype_list);
return 0;
}