doc/website/static/security/patches/SA-04:08/heimdal51.patch
Sergio Carlavilla Delgado 989d921f5d Migrate doc to Hugo/AsciiDoctor
I'm very pleased to announce the release of
our new website and documentation using
the new toolchain with Hugo and AsciiDoctor.

To get more information about the new toolchain
please read the FreeBSD Documentation Project Primer[1],
Hugo docs[2] and AsciiDoctor docs[3].

Acknowledgment:
Benedict Reuschling <bcr@>
Glen Barber <gjb@>
Hiroki Sato <hrs@>
Li-Wen Hsu <lwhsu@>
Sean Chittenden <seanc@>
The FreeBSD Foundation

[1] https://docs.FreeBSD.org/en/books/fdp-primer/
[2] https://gohugo.io/documentation/
[3] https://docs.asciidoctor.org/home/

Approved by:    doceng, core
2021-01-26 00:31:29 +01:00

706 lines
20 KiB
Diff

diff -urN crypto/heimdal/kdc/config.c heimdal-0.5.3/kdc/config.c
--- crypto/heimdal/kdc/config.c 2003-03-17 07:46:55.000000000 +0100
+++ crypto/heimdal/kdc/config.c 2004-02-16 20:08:49.000000000 +0100
@@ -64,6 +64,8 @@
krb5_boolean check_ticket_addresses;
krb5_boolean allow_null_ticket_addresses;
krb5_boolean allow_anonymous;
+int trpolicy;
+static const char *trpolicy_str;
static struct getarg_strings addresses_str; /* addresses to listen on */
krb5_addresses explicit_addresses;
@@ -292,9 +294,8 @@
get_dbinfo();
- if(max_request_str){
+ if(max_request_str)
max_request = parse_bytes(max_request_str, NULL);
- }
if(max_request == 0){
p = krb5_config_get_string (context,
@@ -365,6 +366,23 @@
allow_anonymous =
krb5_config_get_bool(context, NULL, "kdc",
"allow-anonymous", NULL);
+ trpolicy_str =
+ krb5_config_get_string_default(context, NULL, "always-check", "kdc",
+ "transited-policy", NULL);
+ if(strcasecmp(trpolicy_str, "always-check") == 0)
+ trpolicy = TRPOLICY_ALWAYS_CHECK;
+ else if(strcasecmp(trpolicy_str, "allow-per-principal") == 0)
+ trpolicy = TRPOLICY_ALLOW_PER_PRINCIPAL;
+ else if(strcasecmp(trpolicy_str, "always-honour-request") == 0)
+ trpolicy = TRPOLICY_ALWAYS_HONOUR_REQUEST;
+ else {
+ kdc_log(0, "unknown transited-policy: %s, reverting to always-check",
+ trpolicy_str);
+ trpolicy = TRPOLICY_ALWAYS_CHECK;
+ }
+
+ krb5_config_get_bool_default(context, NULL, TRUE, "kdc",
+ "enforce-transited-policy", NULL);
#ifdef KRB4
if(v4_realm == NULL){
p = krb5_config_get_string (context, NULL,
diff -urN crypto/heimdal/kdc/kdc.8 heimdal-0.5.3/kdc/kdc.8
--- crypto/heimdal/kdc/kdc.8 2003-03-17 07:47:03.000000000 +0100
+++ crypto/heimdal/kdc/kdc.8 2004-02-16 18:50:11.000000000 +0100
@@ -2,5 +2,5 @@
.\"
-.Dd August 22, 2002
+.Dd October 22, 2003
.Dt KDC 8
.Os HEIMDAL
.Sh NAME
@@ -145,6 +145,27 @@
check-ticket-addresses is TRUE.
.It Li allow-anonymous = Va boolean
Permit anonymous tickets with no addresses.
+.It Li transited-policy = Xo
+.Li always-check \*(Ba
+.Li allow-per-principal |
+.Li always-honour-request
+.Xc
+This controls how KDC requests with the
+.Li disable-transited-check
+flag are handled. It can be one of:
+.Bl -tag -width "xxx" -offset indent
+.It Li always-check
+Always check transited encoding, this is the default.
+.It Li allow-per-principal
+Currently this is identical to
+.Li always-check .
+In a future release, it will be possible to mark a principal as able
+to handle unchecked requests.
+.It Li always-honour-request
+Always do what the client asked.
+In a future release, it will be possible to force a check per
+principal.
+.El
.It encode_as_rep_as_tgs_rep = Va boolean
Encode AS-Rep as TGS-Rep to be bug-compatible with old DCE code. The
Heimdal clients allow both.
diff -urN crypto/heimdal/kdc/kdc_locl.h heimdal-0.5.3/kdc/kdc_locl.h
--- crypto/heimdal/kdc/kdc_locl.h 2003-03-17 07:47:23.000000000 +0100
+++ crypto/heimdal/kdc/kdc_locl.h 2004-02-16 19:24:43.000000000 +0100
@@ -62,6 +62,11 @@
extern krb5_boolean check_ticket_addresses;
extern krb5_boolean allow_null_ticket_addresses;
extern krb5_boolean allow_anonymous;
+enum { TRPOLICY_ALWAYS_CHECK,
+ TRPOLICY_ALLOW_PER_PRINCIPAL,
+ TRPOLICY_ALWAYS_HONOUR_REQUEST };
+extern int trpolicy;
+extern int enable_v4_cross_realm;
#ifdef KRB4
extern char *v4_realm;
diff -urN crypto/heimdal/kdc/kerberos5.c heimdal-0.5.3/kdc/kerberos5.c
--- crypto/heimdal/kdc/kerberos5.c 2002-09-09 16:03:02.000000000 +0200
+++ crypto/heimdal/kdc/kerberos5.c 2004-02-16 19:23:20.000000000 +0100
@@ -355,10 +355,13 @@
if(n != pa.len) {
char *name;
- krb5_unparse_name(context, client->principal, &name);
+ ret = krb5_unparse_name(context, client->principal, &name);
+ if (ret)
+ name = "<unparse_name failed>";
kdc_log(0, "internal error in get_pa_etype_info(%s): %d != %d",
name, n, pa.len);
- free(name);
+ if (ret == 0)
+ free(name);
pa.len = n;
}
@@ -496,8 +499,8 @@
krb5_enctype cetype, setype;
EncTicketPart et;
EncKDCRepPart ek;
- krb5_principal client_princ, server_princ;
- char *client_name, *server_name;
+ krb5_principal client_princ = NULL, server_princ = NULL;
+ char *client_name = NULL, *server_name = NULL;
krb5_error_code ret = 0;
const char *e_text = NULL;
krb5_crypto crypto;
@@ -506,28 +509,32 @@
memset(&rep, 0, sizeof(rep));
if(b->sname == NULL){
- server_name = "<unknown server>";
ret = KRB5KRB_ERR_GENERIC;
e_text = "No server in request";
} else{
principalname2krb5_principal (&server_princ, *(b->sname), b->realm);
- krb5_unparse_name(context, server_princ, &server_name);
+ ret = krb5_unparse_name(context, server_princ, &server_name);
+ }
+ if (ret) {
+ kdc_log(0, "AS-REQ malformed server name from %s", from);
+ goto out;
}
if(b->cname == NULL){
- client_name = "<unknown client>";
ret = KRB5KRB_ERR_GENERIC;
e_text = "No client in request";
} else {
principalname2krb5_principal (&client_princ, *(b->cname), b->realm);
- krb5_unparse_name(context, client_princ, &client_name);
+ ret = krb5_unparse_name(context, client_princ, &client_name);
}
+ if (ret) {
+ kdc_log(0, "AS-REQ malformed client name from %s", from);
+ goto out;
+ }
+
kdc_log(0, "AS-REQ %s from %s for %s",
client_name, from, server_name);
- if(ret)
- goto out;
-
ret = db_fetch(client_princ, &client);
if(ret){
kdc_log(0, "UNKNOWN -- %s: %s", client_name,
@@ -559,7 +566,6 @@
while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
krb5_data ts_data;
PA_ENC_TS_ENC p;
- time_t patime;
size_t len;
EncryptedData enc_data;
Key *pa_key;
@@ -635,7 +641,6 @@
client_name);
continue;
}
- patime = p.patimestamp;
free_PA_ENC_TS_ENC(&p);
if (abs(kdc_time - p.patimestamp) > context->max_skew) {
ret = KRB5KDC_ERR_PREAUTH_FAILED;
@@ -716,9 +721,10 @@
if (ret == 0) {
kdc_log(5, "Using %s/%s", cet, set);
free(set);
- } else
- free(cet);
- } else
+ }
+ free(cet);
+ }
+ if (ret != 0)
kdc_log(5, "Using e-types %d/%d", cetype, setype);
}
@@ -841,13 +847,8 @@
copy_HostAddresses(b->addresses, et.caddr);
}
- {
- krb5_data empty_string;
-
- krb5_data_zero(&empty_string);
- et.transited.tr_type = DOMAIN_X500_COMPRESS;
- et.transited.contents = empty_string;
- }
+ et.transited.tr_type = DOMAIN_X500_COMPRESS;
+ krb5_data_zero(&et.transited.contents);
copy_EncryptionKey(&et.key, &ek.key);
@@ -914,8 +915,8 @@
client->kvno, &ckey->key, &e_text, reply);
free_EncTicketPart(&et);
free_EncKDCRepPart(&ek);
- free_AS_REP(&rep);
out:
+ free_AS_REP(&rep);
if(ret){
krb5_mk_error(context,
ret,
@@ -929,9 +930,11 @@
ret = 0;
}
out2:
- krb5_free_principal(context, client_princ);
+ if (client_princ)
+ krb5_free_principal(context, client_princ);
free(client_name);
- krb5_free_principal(context, server_princ);
+ if (server_princ)
+ krb5_free_principal(context, server_princ);
free(server_name);
if(client)
free_ent(client);
@@ -1054,33 +1057,35 @@
}
static krb5_error_code
-fix_transited_encoding(TransitedEncoding *tr,
+fix_transited_encoding(krb5_boolean check_policy,
+ TransitedEncoding *tr,
+ EncTicketPart *et,
const char *client_realm,
const char *server_realm,
const char *tgt_realm)
{
krb5_error_code ret = 0;
- if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)){
- char **realms = NULL, **tmp;
- int num_realms = 0;
- int i;
- if(tr->tr_type && tr->contents.length != 0) {
- if(tr->tr_type != DOMAIN_X500_COMPRESS){
- kdc_log(0, "Unknown transited type: %u",
- tr->tr_type);
- return KRB5KDC_ERR_TRTYPE_NOSUPP;
- }
- ret = krb5_domain_x500_decode(context,
- tr->contents,
- &realms,
- &num_realms,
- client_realm,
- server_realm);
- if(ret){
- krb5_warn(context, ret, "Decoding transited encoding");
- return ret;
- }
- }
+ char **realms, **tmp;
+ int num_realms;
+ int i;
+
+ if(tr->tr_type != DOMAIN_X500_COMPRESS) {
+ kdc_log(0, "Unknown transited type: %u", tr->tr_type);
+ return KRB5KDC_ERR_TRTYPE_NOSUPP;
+ }
+
+ ret = krb5_domain_x500_decode(context,
+ tr->contents,
+ &realms,
+ &num_realms,
+ client_realm,
+ server_realm);
+ if(ret){
+ krb5_warn(context, ret, "Decoding transited encoding");
+ return ret;
+ }
+ if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
+ /* not us, so add the previous realm to transited set */
if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
ret = ERANGE;
goto free_realms;
@@ -1097,16 +1102,46 @@
goto free_realms;
}
num_realms++;
- free_TransitedEncoding(tr);
- tr->tr_type = DOMAIN_X500_COMPRESS;
- ret = krb5_domain_x500_encode(realms, num_realms, &tr->contents);
- if(ret)
- krb5_warn(context, ret, "Encoding transited encoding");
- free_realms:
+ }
+ if(num_realms == 0) {
+ if(strcmp(client_realm, server_realm))
+ kdc_log(0, "cross-realm %s -> %s", client_realm, server_realm);
+ } else {
+ size_t l = 0;
+ char *rs;
for(i = 0; i < num_realms; i++)
- free(realms[i]);
- free(realms);
+ l += strlen(realms[i]) + 2;
+ rs = malloc(l);
+ if(rs != NULL) {
+ *rs = '\0';
+ for(i = 0; i < num_realms; i++) {
+ if(i > 0)
+ strlcat(rs, ", ", l);
+ strlcat(rs, realms[i], l);
+ }
+ kdc_log(0, "cross-realm %s -> %s via [%s]", client_realm, server_realm, rs);
+ free(rs);
+ }
}
+ if(check_policy) {
+ ret = krb5_check_transited(context, client_realm,
+ server_realm,
+ realms, num_realms, NULL);
+ if(ret) {
+ krb5_warn(context, ret, "cross-realm %s -> %s",
+ client_realm, server_realm);
+ goto free_realms;
+ }
+ et->flags.transited_policy_checked = 1;
+ }
+ et->transited.tr_type = DOMAIN_X500_COMPRESS;
+ ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
+ if(ret)
+ krb5_warn(context, ret, "Encoding transited encoding");
+ free_realms:
+ for(i = 0; i < num_realms; i++)
+ free(realms[i]);
+ free(realms);
return ret;
}
@@ -1172,18 +1207,35 @@
ret = check_tgs_flags(b, tgt, &et);
if(ret)
- return ret;
+ goto out;
- copy_TransitedEncoding(&tgt->transited, &et.transited);
- ret = fix_transited_encoding(&et.transited,
+ /* We should check the transited encoding if:
+ 1) the request doesn't ask not to be checked
+ 2) globally enforcing a check
+ 3) principal requires checking
+ 4) we allow non-check per-principal, but principal isn't marked as allowing this
+ 5) we don't globally allow this
+ */
+
+#define GLOBAL_FORCE_TRANSITED_CHECK (trpolicy == TRPOLICY_ALWAYS_CHECK)
+#define GLOBAL_ALLOW_PER_PRINCIPAL (trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
+#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK (trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
+/* these will consult the database in future release */
+#define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
+#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
+
+ ret = fix_transited_encoding(!f.disable_transited_check ||
+ GLOBAL_FORCE_TRANSITED_CHECK ||
+ PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
+ !((GLOBAL_ALLOW_PER_PRINCIPAL &&
+ PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
+ GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
+ &tgt->transited, &et,
*krb5_princ_realm(context, client_principal),
*krb5_princ_realm(context, server->principal),
*krb5_princ_realm(context, krbtgt->principal));
- if(ret){
- free_TransitedEncoding(&et.transited);
- return ret;
- }
-
+ if(ret)
+ goto out;
copy_Realm(krb5_princ_realm(context, server->principal),
&rep.ticket.realm);
@@ -1278,7 +1330,7 @@
DES3? */
ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
0, &tgt->key, e_text, reply);
-out:
+ out:
free_TGS_REP(&rep);
free_TransitedEncoding(&et.transited);
if(et.starttime)
@@ -1380,13 +1432,13 @@
}
static Realm
-find_rpath(Realm r)
+find_rpath(Realm crealm, Realm srealm)
{
const char *new_realm = krb5_config_get_string(context,
NULL,
- "libdefaults",
- "capath",
- r,
+ "capaths",
+ crealm,
+ srealm,
NULL);
return (Realm)new_realm;
}
@@ -1456,10 +1508,14 @@
if(ret) {
char *p;
- krb5_unparse_name(context, princ, &p);
+ ret = krb5_unparse_name(context, princ, &p);
+ if (ret != 0)
+ p = "<unparse_name failed>";
+ krb5_free_principal(context, princ);
kdc_log(0, "Ticket-granting ticket not found in database: %s: %s",
p, krb5_get_err_text(context, ret));
- free(p);
+ if (ret == 0)
+ free(p);
ret = KRB5KRB_AP_ERR_NOT_US;
goto out2;
}
@@ -1468,12 +1524,16 @@
*ap_req.ticket.enc_part.kvno != krbtgt->kvno){
char *p;
- krb5_unparse_name (context, princ, &p);
+ ret = krb5_unparse_name (context, princ, &p);
+ krb5_free_principal(context, princ);
+ if (ret != 0)
+ p = "<unparse_name failed>";
kdc_log(0, "Ticket kvno = %d, DB kvno = %d (%s)",
*ap_req.ticket.enc_part.kvno,
krbtgt->kvno,
p);
- free (p);
+ if (ret == 0)
+ free (p);
ret = KRB5KRB_AP_ERR_BADKEYVER;
goto out2;
}
@@ -1657,9 +1717,13 @@
}
principalname2krb5_principal(&sp, *s, r);
- krb5_unparse_name(context, sp, &spn);
+ ret = krb5_unparse_name(context, sp, &spn);
+ if (ret)
+ goto out;
principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
- krb5_unparse_name(context, cp, &cpn);
+ ret = krb5_unparse_name(context, cp, &cpn);
+ if (ret)
+ goto out;
unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units,
opt_str, sizeof(opt_str));
if(*opt_str)
@@ -1676,7 +1740,7 @@
if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
if(loop++ < 2) {
- new_rlm = find_rpath(req_rlm);
+ new_rlm = find_rpath(tgt->crealm, req_rlm);
if(new_rlm) {
kdc_log(5, "krbtgt for realm %s not found, trying %s",
req_rlm, new_rlm);
@@ -1684,7 +1748,9 @@
free(spn);
krb5_make_principal(context, &sp, r,
KRB5_TGS_NAME, new_rlm, NULL);
- krb5_unparse_name(context, sp, &spn);
+ ret = krb5_unparse_name(context, sp, &spn);
+ if (ret)
+ goto out;
goto server_lookup;
}
}
@@ -1697,7 +1763,9 @@
free(spn);
krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
realms[0], NULL);
- krb5_unparse_name(context, sp, &spn);
+ ret = krb5_unparse_name(context, sp, &spn);
+ if (ret)
+ goto out;
krb5_free_host_realm(context, realms);
goto server_lookup;
}
@@ -1725,6 +1793,18 @@
}
#endif
+ if(strcmp(krb5_principal_get_realm(context, sp),
+ krb5_principal_get_comp_string(context, krbtgt->principal, 1)) != 0) {
+ char *tpn;
+ ret = krb5_unparse_name(context, krbtgt->principal, &tpn);
+ kdc_log(0, "Request with wrong krbtgt: %s", (ret == 0) ? tpn : "<unknown>");
+ if(ret == 0)
+ free(tpn);
+ ret = KRB5KRB_AP_ERR_NOT_US;
+ goto out;
+
+ }
+
ret = check_flags(client, cpn, server, spn, FALSE);
if(ret)
goto out;
diff -urN crypto/heimdal/lib/krb5/krb5-protos.h heimdal-0.5.3/lib/krb5/krb5-protos.h
--- crypto/heimdal/lib/krb5/krb5-protos.h 2003-03-17 11:27:40.000000000 +0100
+++ crypto/heimdal/lib/krb5/krb5-protos.h 2004-04-01 16:16:33.000000000 +0200
@@ -521,6 +521,15 @@
krb5_data */*result_string*/);
krb5_error_code
+krb5_check_transited (
+ krb5_context /*context*/,
+ krb5_const_realm /*client_realm*/,
+ krb5_const_realm /*server_realm*/,
+ krb5_realm */*realms*/,
+ int /*num_realms*/,
+ int */*bad_realm*/);
+
+krb5_error_code
krb5_check_transited_realms (
krb5_context /*context*/,
const char *const */*realms*/,
diff -urN crypto/heimdal/lib/krb5/rd_req.c heimdal-0.5.3/lib/krb5/rd_req.c
--- crypto/heimdal/lib/krb5/rd_req.c 2001-06-18 04:48:18.000000000 +0200
+++ crypto/heimdal/lib/krb5/rd_req.c 2004-02-16 19:17:47.000000000 +0100
@@ -129,6 +129,32 @@
return 0;
}
+static krb5_error_code
+check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc)
+{
+ char **realms;
+ int num_realms;
+ krb5_error_code ret;
+
+ if(enc->transited.tr_type != DOMAIN_X500_COMPRESS)
+ return KRB5KDC_ERR_TRTYPE_NOSUPP;
+
+ if(enc->transited.contents.length == 0)
+ return 0;
+
+ ret = krb5_domain_x500_decode(context, enc->transited.contents,
+ &realms, &num_realms,
+ enc->crealm,
+ ticket->realm);
+ if(ret)
+ return ret;
+ ret = krb5_check_transited(context, enc->crealm,
+ ticket->realm,
+ realms, num_realms, NULL);
+ free(realms);
+ return ret;
+}
+
krb5_error_code
krb5_decrypt_ticket(krb5_context context,
Ticket *ticket,
@@ -161,6 +187,14 @@
krb5_clear_error_string (context);
return KRB5KRB_AP_ERR_TKT_EXPIRED;
}
+
+ if(!t.flags.transited_policy_checked) {
+ ret = check_transited(context, ticket, &t);
+ if(ret) {
+ free_EncTicketPart(&t);
+ return ret;
+ }
+ }
}
if(out)
@@ -209,29 +243,6 @@
return ret;
}
-#if 0
-static krb5_error_code
-check_transited(krb5_context context,
- krb5_ticket *ticket)
-{
- char **realms;
- int num_realms;
- krb5_error_code ret;
-
- if(ticket->ticket.transited.tr_type != DOMAIN_X500_COMPRESS)
- return KRB5KDC_ERR_TRTYPE_NOSUPP;
-
- ret = krb5_domain_x500_decode(ticket->ticket.transited.contents,
- &realms, &num_realms,
- ticket->client->realm,
- ticket->server->realm);
- if(ret)
- return ret;
- ret = krb5_check_transited_realms(context, realms, num_realms, NULL);
- free(realms);
- return ret;
-}
-#endif
krb5_error_code
krb5_verify_ap_req(krb5_context context,
diff -urN crypto/heimdal/lib/krb5/transited.c heimdal-0.5.3/lib/krb5/transited.c
--- crypto/heimdal/lib/krb5/transited.c 2002-09-09 16:03:03.000000000 +0200
+++ crypto/heimdal/lib/krb5/transited.c 2004-02-16 19:20:52.000000000 +0100
@@ -304,6 +304,12 @@
struct tr_realm *p, **q;
int ret;
+ if(tr.length == 0) {
+ *realms = NULL;
+ *num_realms = 0;
+ return 0;
+ }
+
/* split string in components */
ret = decode_realms(context, tr.data, tr.length, &r);
if(ret)
@@ -358,6 +364,9 @@
char *s = NULL;
int len = 0;
int i;
+ krb5_data_zero(encoding);
+ if (num_realms == 0)
+ return 0;
for(i = 0; i < num_realms; i++){
len += strlen(realms[i]);
if(realms[i][0] == '/')
@@ -365,6 +374,8 @@
}
len += num_realms - 1;
s = malloc(len + 1);
+ if (s == NULL)
+ return ENOMEM;
*s = '\0';
for(i = 0; i < num_realms; i++){
if(i && i < num_realms - 1)
@@ -379,6 +390,44 @@
}
krb5_error_code
+krb5_check_transited(krb5_context context,
+ krb5_const_realm client_realm,
+ krb5_const_realm server_realm,
+ krb5_realm *realms,
+ int num_realms,
+ int *bad_realm)
+{
+ char **tr_realms;
+ char **p;
+ int i;
+
+ if(num_realms == 0)
+ return 0;
+
+ tr_realms = krb5_config_get_strings(context, NULL,
+ "capaths",
+ client_realm,
+ server_realm,
+ NULL);
+ for(i = 0; i < num_realms; i++) {
+ for(p = tr_realms; p && *p; p++) {
+ if(strcmp(*p, realms[i]) == 0)
+ break;
+ }
+ if(p == NULL || *p == NULL) {
+ krb5_config_free_strings(tr_realms);
+ krb5_set_error_string (context, "no transit through realm %s",
+ realms[i]);
+ if(bad_realm)
+ *bad_realm = i;
+ return KRB5KRB_AP_ERR_ILL_CR_TKT;
+ }
+ }
+ krb5_config_free_strings(tr_realms);
+ return 0;
+}
+
+krb5_error_code
krb5_check_transited_realms(krb5_context context,
const char *const *realms,
int num_realms,