current implementation has little protection against denial-of-service
attacks), the standard port number assigned for Kerberos TCP traffic
is port 88.
--@end table
+
+@itemx restrict_anonymous_to_kdc
+This flag determines the default value of restrict_anonymous_to_kdc for
+realms. The default value is @code{false}.
+@end table
@node realms (kdc.conf), pkinit kdc options, kdcdefaults, kdc.conf
@subsection [realms]
This option defaults to @code{true}.
+@itemx restrict_anonymous_to_tgt
+A boolean value (@code{true}, @code{false}). If set to @code{true}, the
+KDC will reject ticket requests from anonymous principals to service
+principals other than the realm's ticket-granting service. This option
+allows anonymous PKINIT to be enabled for use as FAST armor tickets
+without allowing anonymous authentication to services. By default, the
+value of restrict_anonymous_to_tgt as specified in the [kdcdefaults]
+section is used.
+
@end table
@node pkinit kdc options, Sample kdc.conf File, realms (kdc.conf), kdc.conf
krb5_flags realm_flags;
krb5_key_salt_tuple *realm_keysalts;
unsigned int realm_reject_bad_transit:1;
+ unsigned int realm_restrict_anon:1;
unsigned int realm_kadmind_port_valid:1;
unsigned int realm_enctype_valid:1;
unsigned int realm_max_life_valid:1;
unsigned int realm_expiration_valid:1;
unsigned int realm_flags_valid:1;
unsigned int realm_reject_bad_transit_valid:1;
+ unsigned int realm_restrict_anon_valid:1;
krb5_int32 realm_num_keysalts;
} krb5_realm_params;
#endif /* KRB5_ADM_H__ */
#define KRB5_CONF_REALM_TRY_DOMAINS "realm_try_domains"
#define KRB5_CONF_REJECT_BAD_TRANSIT "reject_bad_transit"
#define KRB5_CONF_RENEW_LIFETIME "renew_lifetime"
+#define KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT "restrict_anonymous_to_tgt"
#define KRB5_CONF_SAFE_CHECKSUM_TYPE "safe_checksum_type"
#define KRB5_CONF_SUPPORTED_ENCTYPES "supported_enctypes"
#define KRB5_CONF_TICKET_LIFETIME "ticket_lifetime"
krb5_deltat realm_maxlife; /* Maximum ticket life for realm */
krb5_deltat realm_maxrlife; /* Maximum renewable life for realm */
krb5_boolean realm_reject_bad_transit; /* Accept unverifiable transited_realm ? */
+ krb5_boolean realm_restrict_anon; /* Anon to local TGT only */
} kdc_realm_t;
extern kdc_realm_t **kdc_realmlist;
#define master_princ kdc_active_realm->realm_mprinc
#define tgs_server kdc_active_realm->realm_tgsprinc
#define reject_bad_transit kdc_active_realm->realm_reject_bad_transit
+#define restrict_anon kdc_active_realm->realm_restrict_anon
/* various externs for KDC */
extern krb5_data empty_string; /* an empty string */
return (protcode >= 0 && protcode <= 128) ? protcode : KRB_ERR_GENERIC;
}
+/* Return -1 if the AS or TGS request is disallowed due to KDC policy on
+ * anonymous tickets. */
+static int
+check_anon(krb5_context context, krb5_principal client, krb5_principal server)
+{
+ /* If restrict_anon is set, reject requests from anonymous to principals
+ * other than the local TGT. */
+ if (restrict_anon &&
+ krb5_principal_compare_any_realm(context, client,
+ krb5_anonymous_principal()) &&
+ !krb5_principal_compare(context, server, tgs_server))
+ return -1;
+ return 0;
+}
+
/*
* Routines that validate a AS request; checks a lot of things. :-)
*
return(KDC_ERR_MUST_USE_USER2USER);
}
+ if (check_anon(kdc_context, request->client, request->server) != 0) {
+ *status = "ANONYMOUS NOT ALLOWED";
+ return(KDC_ERR_POLICY);
+ }
+
/* Perform KDB module policy checks. */
ret = krb5_db_check_policy_as(kdc_context, request, &client, &server,
kdc_time, status, e_data);
return KRB_ERR_GENERIC;
}
+ if (check_anon(kdc_context, ticket->enc_part2->client,
+ request->server) != 0) {
+ *status = "ANONYMOUS NOT ALLOWED";
+ return(KDC_ERR_POLICY);
+ }
+
/* Perform KDB module policy checks. */
ret = krb5_db_check_policy_tgs(kdc_context, request, &server,
ticket, status, e_data);
static krb5_error_code
init_realm(kdc_realm_t *rdp, char *realm, char *def_mpname,
krb5_enctype def_enctype, char *def_udp_ports, char *def_tcp_ports,
- krb5_boolean def_manual, char **db_args, char *no_refrls,
- char *host_based_srvcs)
+ krb5_boolean def_manual, krb5_boolean def_restrict_anon,
+ char **db_args, char *no_refrls, char *host_based_srvcs)
{
krb5_error_code kret;
krb5_boolean manual;
} else
manual = def_manual;
+ if (rparams && rparams->realm_restrict_anon_valid)
+ rdp->realm_restrict_anon = rparams->realm_restrict_anon;
+ else
+ rdp->realm_restrict_anon = def_restrict_anon;
+
/* Handle master key type */
if (rparams && rparams->realm_enctype_valid)
rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype;
krb5_enctype menctype = ENCTYPE_UNKNOWN;
kdc_realm_t *rdatap = NULL;
krb5_boolean manual = FALSE;
+ krb5_boolean def_restrict_anon;
char *default_udp_ports = 0;
char *default_tcp_ports = 0;
krb5_pointer aprof;
hierarchy[1] = KRB5_CONF_MAX_DGRAM_REPLY_SIZE;
if (krb5_aprof_get_int32(aprof, hierarchy, TRUE, &max_dgram_reply_size))
max_dgram_reply_size = MAX_DGRAM_SIZE;
+ hierarchy[1] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT;
+ if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE, &def_restrict_anon))
+ def_restrict_anon = FALSE;
hierarchy[1] = KRB5_CONF_NO_HOST_REFERRAL;
if (krb5_aprof_get_string_all(aprof, hierarchy, &no_refrls))
no_refrls = 0;
if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
if ((retval = init_realm(rdatap, optarg, mkey_name,
menctype, default_udp_ports,
- default_tcp_ports, manual, db_args,
+ default_tcp_ports, manual,
+ def_restrict_anon, db_args,
no_refrls, host_based_srvcs))) {
fprintf(stderr,
"%s: cannot initialize realm %s - see log file for details\n",
if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
if ((retval = init_realm(rdatap, lrealm, mkey_name, menctype,
default_udp_ports, default_tcp_ports,
- manual, db_args, no_refrls,
- host_based_srvcs))) {
+ manual, def_restrict_anon, db_args,
+ no_refrls, host_based_srvcs))) {
fprintf(stderr,"%s: cannot initialize realm %s - see log file for details\n",
argv[0], lrealm);
exit(1);
krb5_flags realm_flags;
krb5_key_salt_tuple *realm_keysalts;
unsigned int realm_reject_bad_transit:1;
+ unsigned int realm_restrict_anon:1;
unsigned int realm_kadmind_port_valid:1;
unsigned int realm_enctype_valid:1;
unsigned int realm_max_life_valid:1;
unsigned int realm_expiration_valid:1;
unsigned int realm_flags_valid:1;
unsigned int realm_reject_bad_transit_valid:1;
+ unsigned int realm_restrict_anon_valid:1;
krb5_int32 realm_num_keysalts;
} krb5_realm_params;
rparams->realm_reject_bad_transit_valid = 1;
}
+ hierarchy[2] = KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT;
+ if (!krb5_aprof_get_boolean(aprofile, hierarchy, TRUE, &bvalue)) {
+ rparams->realm_restrict_anon = bvalue;
+ rparams->realm_restrict_anon_valid = 1;
+ }
+
hierarchy[2] = KRB5_CONF_NO_HOST_REFERRAL;
if (!krb5_aprof_get_string_all(aprofile, hierarchy, &no_refrls))
rparams->realm_no_host_referral = no_refrls;
}
}
-realm = K5Realm(krb5_conf=pkinit_krb5_conf, create_user=False,
- create_host=False)
+restrictive_kdc_conf = {
+ 'all': { 'realms' : { '$realm' : {
+ 'restrict_anonymous_to_tgt' : 'true' } } } }
+
+# In the basic test, anonymous is not restricted, so kvno should succeed.
+realm = K5Realm(krb5_conf=pkinit_krb5_conf, create_user=False)
realm.addprinc('WELLKNOWN/ANONYMOUS')
realm.kinit('@%s' % realm.realm, flags=['-n'])
realm.klist('WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS')
+realm.run_as_client([kvno, realm.host_princ])
+realm.stop()
+
+# Now try again with anonymous restricted; kvno should fail.
+realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=restrictive_kdc_conf,
+ create_user=False)
+realm.addprinc('WELLKNOWN/ANONYMOUS')
+realm.kinit('@%s' % realm.realm, flags=['-n'])
+realm.run_as_client([kvno, realm.host_princ], expected_code=1)
success('Anonymous PKINIT.')
- ktutil
- kinit
- klist
+ - kvno
- kdestroy
- kpasswd
- t_inetd
ktutil = os.path.join(buildtop, 'kadmin', 'ktutil', 'ktutil')
kinit = os.path.join(buildtop, 'clients', 'kinit', 'kinit')
klist = os.path.join(buildtop, 'clients', 'klist', 'klist')
+kvno = os.path.join(buildtop, 'clients', 'kvno', 'kvno')
kdestroy = os.path.join(buildtop, 'clients', 'kdestroy', 'kdestroy')
kpasswd = os.path.join(buildtop, 'clients', 'kpasswd', 'kpasswd')
t_inetd = os.path.join(buildtop, 'tests', 'dejagnu', 't_inetd')