When user_realm is used by PAM, do likewise in kinit.
When PAM is configured to use a user_realm that is different from the default realm, do likewise in kinit with bare user names or the default principal computed from the login name. Similarly, when using a keytab, if no realm is specified find the most suitable match in the keytab file.
This commit is contained in:

committed by
Viktor Dukhovni

parent
4fcad71a3a
commit
3f3bcc2731
234
kuser/kinit.c
234
kuser/kinit.c
@@ -63,6 +63,7 @@ static int switch_cache_flags = 1;
|
|||||||
struct getarg_strings etype_str;
|
struct getarg_strings etype_str;
|
||||||
int use_keytab = 0;
|
int use_keytab = 0;
|
||||||
char *keytab_str = NULL;
|
char *keytab_str = NULL;
|
||||||
|
static krb5_keytab kt = NULL;
|
||||||
int do_afslog = -1;
|
int do_afslog = -1;
|
||||||
int fcache_version;
|
int fcache_version;
|
||||||
char *password_file = NULL;
|
char *password_file = NULL;
|
||||||
@@ -361,7 +362,6 @@ get_new_tickets(krb5_context context,
|
|||||||
const char *renewstr = NULL;
|
const char *renewstr = NULL;
|
||||||
krb5_enctype *enctype = NULL;
|
krb5_enctype *enctype = NULL;
|
||||||
krb5_ccache tempccache;
|
krb5_ccache tempccache;
|
||||||
krb5_keytab kt = NULL;
|
|
||||||
krb5_init_creds_context ctx;
|
krb5_init_creds_context ctx;
|
||||||
#ifndef NO_NTLM
|
#ifndef NO_NTLM
|
||||||
struct ntlm_buf ntlmkey;
|
struct ntlm_buf ntlmkey;
|
||||||
@@ -524,18 +524,9 @@ get_new_tickets(krb5_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (use_keytab || keytab_str) {
|
if (use_keytab || keytab_str) {
|
||||||
|
|
||||||
if (keytab_str)
|
|
||||||
ret = krb5_kt_resolve(context, keytab_str, &kt);
|
|
||||||
else
|
|
||||||
ret = krb5_kt_default(context, &kt);
|
|
||||||
if (ret)
|
|
||||||
krb5_err(context, 1, ret, "resolving keytab");
|
|
||||||
|
|
||||||
ret = krb5_init_creds_set_keytab(context, ctx, kt);
|
ret = krb5_init_creds_set_keytab(context, ctx, kt);
|
||||||
if (ret)
|
if (ret)
|
||||||
krb5_err(context, 1, ret, "krb5_init_creds_set_keytab");
|
krb5_err(context, 1, ret, "krb5_init_creds_set_keytab");
|
||||||
|
|
||||||
} else if (pk_user_id || ent_user_id || anonymous_flag) {
|
} else if (pk_user_id || ent_user_id || anonymous_flag) {
|
||||||
|
|
||||||
} else if (!interactive) {
|
} else if (!interactive) {
|
||||||
@@ -666,8 +657,6 @@ get_new_tickets(krb5_context context,
|
|||||||
|
|
||||||
krb5_get_init_creds_opt_free(context, opt);
|
krb5_get_init_creds_opt_free(context, opt);
|
||||||
|
|
||||||
if (kt)
|
|
||||||
krb5_kt_close(context, kt);
|
|
||||||
if (enctype)
|
if (enctype)
|
||||||
free(enctype);
|
free(enctype);
|
||||||
|
|
||||||
@@ -773,16 +762,204 @@ renew_func(void *ptr)
|
|||||||
return expire / 2 + 1;
|
return expire / 2 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_name_realm(krb5_context context,
|
||||||
|
const char *name,
|
||||||
|
int flags,
|
||||||
|
const char *realm,
|
||||||
|
krb5_principal *princ)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
ret = krb5_parse_name_flags_realm(context, name, flags, realm, princ);
|
||||||
|
if (ret)
|
||||||
|
krb5_err(context, 1, ret, "krb5_parse_name_flags_realm");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_default_realm(krb5_context context)
|
||||||
|
{
|
||||||
|
char *realm;
|
||||||
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
if ((ret = krb5_get_default_realm(context, &realm)) != 0)
|
||||||
|
krb5_err(context, 1, ret, "krb5_get_default_realm");
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_default_principal(krb5_context context, krb5_principal *princ)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
if ((ret = krb5_get_default_principal(context, princ)) != 0)
|
||||||
|
krb5_err(context, 1, ret, "krb5_get_default_principal");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_princ_realm(krb5_context context,
|
||||||
|
krb5_principal principal,
|
||||||
|
const char *realm)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
if ((ret = krb5_principal_set_realm(context, principal, realm)) != 0)
|
||||||
|
krb5_err(context, 1, ret, "krb5_principal_set_realm");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_user_realm(krb5_context context)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
char *user_realm = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If memory allocation fails, we don't try to use the wrong realm,
|
||||||
|
* that will trigger misleading error messages complicate support.
|
||||||
|
*/
|
||||||
|
krb5_appdefault_string(context, "kinit", NULL, "user_realm", "",
|
||||||
|
&user_realm);
|
||||||
|
if (user_realm == NULL) {
|
||||||
|
ret = krb5_enomem(context);
|
||||||
|
krb5_err(context, 1, ret, "krb5_appdefault_string");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*user_realm == 0) {
|
||||||
|
free(user_realm);
|
||||||
|
user_realm = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user_realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_princ(krb5_context context, krb5_principal *principal, const char *name)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
krb5_principal tmp;
|
||||||
|
int parseflags = 0;
|
||||||
|
char *user_realm;
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
krb5_ccache ccache;
|
||||||
|
|
||||||
|
/* If credential cache provides a client principal, use that. */
|
||||||
|
if (krb5_cc_default(context, &ccache) == 0) {
|
||||||
|
ret = krb5_cc_get_principal(context, ccache, principal);
|
||||||
|
krb5_cc_close(context, ccache);
|
||||||
|
if (ret == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user_realm = get_user_realm(context);
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
if (canonicalize_flag || enterprise_flag)
|
||||||
|
parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
|
||||||
|
|
||||||
|
parse_name_realm(context, name, parseflags, user_realm, &tmp);
|
||||||
|
|
||||||
|
if (user_realm && krb5_principal_get_num_comp(context, tmp) > 1) {
|
||||||
|
/* Principal is instance qualified, reparse with default realm. */
|
||||||
|
krb5_free_principal(context, tmp);
|
||||||
|
parse_name_realm(context, name, parseflags, NULL, principal);
|
||||||
|
} else {
|
||||||
|
*principal = tmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
get_default_principal(context, principal);
|
||||||
|
if (user_realm)
|
||||||
|
set_princ_realm(context, *principal, user_realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_realm)
|
||||||
|
free(user_realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_princ_kt(krb5_context context,
|
||||||
|
krb5_principal *principal,
|
||||||
|
char *name)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
krb5_principal tmp;
|
||||||
|
krb5_ccache ccache;
|
||||||
|
krb5_kt_cursor cursor;
|
||||||
|
krb5_keytab_entry entry;
|
||||||
|
int parseflags = 0;
|
||||||
|
char *def_realm;
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
/*
|
||||||
|
* If the credential cache exists and specifies a client principal,
|
||||||
|
* use that.
|
||||||
|
*/
|
||||||
|
if (krb5_cc_default(context, &ccache) == 0) {
|
||||||
|
ret = krb5_cc_get_principal(context, ccache, principal);
|
||||||
|
krb5_cc_close(context, ccache);
|
||||||
|
if (ret == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
/* If the principal specifies an explicit realm, just use that. */
|
||||||
|
parseflags |= KRB5_PRINCIPAL_PARSE_NO_DEF_REALM;
|
||||||
|
parse_name_realm(context, name, parseflags, NULL, &tmp);
|
||||||
|
if (krb5_principal_get_realm(context, tmp) != NULL) {
|
||||||
|
*principal = tmp;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Otherwise, search keytab for bare name of the default principal. */
|
||||||
|
get_default_principal(context, &tmp);
|
||||||
|
set_princ_realm(context, tmp, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
def_realm = get_default_realm(context);
|
||||||
|
|
||||||
|
ret = krb5_kt_start_seq_get(context, kt, &cursor);
|
||||||
|
if (ret)
|
||||||
|
krb5_err(context, 1, ret, "krb5_kt_start_seq_get");
|
||||||
|
|
||||||
|
while (ret == 0 &&
|
||||||
|
krb5_kt_next_entry(context, kt, &entry, &cursor) == 0) {
|
||||||
|
const char *realm;
|
||||||
|
|
||||||
|
if (!krb5_principal_compare_any_realm(context, tmp, entry.principal))
|
||||||
|
continue;
|
||||||
|
if (*principal &&
|
||||||
|
krb5_principal_compare(context, *principal, entry.principal))
|
||||||
|
continue;
|
||||||
|
/* The default realm takes precedence */
|
||||||
|
realm = krb5_principal_get_realm(context, entry.principal);
|
||||||
|
if (*principal && strcmp(def_realm, realm) == 0) {
|
||||||
|
krb5_free_principal(context, *principal);
|
||||||
|
ret = krb5_copy_principal(context, entry.principal, principal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!*principal)
|
||||||
|
ret = krb5_copy_principal(context, entry.principal, principal);
|
||||||
|
}
|
||||||
|
if (ret != 0 || (ret = krb5_kt_end_seq_get(context, kt, &cursor)) != 0)
|
||||||
|
krb5_err(context, 1, ret, "get_princ_kt");
|
||||||
|
if (!*principal)
|
||||||
|
parse_name_realm(context, name, parseflags, NULL, principal);
|
||||||
|
|
||||||
|
krb5_free_principal(context, tmp);
|
||||||
|
free(def_realm);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_context context;
|
krb5_context context;
|
||||||
krb5_ccache ccache;
|
krb5_ccache ccache;
|
||||||
krb5_principal principal;
|
krb5_principal principal = NULL;
|
||||||
int optidx = 0;
|
int optidx = 0;
|
||||||
krb5_deltat ticket_life = 0;
|
krb5_deltat ticket_life = 0;
|
||||||
int parseflags = 0;
|
|
||||||
|
|
||||||
setprogname(argv[0]);
|
setprogname(argv[0]);
|
||||||
|
|
||||||
@@ -810,8 +987,18 @@ main(int argc, char **argv)
|
|||||||
argc -= optidx;
|
argc -= optidx;
|
||||||
argv += optidx;
|
argv += optidx;
|
||||||
|
|
||||||
if (canonicalize_flag || enterprise_flag)
|
/*
|
||||||
parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
|
* Open the keytab now, we use the keytab to determine the principal's
|
||||||
|
* realm when the requested principal has no realm.
|
||||||
|
*/
|
||||||
|
if (use_keytab || keytab_str) {
|
||||||
|
if (keytab_str)
|
||||||
|
ret = krb5_kt_resolve(context, keytab_str, &kt);
|
||||||
|
else
|
||||||
|
ret = krb5_kt_default(context, &kt);
|
||||||
|
if (ret)
|
||||||
|
krb5_err(context, 1, ret, "resolving keytab");
|
||||||
|
}
|
||||||
|
|
||||||
if (pk_enterprise_flag) {
|
if (pk_enterprise_flag) {
|
||||||
ret = krb5_pk_enterprise_cert(context, pk_user_id,
|
ret = krb5_pk_enterprise_cert(context, pk_user_id,
|
||||||
@@ -831,17 +1018,10 @@ main(int argc, char **argv)
|
|||||||
krb5_err(context, 1, ret, "krb5_make_principal");
|
krb5_err(context, 1, ret, "krb5_make_principal");
|
||||||
krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN);
|
krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN);
|
||||||
|
|
||||||
|
} else if (use_keytab || keytab_str) {
|
||||||
|
get_princ_kt(context, &principal, argv[0]);
|
||||||
} else {
|
} else {
|
||||||
if (argv[0]) {
|
get_princ(context, &principal, argv[0]);
|
||||||
ret = krb5_parse_name_flags(context, argv[0], parseflags,
|
|
||||||
&principal);
|
|
||||||
if (ret)
|
|
||||||
krb5_err(context, 1, ret, "krb5_parse_name");
|
|
||||||
} else {
|
|
||||||
ret = krb5_get_default_principal(context, &principal);
|
|
||||||
if (ret)
|
|
||||||
krb5_err(context, 1, ret, "krb5_get_default_principal");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fcache_version)
|
if (fcache_version)
|
||||||
@@ -969,6 +1149,8 @@ main(int argc, char **argv)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
krb5_free_principal(context, principal);
|
krb5_free_principal(context, principal);
|
||||||
|
if (kt)
|
||||||
|
krb5_kt_close(context, kt);
|
||||||
krb5_free_context(context);
|
krb5_free_context(context);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user