doc/share/security/patches/SA-04:08/heimdal6.patch
Bjoern A. Zeeb 3571e53040 Import FreeBSD Security Advisories and Errata Notices, as well as their
patches for easier mirroring, to eliminate a special copy, to make
www.freebsd.org/security a full copy of security.freebsd.org and be
eventually be the same.

For now files are just sitting there.   The symlinks are missing.

Discussed on:	www (repository location)
Discussed with:	simon (so)
2012-08-15 06:19:40 +00:00

558 lines
16 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 -u crypto/heimdal/kdc/kdc_locl.h:1.1.1.6 crypto/heimdal/kdc/kdc_locl.h:1.1.1.7
--- crypto/heimdal/kdc/kdc_locl.h:1.1.1.6 Thu Oct 9 14:36:19 2003
+++ crypto/heimdal/kdc/kdc_locl.h Sat Apr 3 15:20:48 2004
@@ -62,6 +62,10 @@
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_524;
extern int enable_v4_cross_realm;
--- crypto/heimdal/kdc/kerberos5.c 9 Oct 2003 19:36:19 -0000 1.1.1.8
+++ crypto/heimdal/kdc/kerberos5.c 3 Apr 2004 21:20:51 -0000 1.1.1.9
@@ -496,8 +496,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,27 +506,30 @@
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);
}
+ 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);
}
- kdc_log(0, "AS-REQ %s from %s for %s",
- client_name, from, server_name);
-
- if(ret)
+ 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);
ret = db_fetch(client_princ, &client);
if(ret){
@@ -842,13 +845,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);
@@ -930,9 +928,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);
@@ -1055,33 +1055,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;
@@ -1098,16 +1100,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;
}
@@ -1175,8 +1207,28 @@
if(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));
@@ -1276,7 +1328,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)
@@ -1378,13 +1430,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;
}
@@ -1676,7 +1728,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);
@@ -1724,6 +1776,18 @@
goto out;
}
#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)
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,