summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kdc/ChangeLog13
-rw-r--r--src/kdc/kdc_util.h1
-rw-r--r--src/kdc/kerberos_v4.c129
-rw-r--r--src/kdc/main.c9
-rw-r--r--src/krb524/ChangeLog8
-rw-r--r--src/krb524/cnv_tkt_skey.c20
-rw-r--r--src/krb524/krb524d.c36
-rw-r--r--src/lib/kdb/ChangeLog8
-rw-r--r--src/lib/kdb/keytab.c47
9 files changed, 190 insertions, 81 deletions
diff --git a/src/kdc/ChangeLog b/src/kdc/ChangeLog
index eb4273615..040281988 100644
--- a/src/kdc/ChangeLog
+++ b/src/kdc/ChangeLog
@@ -1,3 +1,16 @@
+2003-03-16 Sam Hartman <hartmans@mit.edu>
+
+ * main.c (initialize_realms): Add support to call
+ enable_v4_crossrealm if the user wants insecure operation
+
+ * kerberos_v4.c: Add enable_v4_crossrealm. By default krb4
+ cross-realm is not allowed as it is insecure. Also, remove
+ support for generating krb4 tickets encrypted in 3DES as they are
+ insecure.
+
+ * kdc_util.h: Define enable_v4_crossrealm, new function to enable
+ secure krb4 cross-realm authentication
+
2003-03-05 Tom Yu <tlyu@mit.edu>
* main.c (init_realm): Update call to krb5_ktdb_resolve().
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 9abe3b860..05ba07f4f 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -176,6 +176,7 @@ krb5_error_code process_v4 (const krb5_data *,
const krb5_fulladdr *,
krb5_data **);
void process_v4_mode (const char *, const char *);
+void enable_v4_crossrealm(char *);
#else
#define process_v4(foo,bar,quux,foobar) KRB5KRB_AP_ERR_BADVERSION
#endif
diff --git a/src/kdc/kerberos_v4.c b/src/kdc/kerberos_v4.c
index a87a1d5e5..01359792f 100644
--- a/src/kdc/kerberos_v4.c
+++ b/src/kdc/kerberos_v4.c
@@ -146,7 +146,7 @@ static krb5_data *response;
void kerberos_v4 (struct sockaddr_in *, KTEXT);
void kerb_err_reply (struct sockaddr_in *, KTEXT, long, char *);
-static int set_tgtkey (char *, krb5_kvno);
+static int set_tgtkey (char *, krb5_kvno, krb5_boolean);
/* Attributes converted from V5 to V4 - internal representation */
#define V4_KDB_REQUIRES_PREAUTH 0x1
@@ -180,6 +180,8 @@ static const struct v4mode_lookup_entry v4mode_table[] = {
static const int v4mode_table_nents = sizeof(v4mode_table)/
sizeof(v4mode_table[0]);
+static int allow_v4_crossrealm = 0;
+
void process_v4_mode(const char *program_name, const char *string)
{
int i, found;
@@ -205,6 +207,11 @@ void process_v4_mode(const char *program_name, const char *string)
return;
}
+void enable_v4_crossrealm ( char *programname) {
+ allow_v4_crossrealm = 1;
+ krb5_klog_syslog(LOG_ERR, "Enabling v4 cross-realm compatibility; this is a known security hole");
+}
+
krb5_error_code
process_v4(const krb5_data *pkt, const krb5_fulladdr *client_fulladdr,
krb5_data **resp)
@@ -382,6 +389,14 @@ compat_decrypt_key (krb5_key_data *in5, unsigned char *out4,
/* array of name-components + NULL ptr
*/
+/*
+ * Previously this code returned either a v4 key or a v5 key and you
+ * could tell from the enctype of the v5 key whether the v4 key was
+ * useful. Now we return both keys so the code can try both des3 and
+ * des decryption. We fail if the ticket doesn't have a v4 key.
+ * Also, note as a side effect, the v5 key is basically useless in
+ * the client case. It is still returned so the caller can free it.
+ */
static int
kerb_get_principal(char *name, char *inst, /* could have wild cards */
Principal *principal,
@@ -461,8 +476,28 @@ kerb_get_principal(char *name, char *inst, /* could have wild cards */
return(0);
}
} else {
- /* XXX yes I know this is a hardcoded search order */
- if (krb5_dbe_find_enctype(kdc_context, &entries,
+ if ( krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4, kvno, &pkey) &&
+ krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES_CBC_CRC,
+ -1, kvno, &pkey)) {
+ lt = klog(L_KRB_PERR,
+ "KDC V4: failed to find key for %s.%s #%d",
+ name, inst, kvno);
+ krb5_db_free_principal(kdc_context, &entries, nprinc);
+ return(0);
+ }
+ }
+
+ if (!compat_decrypt_key(pkey, k, k5key, issrv)) {
+ memcpy( &principal->key_low, k, LONGLEN);
+ memcpy( &principal->key_high, (krb5_ui_4 *) k + 1, LONGLEN);
+ }
+ memset(k, 0, sizeof k);
+ if (issrv) {
+ krb5_free_keyblock_contents (kdc_context, k5key);
+ if (krb5_dbe_find_enctype(kdc_context, &entries,
ENCTYPE_DES3_CBC_RAW,
-1, kvno, &pkey) &&
krb5_dbe_find_enctype(kdc_context, &entries,
@@ -478,17 +513,16 @@ kerb_get_principal(char *name, char *inst, /* could have wild cards */
ENCTYPE_DES_CBC_CRC,
-1, kvno, &pkey)) {
lt = klog(L_KRB_PERR,
- "KDC V4: failed to find key for %s.%s #%d",
+ "KDC V4: failed to find key for %s.%s #%d (after having found it once)",
name, inst, kvno);
krb5_db_free_principal(kdc_context, &entries, nprinc);
return(0);
}
- }
+ compat_decrypt_key(pkey, k, k5key, issrv);
+ memset (k, 0, sizeof k);
+ }
+
- if (!compat_decrypt_key(pkey, k, k5key, issrv)) {
- memcpy( &principal->key_low, k, LONGLEN);
- memcpy( &principal->key_high, (krb5_ui_4 *) k + 1, LONGLEN);
- }
/*
* Convert v5's entries struct to v4's Principal struct:
* v5's time-unit for lifetimes is 1 sec, while v4 uses 5 minutes,
@@ -732,21 +766,14 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
kdb_encrypt_key(key, key, master_key,
master_key_schedule, DECRYPT);
/* construct and seal the ticket */
- if (K4KDC_ENCTYPE_OK(k5key.enctype)) {
- krb_create_ticket(tk, k_flags, a_name_data.name,
- a_name_data.instance, local_realm,
- client_host.s_addr, (char *) session_key,
- lifetime, kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- key);
- } else {
- krb_cr_tkt_krb5(tk, k_flags, a_name_data.name,
- a_name_data.instance, local_realm,
- client_host.s_addr, (char *) session_key,
- lifetime, kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- &k5key);
- }
+ /* We always issue des tickets; the 3des tickets are a broken hack*/
+ krb_create_ticket(tk, k_flags, a_name_data.name,
+ a_name_data.instance, local_realm,
+ client_host.s_addr, (char *) session_key,
+ lifetime, kerb_time.tv_sec,
+ s_name_data.name, s_name_data.instance,
+ key);
+
krb5_free_keyblock_contents(kdc_context, &k5key);
memset(key, 0, sizeof(key));
memset(key_s, 0, sizeof(key_s));
@@ -826,8 +853,15 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
tktrlm[REALM_SZ-1] = '\0';
kvno = (krb5_kvno)auth->dat[2];
- if (set_tgtkey(tktrlm, kvno)) {
- lt = klog(L_ERR_UNK,
+ if ((!allow_v4_crossrealm)&&strcmp(tktrlm, local_realm) != 0) {
+ lt = klog(L_ERR_UNK,
+ "Cross realm ticket from %s denied by policy,", tktrlm);
+ kerb_err_reply(client, pkt,
+ KERB_ERR_PRINCIPAL_UNKNOWN, lt);
+ return;
+ }
+ if (set_tgtkey(tktrlm, kvno, 0)) {
+ lt = klog(L_ERR_UNK,
"FAILED set_tgtkey realm %s, kvno %d. Host: %s ",
tktrlm, kvno, inet_ntoa(client_host));
/* no better error code */
@@ -837,6 +871,19 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
}
kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
ad, 0);
+ if (kerno) {
+ if (set_tgtkey(tktrlm, kvno, 1)) {
+ lt = klog(L_ERR_UNK,
+ "FAILED 3des set_tgtkey realm %s, kvno %d. Host: %s ",
+ tktrlm, kvno, inet_ntoa(client_host));
+ /* no better error code */
+ kerb_err_reply(client, pkt,
+ KERB_ERR_PRINCIPAL_UNKNOWN, lt);
+ return;
+ }
+ kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
+ ad, 0);
+ }
if (kerno) {
klog(L_ERR_UNK, "FAILED krb_rd_req from %s: %s",
@@ -913,21 +960,13 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
des_new_random_key(session_key);
#endif
- if (K4KDC_ENCTYPE_OK(k5key.enctype)) {
- krb_create_ticket(tk, k_flags, ad->pname, ad->pinst,
- ad->prealm, client_host.s_addr,
- (char *) session_key, lifetime,
- kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- key);
- } else {
- krb_cr_tkt_krb5(tk, k_flags, ad->pname, ad->pinst,
- ad->prealm, client_host.s_addr,
- (char *) session_key, lifetime,
- kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- &k5key);
- }
+ /* ALways issue des tickets*/
+ krb_create_ticket(tk, k_flags, ad->pname, ad->pinst,
+ ad->prealm, client_host.s_addr,
+ (char *) session_key, lifetime,
+ kerb_time.tv_sec,
+ s_name_data.name, s_name_data.instance,
+ key);
krb5_free_keyblock_contents(kdc_context, &k5key);
memset(key, 0, sizeof(key));
memset(key_s, 0, sizeof(key_s));
@@ -1107,11 +1146,12 @@ check_princ(char *p_name, char *instance, int lifetime, Principal *p,
/* Set the key for krb_rd_req so we can check tgt */
static int
-set_tgtkey(char *r, krb5_kvno kvno)
+set_tgtkey(char *r, krb5_kvno kvno, krb5_boolean use_3des)
{
int n;
static char lastrealm[REALM_SZ] = "";
static int last_kvno = 0;
+ static krb5_boolean last_use_3des = 0;
static int more;
Principal p_st;
Principal *p = &p_st;
@@ -1119,7 +1159,7 @@ set_tgtkey(char *r, krb5_kvno kvno)
krb5_keyblock k5key;
k5key.contents = NULL;
- if (!strcmp(lastrealm, r) && last_kvno == kvno)
+ if (!strcmp(lastrealm, r) && last_kvno == kvno && last_use_3des == use_3des)
return (KSUCCESS);
/* log("Getting key for %s", r); */
@@ -1141,11 +1181,12 @@ set_tgtkey(char *r, krb5_kvno kvno)
return KFAILURE;
}
- if (!K4KDC_ENCTYPE_OK(k5key.enctype)) {
+ if (use_3des&&!K4KDC_ENCTYPE_OK(k5key.enctype)) {
krb_set_key_krb5(kdc_context, &k5key);
strncpy(lastrealm, r, sizeof(lastrealm) - 1);
lastrealm[sizeof(lastrealm) - 1] = '\0';
last_kvno = kvno;
+ last_use_3des = use_3des;
} else {
/* unseal tgt key from master key */
memcpy(key, &p->key_low, 4);
diff --git a/src/kdc/main.c b/src/kdc/main.c
index 3e5091cbf..5fb460b0a 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -551,7 +551,7 @@ setup_sam(void)
void
usage(char *name)
{
- fprintf(stderr, "usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-4 v4mode] [-n]\n", name);
+ fprintf(stderr, "usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-4 v4mode] [-X] [-n]\n", name);
return;
}
@@ -606,7 +606,7 @@ initialize_realms(krb5_context kcontext, int argc, char **argv)
* Loop through the option list. Each time we encounter a realm name,
* use the previously scanned options to fill in for defaults.
*/
- while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n4:3")) != -1) {
+ while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n4:X3")) != -1) {
switch(c) {
case 'r': /* realm name for db */
if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
@@ -662,6 +662,11 @@ initialize_realms(krb5_context kcontext, int argc, char **argv)
v4mode = strdup(optarg);
#endif
break;
+ case 'X':
+#ifdef KRB5_KRB4_COMPAT
+ enable_v4_crossrealm(argv[0]);
+#endif
+ break;
case '3':
#ifdef ATHENA_DES3_KLUDGE
if (krb5_enctypes_list[krb5_enctypes_length-1].etype
diff --git a/src/krb524/ChangeLog b/src/krb524/ChangeLog
index 2a7b6cc54..ba03cc0da 100644
--- a/src/krb524/ChangeLog
+++ b/src/krb524/ChangeLog
@@ -1,3 +1,11 @@
+2003-03-16 Sam Hartman <hartmans@mit.edu>
+
+ * krb524d.c (handle_classic_v4): Do not support 3des enctypes as
+ they are insecure. Also, by default do not allow krb4
+ cross-realm.
+
+ * cnv_tkt_skey.c (krb524_convert_tkt_skey): Don't support 3des tickets
+
2003-03-12 Ken Raeburn <raeburn@mit.edu>
* cnv_tkt_skey.c (krb524_convert_tkt_skey): Extract source IP
diff --git a/src/krb524/cnv_tkt_skey.c b/src/krb524/cnv_tkt_skey.c
index 595a1d392..3730ce43c 100644
--- a/src/krb524/cnv_tkt_skey.c
+++ b/src/krb524/cnv_tkt_skey.c
@@ -184,26 +184,8 @@ int krb524_convert_tkt_skey(context, v5tkt, v4tkt, v5_skey, v4_skey,
sname,
sinst,
v4_skey->contents);
- } else {
- /* Force enctype to be raw if using DES3. */
- if (v4_skey->enctype == ENCTYPE_DES3_CBC_SHA1 ||
- v4_skey->enctype == ENCTYPE_LOCAL_DES3_HMAC_SHA1)
- v4_skey->enctype = ENCTYPE_DES3_CBC_RAW;
- ret = krb524int_krb_cr_tkt_krb5(v4tkt,
- 0, /* flags */
- pname,
- pinst,
- prealm,
- sinp->sin_addr.s_addr,
- (char *) v5etkt->session->contents,
- lifetime,
- /* issue_data */
- server_time,
- sname,
- sinst,
- v4_skey);
}
-
+ else abort();
krb5_free_enc_tkt_part(context, v5etkt);
v5tkt->enc_part2 = NULL;
if (ret == KSUCCESS)
diff --git a/src/krb524/krb524d.c b/src/krb524/krb524d.c
index 4995b515f..0dce9cbc9 100644
--- a/src/krb524/krb524d.c
+++ b/src/krb524/krb524d.c
@@ -76,6 +76,7 @@ static int debug = 0;
void *handle = NULL;
int use_keytab, use_master;
+int allow_v4_crossrealm = 0;
char *keytab = NULL;
krb5_keytab kt;
@@ -137,7 +138,10 @@ int main(argc, argv)
config_params.mask = 0;
while (argc) {
- if (strncmp(*argv, "-k", 2) == 0)
+ if (strncmp(*argv, "-X", 2) == 0) {
+ allow_v4_crossrealm = 1;
+ }
+ else if (strncmp(*argv, "-k", 2) == 0)
use_keytab = 1;
else if (strncmp(*argv, "-m", 2) == 0)
use_master = 1;
@@ -524,19 +528,7 @@ handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
&v5_service_key, NULL)))
goto error;
- if ((ret = lookup_service_key(context, v5tkt->server,
- ENCTYPE_DES3_CBC_RAW,
- 0, /* highest kvno */
- &v4_service_key, v4kvno)) &&
- (ret = lookup_service_key(context, v5tkt->server,
- ENCTYPE_LOCAL_DES3_HMAC_SHA1,
- 0,
- &v4_service_key, v4kvno)) &&
- (ret = lookup_service_key(context, v5tkt->server,
- ENCTYPE_DES3_CBC_SHA1,
- 0,
- &v4_service_key, v4kvno)) &&
- (ret = lookup_service_key(context, v5tkt->server,
+ if ( (ret = lookup_service_key(context, v5tkt->server,
ENCTYPE_DES_CBC_CRC,
0,
&v4_service_key, v4kvno)))
@@ -544,8 +536,19 @@ handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
if (debug)
printf("service key retrieved\n");
+ if ((ret = krb5_decrypt_tkt_part(context, &v5_service_key, v5tkt))) {
+ goto error;
+ }
- ret = krb524_convert_tkt_skey(context, v5tkt, &v4tkt, &v5_service_key,
+ if (!(allow_v4_crossrealm || krb5_realm_compare(context, v5tkt->server,
+ v5tkt->enc_part2->client))) {
+ret = KRB5KDC_ERR_POLICY ;
+ goto error;
+ }
+ krb5_free_enc_tkt_part(context, v5tkt->enc_part2);
+ v5tkt->enc_part2= NULL;
+
+ ret = krb524_convert_tkt_skey(context, v5tkt, &v4tkt, &v5_service_key,
&v4_service_key,
(struct sockaddr_in *)saddr);
if (ret)
@@ -561,6 +564,9 @@ handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
printf("v4 credentials encoded\n");
error:
+ if (v5tkt->enc_part2)
+ krb5_free_enc_tkt_part(context, v5tkt->enc_part2);
+
if(v5_service_key.contents)
krb5_free_keyblock_contents(context, &v5_service_key);
if (v4_service_key.contents)
diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog
index d685be6d9..4592b4c19 100644
--- a/src/lib/kdb/ChangeLog
+++ b/src/lib/kdb/ChangeLog
@@ -1,3 +1,11 @@
+2003-03-16 Sam Hartman <hartmans@mit.edu>
+
+ * keytab.c (krb5_ktkdb_get_entry): Match only against the first
+ enctype for non-cross-realm tickets so we will only accept
+ tickets that the current configuration would have issued. For
+ cross-realm tickets be liberal and match against the specified
+ enctype.
+
2003-03-05 Tom Yu <tlyu@mit.edu>
* kdb_xdr.c (krb5_dbe_search_enctype): Check for ktype > 0 rather
diff --git a/src/lib/kdb/keytab.c b/src/lib/kdb/keytab.c
index 6ec375ac2..6a1dea152 100644
--- a/src/lib/kdb/keytab.c
+++ b/src/lib/kdb/keytab.c
@@ -24,10 +24,14 @@
* or implied warranty.
*
*/
+#include <string.h>
#include "k5-int.h"
#include "kdb_kt.h"
+static int
+is_xrealm_tgt(krb5_context, krb5_const_principal);
+
krb5_error_code krb5_ktkdb_close (krb5_context, krb5_keytab);
krb5_error_code krb5_ktkdb_get_entry (krb5_context, krb5_keytab, krb5_const_principal,
@@ -116,6 +120,8 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
krb5_db_entry db_entry;
krb5_boolean more = 0;
int n = 0;
+ int xrealm_tgt = is_xrealm_tgt(context, principal);
+ int similar;
if (ktkdb_ctx)
context = ktkdb_ctx;
@@ -150,16 +156,31 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
if (kerror)
goto error;
+ /* For cross realm tgts, we match whatever enctype is provided;
+ * for other principals, we only match the first enctype that is
+ * found. Since the TGS and AS code do the same thing, then we
+ * will only successfully decrypt tickets we have issued.*/
kerror = krb5_dbe_find_enctype(context, &db_entry,
- enctype, -1, kvno, &key_data);
+ xrealm_tgt?enctype:-1,
+ -1, kvno, &key_data);
if (kerror)
goto error;
+
kerror = krb5_dbekd_decrypt_key_data(context, master_key,
key_data, &entry->key, NULL);
if (kerror)
goto error;
+ kerror = krb5_c_enctype_compare(context, enctype, entry->key.enctype, &similar);
+ if (kerror)
+ goto error;
+
+ if (!similar) {
+ kerror = KRB5_KDB_NO_PERMITTED_KEY;
+ goto error;
+ }
+
/*
* Coerce the enctype of the output keyblock in case we got an
* inexact match on the enctype.
@@ -176,3 +197,27 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
krb5_db_close_database(context);
return(kerror);
}
+
+/*
+ * is_xrealm_tgt: Returns true if the principal is a cross-realm TGT
+ * principal-- a principal with first component krbtgt and second
+ * component not equal to realm.
+ */
+static int
+is_xrealm_tgt(krb5_context context, krb5_const_principal princ)
+{
+ krb5_data *dat;
+ if (krb5_princ_size(context, princ) != 2)
+ return 0;
+ dat = krb5_princ_component(context, princ, 0);
+ if (strncmp("krbtgt", dat->data, dat->length) != 0)
+ return 0;
+ dat = krb5_princ_component(context, princ, 1);
+ if (dat->length != princ->realm.length)
+ return 1;
+ if (strcmp(dat->data, princ->realm.data) == 0)
+ return 0;
+ return 1;
+
+}
+