kuser: support authenticated anonymous AS-REQs in kinit

Allow kinit to request anonymous tickets with authenticated clients, not just
anonymous PKINIT.
This commit is contained in:
Luke Howard
2019-05-03 14:45:58 +10:00
committed by Jeffrey Altman
parent 63557427e0
commit 3051db0d5d
3 changed files with 58 additions and 16 deletions

View File

@@ -82,7 +82,7 @@
.Op Fl Fl password-file= Ns Ar filename .Op Fl Fl password-file= Ns Ar filename
.Op Fl Fl fcache-version= Ns Ar version-number .Op Fl Fl fcache-version= Ns Ar version-number
.Op Fl A | Fl Fl no-addresses .Op Fl A | Fl Fl no-addresses
.Op Fl Fl anonymous .Op Fl n | Fl Fl anonymous
.Op Fl Fl enterprise .Op Fl Fl enterprise
.Op Fl Fl version .Op Fl Fl version
.Op Fl Fl help .Op Fl Fl help
@@ -165,10 +165,12 @@ in
.Xr krb5.conf 5 . .Xr krb5.conf 5 .
.It Fl A , Fl Fl no-addresses .It Fl A , Fl Fl no-addresses
Request a ticket with no addresses. Request a ticket with no addresses.
.It Fl Fl anonymous .It Fl n , Fl Fl anonymous
Request an anonymous ticket (which means that the ticket will be Request an anonymous ticket. If the principal is specified as @REALM, then
issued to an anonymous principal, typically anonymous PKINIT will be used to acquire an unauthenticated anonymous ticket
.Dq anonymous@REALM ) . and both the client name and realm in the returned ticket will be anonymized.
Otherwise, authentication proceeds as normal and the anonymous ticket will have
only the client name anonymized.
.It Fl Fl enterprise .It Fl Fl enterprise
Parse principal as a enterprise (KRB5-NT-ENTERPRISE) name. Enterprise Parse principal as a enterprise (KRB5-NT-ENTERPRISE) name. Enterprise
names are email like principals that are stored in the name part of names are email like principals that are stored in the name part of

View File

@@ -155,7 +155,7 @@ static struct getargs args[] = {
{ "extra-addresses",'a', arg_strings, &extra_addresses, { "extra-addresses",'a', arg_strings, &extra_addresses,
NP_("include these extra addresses", ""), "addresses" }, NP_("include these extra addresses", ""), "addresses" },
{ "anonymous", 0, arg_flag, &anonymous_flag, { "anonymous", 'n', arg_flag, &anonymous_flag,
NP_("request an anonymous ticket", ""), NULL }, NP_("request an anonymous ticket", ""), NULL },
{ "request-pac", 0, arg_flag, &pac_flag, { "request-pac", 0, arg_flag, &pac_flag,
@@ -425,12 +425,25 @@ store_ntlmkey(krb5_context context, krb5_ccache id,
} }
#endif #endif
static krb5_boolean
is_anonymous_princ_p(krb5_const_principal principal)
{
if ((principal->name.name_type != KRB5_NT_WELLKNOWN &&
principal->name.name_type != KRB5_NT_UNKNOWN) ||
principal->name.name_string.len != 2 ||
strcmp(principal->name.name_string.val[0], KRB5_WELLKNOWN_NAME) != 0 ||
strcmp(principal->name.name_string.val[1], KRB5_ANON_NAME) != 0)
return 0;
return 1;
}
static krb5_error_code static krb5_error_code
get_new_tickets(krb5_context context, get_new_tickets(krb5_context context,
krb5_principal principal, krb5_principal principal,
krb5_ccache ccache, krb5_ccache ccache,
krb5_deltat ticket_life, krb5_deltat ticket_life,
int interactive) int interactive,
int anonymous_pkinit)
{ {
krb5_error_code ret; krb5_error_code ret;
krb5_creds cred; krb5_creds cred;
@@ -529,7 +542,7 @@ get_new_tickets(krb5_context context,
krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE); krb5_get_init_creds_opt_set_canonicalize(context, opt, TRUE);
if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag) if (pk_enterprise_flag || enterprise_flag || canonicalize_flag || windows_flag)
krb5_get_init_creds_opt_set_win2k(context, opt, TRUE); krb5_get_init_creds_opt_set_win2k(context, opt, TRUE);
if (pk_user_id || ent_user_id || anonymous_flag) { if (pk_user_id || ent_user_id || anonymous_pkinit) {
ret = krb5_get_init_creds_opt_set_pkinit(context, opt, ret = krb5_get_init_creds_opt_set_pkinit(context, opt,
principal, principal,
pk_user_id, pk_user_id,
@@ -537,7 +550,7 @@ get_new_tickets(krb5_context context,
NULL, NULL,
NULL, NULL,
pk_use_enckey ? 2 : 0 | pk_use_enckey ? 2 : 0 |
anonymous_flag ? 4 : 0, anonymous_pkinit ? 4 : 0,
prompter, prompter,
NULL, NULL,
passwd); passwd);
@@ -629,7 +642,7 @@ get_new_tickets(krb5_context context,
krb5_warn(context, ret, "krb5_init_creds_set_keytab"); krb5_warn(context, ret, "krb5_init_creds_set_keytab");
goto out; goto out;
} }
} else if (pk_user_id || ent_user_id || anonymous_flag) { } else if (pk_user_id || ent_user_id || is_anonymous_princ_p(principal)) {
} else if (!interactive && passwd[0] == '\0') { } else if (!interactive && passwd[0] == '\0') {
static int already_warned = 0; static int already_warned = 0;
@@ -924,7 +937,7 @@ renew_func(void *ptr)
server_str, ctx->ticket_life); server_str, ctx->ticket_life);
} else { } else {
ret = get_new_tickets(ctx->context, ctx->principal, ctx->ccache, ret = get_new_tickets(ctx->context, ctx->principal, ctx->ccache,
ctx->ticket_life, 0); ctx->ticket_life, 0, 0);
} }
expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal, expire = ticket_lifetime(ctx->context, ctx->ccache, ctx->principal,
server_str, &renew_expire); server_str, &renew_expire);
@@ -1224,6 +1237,7 @@ main(int argc, char **argv)
struct sigaction sa; struct sigaction sa;
#endif #endif
krb5_boolean unique_ccache = FALSE; krb5_boolean unique_ccache = FALSE;
int anonymous_pkinit = FALSE;
setprogname(argv[0]); setprogname(argv[0]);
@@ -1273,15 +1287,16 @@ main(int argc, char **argv)
pk_user_id = NULL; pk_user_id = NULL;
} else if (anonymous_flag) { } else if (anonymous_flag && argc && argv[0][0] == '@') {
/* If principal argument as @REALM, try anonymous PKINIT */
ret = krb5_make_principal(context, &principal, argv[0], ret = krb5_make_principal(context, &principal, &argv[0][1],
KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME,
NULL); NULL);
if (ret) if (ret)
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);
anonymous_pkinit = TRUE;
} else if (use_keytab || keytab_str) { } else if (use_keytab || keytab_str) {
get_princ_kt(context, &principal, argv[0]); get_princ_kt(context, &principal, argv[0]);
} else { } else {
@@ -1388,7 +1403,8 @@ main(int argc, char **argv)
exit(ret != 0); exit(ret != 0);
} }
ret = get_new_tickets(context, principal, ccache, ticket_life, 1); ret = get_new_tickets(context, principal, ccache, ticket_life,
1, anonymous_pkinit);
if (ret) { if (ret) {
if (unique_ccache) if (unique_ccache)
krb5_cc_destroy(context, ccache); krb5_cc_destroy(context, ccache);

View File

@@ -487,6 +487,30 @@ for a in $enctypes; do
done done
${kdestroy} ${kdestroy}
echo "Getting client authenticated anonymous initial tickets"; > messages.log
${kinit} -n --password-file=${objdir}/foopassword foo@$R || \
{ ec=1 ; eval "${testfailed}"; }
for a in $enctypes; do
echo "Getting tickets ($a)"; > messages.log
${kgetcred} -e $a ${server}@${R} || { ec=1 ; eval "${testfailed}"; }
${test_ap_req} ${server}@${R} ${keytab} ${cache} || \
{ ec=1 ; eval "${testfailed}"; }
${kdestroy} --credential=${server}@${R}
done
${kdestroy}
echo "Getting client anonymous service tickets"; > messages.log
${kinit} --password-file=${objdir}/foopassword foo@$R || \
{ ec=1 ; eval "${testfailed}"; }
for a in $enctypes; do
echo "Getting tickets ($a)"; > messages.log
${kgetcred} -n -e $a ${server}@${R} || { ec=1 ; eval "${testfailed}"; }
${test_ap_req} ${server}@${R} ${keytab} ${cache} || \
{ ec=1 ; eval "${testfailed}"; }
${kdestroy} --credential=${server}@${R}
done
${kdestroy}
echo "Getting client initial tickets for cross realm case"; > messages.log echo "Getting client initial tickets for cross realm case"; > messages.log
${kinit} --password-file=${objdir}/foopassword foo@$R || { ec=1 ; eval "${testfailed}"; } ${kinit} --password-file=${objdir}/foopassword foo@$R || { ec=1 ; eval "${testfailed}"; }
for a in $enctypes; do for a in $enctypes; do
@@ -713,7 +737,7 @@ fi
if test "$pkinit" = yes -a "$rsa" = yes ; then if test "$pkinit" = yes -a "$rsa" = yes ; then
echo "try anonymous pkinit"; > messages.log echo "try anonymous pkinit"; > messages.log
${kinit} --anonymous ${R} || \ ${kinit} -n @${R} || \
{ ec=1 ; eval "${testfailed}"; } { ec=1 ; eval "${testfailed}"; }
${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; }
${kdestroy} ${kdestroy}