krb5_error_code k5_kt_get_principal(krb5_context context, krb5_keytab keytab,
krb5_principal *princ_out);
+krb5_error_code k5_kt_have_match(krb5_context context, krb5_keytab keytab,
+ krb5_principal mprinc);
+
krb5_error_code krb5_principal2salt_norealm(krb5_context, krb5_const_principal,
krb5_data *);
{
krb5_error_code code;
krb5_keytab_entry ent;
- krb5_kt_cursor cursor;
krb5_principal accprinc = NULL;
- krb5_boolean match;
char *princname;
if (name->service == NULL) {
return code;
/* Scan the keytab for host-based entries matching accprinc. */
- code = krb5_kt_start_seq_get(context, kt, &cursor);
- if (code)
- goto cleanup;
- while ((code = krb5_kt_next_entry(context, kt, &ent, &cursor)) == 0) {
- match = krb5_sname_match(context, accprinc, ent.principal);
- (void)krb5_free_keytab_entry_contents(context, &ent);
- if (match)
- break;
- }
- (void)krb5_kt_end_seq_get(context, kt, &cursor);
- if (code == KRB5_KT_END) {
- code = KRB5_KT_NOTFOUND;
+ code = k5_kt_have_match(context, kt, accprinc);
+ if (code == KRB5_KT_NOTFOUND) {
if (krb5_unparse_name(context, accprinc, &princname) == 0) {
k5_setmsg(context, code, _("No key table entry found matching %s"),
princname);
free(princname);
}
}
-
-cleanup:
krb5_free_principal(context, accprinc);
return code;
}
#ifndef LEAN_CLIENT
#include "k5-int.h"
+#include "../krb/int-proto.h"
+#include "../os/os-proto.h"
const char * KRB5_CALLCONV
krb5_kt_get_type (krb5_context context, krb5_keytab keytab)
return KRB5_KT_NOTFOUND;
}
+static krb5_error_code
+match_entries(krb5_context context, krb5_keytab keytab,
+ krb5_const_principal mprinc)
+{
+ krb5_error_code ret;
+ krb5_keytab_entry ent;
+ krb5_kt_cursor cursor;
+ krb5_boolean match;
+
+ /* Scan the keytab for host-based entries matching accprinc. */
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret)
+ return ret;
+ while ((ret = krb5_kt_next_entry(context, keytab, &ent, &cursor)) == 0) {
+ match = krb5_sname_match(context, mprinc, ent.principal);
+ (void)krb5_free_keytab_entry_contents(context, &ent);
+ if (match)
+ break;
+ }
+ (void)krb5_kt_end_seq_get(context, keytab, &cursor);
+ if (ret && ret != KRB5_KT_END)
+ return ret;
+ return match ? 0 : KRB5_KT_NOTFOUND;
+}
+
+krb5_error_code
+k5_kt_have_match(krb5_context context, krb5_keytab keytab,
+ krb5_principal mprinc)
+{
+ krb5_error_code ret;
+ struct canonprinc iter = { mprinc, .no_hostrealm = TRUE };
+ krb5_const_principal canonprinc = NULL;
+
+ /* Don't try to canonicalize if we're going to ignore hostnames. */
+ if (k5_sname_wildcard_host(context, mprinc))
+ return match_entries(context, keytab, mprinc);
+
+ while ((ret = k5_canonprinc(context, &iter, &canonprinc)) == 0 &&
+ canonprinc != NULL) {
+ ret = match_entries(context, keytab, canonprinc);
+ if (ret != KRB5_KT_NOTFOUND)
+ break;
+ }
+ free_canonprinc(&iter);
+ return (ret == 0 && canonprinc == NULL) ? KRB5_KT_NOTFOUND : ret;
+}
+
/*
* In a couple of places we need to get a principal name from a keytab: when
* verifying credentials against a keytab, and when querying the name of a
krb5_ccache ccache, krb5_creds *in_creds,
krb5_creds **out_creds);
+/* Return true if mprinc will match any hostname in a host-based principal name
+ * (possibly due to ignore_acceptor_hostname) with krb5_sname_match(). */
+krb5_boolean
+k5_sname_wildcard_host(krb5_context context, krb5_const_principal mprinc);
+
#endif /* KRB5_INT_FUNC_PROTO__ */
struct canonprinc iter = { server, .no_hostrealm = TRUE };
krb5_const_principal canonprinc;
- /* Don't try to canonicalize if we're going to ignore the hostname, or if
- * server is null or has a wildcard hostname. */
- if (context->ignore_acceptor_hostname || server == NULL ||
- (server->length == 2 && server->data[1].length == 0))
+ /* Don't try to canonicalize if we're going to ignore hostnames. */
+ if (k5_sname_wildcard_host(context, server))
return decrypt_try_server(context, req, server, keytab, keyblock_out);
/* Try each canonicalization candidate for server. If they all fail,
*/
#include "k5-int.h"
+#include "int-proto.h"
krb5_boolean KRB5_CALLCONV
krb5_sname_match(krb5_context context, krb5_const_principal matching,
/* All elements match. */
return TRUE;
}
+
+krb5_boolean
+k5_sname_wildcard_host(krb5_context context, krb5_const_principal mprinc)
+{
+ if (mprinc == NULL)
+ return TRUE;
+
+ if (mprinc->type != KRB5_NT_SRV_HST || mprinc->length != 2)
+ return FALSE;
+
+ return context->ignore_acceptor_hostname || mprinc->data[1].length == 0;
+}
k5_internalize_principal
k5_is_string_numeric
k5_kt_get_principal
+k5_kt_have_match
k5_localauth_free_context
k5_locate_kdc
k5_marshal_cred
; new in 1.19
k5_cc_store_primary_cred @470 ; PRIVATE
+ k5_kt_have_match @471 ; PRIVATE GSSAPI
realm.run(['./t_iov', '-s', 'p:' + realm.host_princ])
realm.run(['./t_pcontok', 'p:' + realm.host_princ])
+realm = K5Realm(krb5_conf={'libdefaults': {'rdns': 'false'}})
+
# Test gss_add_cred().
-realm = K5Realm()
realm.run(['./t_add_cred'])
### Test acceptor name behavior.
'h:host@%s' % socket.gethostname()], expected_code=1,
expected_msg=' not found in keytab')
+# If possible, test with an acceptor name requiring fallback to match
+# against a keytab entry. Forward-canonicalize the hostname, relying
+# on the rdns=false realm setting.
+try:
+ ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
+ (family, socktype, proto, canonname, sockaddr) = ai[0]
+except socket.gaierror:
+ canonname = hostname
+if canonname != hostname:
+ os.rename(realm.keytab, realm.keytab + '.save')
+ canonprinc = 'host/' + canonname
+ realm.run([kadminl, 'addprinc', '-randkey', canonprinc])
+ realm.extract_keytab(canonprinc, realm.keytab)
+ # Use the canonical name for the initiator's target name, since
+ # host/hostname exists in the KDB (but not the keytab).
+ realm.run(['./t_accname', 'h:host@' + canonname, 'h:host@' + hostname])
+ os.rename(realm.keytab + '.save', realm.keytab)
+else:
+ skipped('GSS acceptor name fallback test',
+ '%s does not canonicalize to a different name' % hostname)
+
# Test krb5_gss_import_cred.
realm.run(['./t_imp_cred', 'p:service1/barack'])
realm.run(['./t_imp_cred', 'p:service1/barack', 'service1/barack'])