From: Sam Hartman Date: Wed, 23 Dec 2009 21:10:55 +0000 (+0000) Subject: Change kinit -n logic to support an interface for both fully and X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=09b1601762ce24164a053074585d94c902318b7d;p=thirdparty%2Fkrb5.git Change kinit -n logic to support an interface for both fully and partially anonymous principals. * New API krb5_get_init_creds_opt_set_anonymous * In krb5_get_init_creds_init, map @REALM to WELLKNOWN/ANONYMOUS@REALM * Change logic for what canonicalization is acceptable to support realm-exposed anonymous principals too * Use the above in kinit git-svn-id: svn://anonsvn.mit.edu/krb5/branches/anonymous@23511 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c index 1ecf6d4aa6..79ac654188 100644 --- a/src/clients/kinit/kinit.c +++ b/src/clients/kinit/kinit.c @@ -467,71 +467,74 @@ k5_begin(opts, k5) if (opts->principal_name) { - if (opts->anonymous) { - code = krb5_build_principal_ext(k5->ctx, &k5->me, strlen(opts->principal_name), - opts->principal_name, - strlen(KRB5_WELLKNOWN_NAMESTR), KRB5_WELLKNOWN_NAMESTR, - strlen(KRB5_ANONYMOUS_PRINCSTR), - KRB5_ANONYMOUS_PRINCSTR, 0); - if (code) { - com_err(progname, code, "while setting up anonymous principal"); - return 0; - } - } else { - /* Use specified name */ - if ((code = krb5_parse_name_flags(k5->ctx, opts->principal_name, - flags, &k5->me))) { - com_err(progname, code, "when parsing name %s", - opts->principal_name); - return 0; - } + /* Use specified name */ + if ((code = krb5_parse_name_flags(k5->ctx, opts->principal_name, + flags, &k5->me))) { + com_err(progname, code, "when parsing name %s", + opts->principal_name); + return 0; } } else { /* No principal name specified */ if (opts->anonymous) { - fprintf(stderr, "%s: please specify realm for anonymous authentication\n", progname); - return 0; - } - if (opts->action == INIT_KT) { - /* Use the default host/service name */ - code = krb5_sname_to_principal(k5->ctx, NULL, NULL, - KRB5_NT_SRV_HST, &k5->me); + char *defrealm; + code = krb5_get_default_realm(k5->ctx, &defrealm); if (code) { - com_err(progname, code, - "when creating default server principal name"); + com_err(progname, code, "while getting default realm"); return 0; } - if (k5->me->realm.data[0] == 0) { - code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); - if (code == 0) - com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, - "(principal %s)", k5->name); - else - com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, - "for local services"); + code = krb5_build_principal_ext(k5->ctx, &k5->me, + strlen(defrealm), defrealm, + strlen(KRB5_WELLKNOWN_NAMESTR), KRB5_WELLKNOWN_NAMESTR, + strlen(KRB5_ANONYMOUS_PRINCSTR), KRB5_ANONYMOUS_PRINCSTR, + 0); + krb5_free_default_realm( k5->ctx, defrealm); + if (code) { + com_err(progname, code, "while building principal"); return 0; } } else { - /* Get default principal from cache if one exists */ - code = krb5_cc_get_principal(k5->ctx, k5->cc, - &k5->me); - if (code) - { - char *name = get_name_from_os(); - if (!name) - { - fprintf(stderr, "Unable to identify user\n"); + if (opts->action == INIT_KT) { + /* Use the default host/service name */ + code = krb5_sname_to_principal(k5->ctx, NULL, NULL, + KRB5_NT_SRV_HST, &k5->me); + if (code) { + com_err(progname, code, + "when creating default server principal name"); return 0; } - if ((code = krb5_parse_name_flags(k5->ctx, name, - flags, &k5->me))) - { - com_err(progname, code, "when parsing name %s", - name); + if (k5->me->realm.data[0] == 0) { + code = krb5_unparse_name(k5->ctx, k5->me, &k5->name); + if (code == 0) + com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, + "(principal %s)", k5->name); + else + com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN, + "for local services"); return 0; } + } else { + /* Get default principal from cache if one exists */ + code = krb5_cc_get_principal(k5->ctx, k5->cc, + &k5->me); + if (code) + { + char *name = get_name_from_os(); + if (!name) + { + fprintf(stderr, "Unable to identify user\n"); + return 0; + } + if ((code = krb5_parse_name_flags(k5->ctx, name, + flags, &k5->me))) + { + com_err(progname, code, "when parsing name %s", + name); + return 0; + } + } } } } @@ -615,6 +618,8 @@ k5_kinit(opts, k5) krb5_get_init_creds_opt_set_proxiable(options, 0); if (opts->canonicalize) krb5_get_init_creds_opt_set_canonicalize(options, 1); + if (opts->anonymous) + krb5_get_init_creds_opt_set_anonymous(options, 1); if (opts->addresses) { krb5_address **addresses = NULL; diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index ac89a3c729..fed941eb04 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -2204,6 +2204,7 @@ typedef struct _krb5_get_init_creds_opt { #define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080 #define KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT 0x0100 #define KRB5_GET_INIT_CREDS_OPT_CANONICALIZE 0x0200 +#define KRB5_GET_INIT_CREDS_OPT_ANONYMOUS 0x0400 krb5_error_code KRB5_CALLCONV @@ -2237,6 +2238,20 @@ void KRB5_CALLCONV krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opt, int canonicalize); +/** + * Request anonymous credentials from the KDC. If the client name looks like + * "@REALM" (an empty principal name), then fully anonymous credentials are + * requested. If the client name looks like "name@REALM," then credentials + * tied to a specific realm are requested. + * + * Credentials tied to a specific realm are not supported in this version. + * + * Note that anonymous credentials are only a request; clients must verify that + * credentials are anonymous if that is a requirement. + */ +krb5_get_init_creds_opt_set_anonymous(krb5_get_init_creds_opt *opt, + int anonymous); + void KRB5_CALLCONV krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 7043845920..64989ac61a 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -305,13 +305,12 @@ verify_as_reply(krb5_context context, */ canon_req = ((request->kdc_options & KDC_OPT_CANONICALIZE) != 0) || (krb5_princ_type(context, request->client) == KRB5_NT_ENTERPRISE_PRINCIPAL) - || (krb5_principal_compare_any_realm(context, request->client, - krb5_anonymous_principal())); + || (request->kdc_options & KDC_OPT_REQUEST_ANONYMOUS); if (canon_req) { canon_ok = IS_TGS_PRINC(context, request->server) && IS_TGS_PRINC(context, as_reply->enc_part2->server); if ((!canon_ok ) && (request->kdc_options &KDC_OPT_REQUEST_ANONYMOUS)) - canon_ok = krb5_principal_compare(context, as_reply->client, + canon_ok = krb5_principal_compare_any_realm(context, as_reply->client, krb5_anonymous_principal()); } else canon_ok = 0; @@ -1535,6 +1534,26 @@ krb5_init_creds_init(krb5_context context, } /*Anonymous*/ + if(opte->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) { + ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS; + /*Remap @REALM to WELLKNOWN/ANONYMOUS@REALM*/ + if (client->length == 1 && client->data[0].length ==0) { + krb5_principal new_client; + code = krb5_build_principal_ext(context, &new_client, client->realm.length, + client->realm.data, + strlen(KRB5_WELLKNOWN_NAMESTR), + KRB5_WELLKNOWN_NAMESTR, + strlen(KRB5_ANONYMOUS_PRINCSTR), + KRB5_ANONYMOUS_PRINCSTR, + 0); + if (code) + goto cleanup; + krb5_free_principal(context, ctx->request->client); + ctx->request->client = new_client; + krb5_princ_type(context, ctx->request->client) = KRB5_NT_WELLKNOWN; + } + } + /*We will also handle anonymous if the input principal is the anonymous principal*/ if (krb5_principal_compare_any_realm(context, ctx->request->client, krb5_anonymous_principal())) { ctx->request->kdc_options |= KDC_OPT_REQUEST_ANONYMOUS; diff --git a/src/lib/krb5/krb/gic_opt.c b/src/lib/krb5/krb/gic_opt.c index b04252bb40..6a7809f103 100644 --- a/src/lib/krb5/krb/gic_opt.c +++ b/src/lib/krb5/krb/gic_opt.c @@ -52,6 +52,15 @@ krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opt, int canon opt->flags &= ~(KRB5_GET_INIT_CREDS_OPT_CANONICALIZE); } +void KRB5_CALLCONV +krb5_get_init_creds_opt_set_anonymous (krb5_get_init_creds_opt *opt, + int anonymous) +{ + if (anonymous) + opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS; + else opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ANONYMOUS; +} + void KRB5_CALLCONV krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, int etype_list_length) { diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index 19303a6d10..523afcb709 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -339,6 +339,7 @@ krb5_get_init_creds_opt_get_fast_flags krb5_get_init_creds_opt_get_pa krb5_get_init_creds_opt_init krb5_get_init_creds_opt_set_address_list +krb5_get_init_creds_opt_set_anonymous krb5_get_init_creds_opt_set_canonicalize krb5_get_init_creds_opt_set_change_password_prompt krb5_get_init_creds_opt_set_etype_list