[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: multiple krb5 salted des keys



Derrick J Brashear <shadow@dementia.org> writes:

> and the mods to make all the necessary keys be created in set_keys
> is also included

I re-did in a different way.

With this change you can do something like:

[kadmin]
        default_keys = v5 v4 afs3-salt:andrew.cmu.edu

or stuff like:

        default_keys = des3-cbc-sha1:pw-salt:foobar des:pw-salt:

to get v4 salted des-keys and des3 keys salted with the string
`foobar'. Don't know if this is ever useful.

Still modulo a better named option for this.

/Johan

--- set_keys.c	2000/03/23 23:06:31	1.19
+++ set_keys.c	2000/06/26 14:22:02	1.20
@@ -33,7 +33,7 @@
 
 #include "kadm5_locl.h"
 
-RCSID("$Id: set_keys.c,v 1.19 2000/03/23 23:06:31 assar Exp $");
+RCSID("$Id: set_keys.c,v 1.20 2000/06/26 14:22:02 joda Exp $");
 
 /*
  * free all the memory used by (len, keys)
@@ -82,83 +82,227 @@
 static krb5_enctype des_types[] = { ETYPE_DES_CBC_CRC,
 				    ETYPE_DES_CBC_MD4,
 				    ETYPE_DES_CBC_MD5 };
+static unsigned n_des_types = sizeof(des_types) / sizeof(des_types[0]);
 
-static unsigned n_des_types = 3;
+static krb5_error_code
+make_keys(krb5_context context, krb5_principal principal, const char *password,
+	  Key **keys_ret, size_t *num_keys_ret)
+{
+    krb5_enctype all_etypes[] = { ETYPE_DES3_CBC_SHA1,
+				  ETYPE_DES_CBC_MD5,
+				  ETYPE_DES_CBC_MD4,
+				  ETYPE_DES_CBC_CRC };
 
-/*
- * Set the keys of `ent' to the string-to-key of `password'
- */
 
-kadm5_ret_t
-_kadm5_set_keys(kadm5_server_context *context,
-		hdb_entry *ent, 
-		const char *password)
-{
-    kadm5_ret_t ret = 0;
+    krb5_enctype e;
+
+    krb5_error_code ret;
+    char **ktypes, **kp;
+
+    Key *keys = NULL, *tmp;
+    int num_keys = 0;
+    Key key;
+
     int i;
-    unsigned len;
-    Key *keys;
-    krb5_salt salt;
-    krb5_boolean v4_salt = FALSE;
 
-    len  = n_des_types + 1;
-    keys = malloc (len * sizeof(*keys));
-    if (keys == NULL)
-	return ENOMEM;
+    ktypes = krb5_config_get_strings(context, NULL, "kadmin", 
+				     "default_keys", NULL);
 
-    init_keys (keys, len);
+    /* for each entry in `default_keys' try to parse it as a sequence
+       of etype:salttype:salt, syntax of this if something like:
+       [(des|des3|etype):](pw|afs3)[:string], if etype is omitted it
+       means everything, and if string is omitted is means the default
+       string (for that principal). Additional special values:
+       v5 == pw, and
+       v4 == pw: 
+    */
 
-    salt.salttype         = KRB5_PW_SALT;
-    salt.saltvalue.length = 0;
-    salt.saltvalue.data   = NULL;
+    for(kp = ktypes; kp && *kp; kp++) {
+	krb5_enctype *etypes;
+	int num_etypes;
+	krb5_salt salt;
+	krb5_boolean salt_set;
 
-    if (krb5_config_get_bool (context->context,
-			      NULL, "kadmin", "use_v4_salt", NULL)) {
-	v4_salt = TRUE;
+	const char *p;
+	char buf[3][256];
+	int num_buf = 0;
+
+	p = *kp;
+	if(strcmp(p, "v5") == 0)
+	    p = "pw-salt";
+	else if(strcmp(p, "v4") == 0)
+	    p = "des:pw-salt:";
+	
+	/* split p in a list of :-separated strings */
+	for(num_buf = 0; num_buf < 3; num_buf++)
+	    if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1)
+		break;
+
+	etypes = NULL;
+	num_etypes = 0;
+	memset(&salt, 0, sizeof(salt));
+	salt_set = FALSE;
+
+	for(i = 0; i < num_buf; i++) {
+	    if(etypes == NULL) {
+		/* this might be a etype specifier */
+		/* XXX there should be a string_to_etypes handling
+                   special cases like `des' and `all' */
+		if(strcmp(buf[i], "des") == 0) {
+		    etypes = all_etypes + 1;
+		    num_etypes = 3;
+		    continue;
+		} else if(strcmp(buf[i], "des3") == 0) {
+		    e = ETYPE_DES3_CBC_SHA1;
+		    etypes = &e;
+		    num_etypes = 1;
+		    continue;
     } else {
-	ret = krb5_get_pw_salt (context->context, ent->principal, &salt);
-	if (ret)
-	    goto out;
+		    ret = krb5_string_to_enctype(context, buf[i], &e);
+		    if(ret == 0) {
+			etypes = &e;
+			num_etypes = 1;
+			continue;
+		    }
+		}
+	    }
+	    if(salt.salttype == 0) {
+		/* interpret string as a salt specifier, if no etype
+                   is set, this sets default values */
+		/* XXX should perhaps use string_to_salttype, but that
+                   interface sucks */
+		if(strcmp(buf[i], "pw-salt") == 0) {
+		    if(etypes == NULL) {
+			etypes = all_etypes;
+			num_etypes = 4;
+		    }
+		    salt.salttype = KRB5_PW_SALT;
+		} else if(strcmp(buf[i], "afs3-salt") == 0) {
+		    if(etypes == NULL) {
+			etypes = all_etypes + 1;
+			num_etypes = 3;
+		    }
+		    salt.salttype = KRB5_AFS3_SALT;
+		}
+	    } else {
+		/* if there is a final string, use it as the string to
+                   salt with, this is mostly useful with null salt for
+                   v4 compat, and a cell name for afs compat */
+		salt.saltvalue.data = buf[i];
+		salt.saltvalue.length = strlen(buf[i]);
+		salt_set = TRUE;
+	    }
     }
 
-    for (i = 0; i < n_des_types; ++i) {
-	ret = krb5_string_to_key_salt (context->context,
-				       des_types[i],
+	if(etypes == NULL || salt.salttype == 0) {	    
+	    krb5_warnx(context, "bad value for default_keys `%s'", *kp);
+	    continue;
+	}
+
+	if(!salt_set && salt.salttype == KRB5_PW_SALT)
+	    /* make up default salt */
+	    ret = krb5_get_pw_salt(context, principal, &salt);
+	memset(&key, 0, sizeof(key));
+	for(i = 0; i < num_etypes; i++) {
+	    ret = krb5_string_to_key_salt (context,
+					   etypes[i],
 				       password,
 				       salt,
-				       &keys[i].key);
+					   &key.key);
+
 	if (ret)
 	    goto out;
-	if (v4_salt) {
-	    keys[i].salt = malloc (sizeof(*keys[i].salt));
-	    if (keys[i].salt == NULL) {
+
+	    if (salt_set) {
+		/* is the salt has not been set explicitly, it will be
+                   the default salt, so there's no need to explicitly
+                   copy it */
+		key.salt = malloc (sizeof(*key.salt));
+		if (key.salt == NULL) {
 		ret = ENOMEM;
 		goto out;
 	    }
-	    keys[i].salt->type = salt.salttype;
-	    ret = copy_octet_string (&salt.saltvalue, &keys[i].salt->salt);
+		key.salt->type = salt.salttype;
+		ret = krb5_data_copy(&key.salt->salt, 
+				     salt.saltvalue.data, 
+				     salt.saltvalue.length);
 	    if (ret)
 		goto out;
 	}
+	    tmp = realloc(keys, (num_keys + 1) * sizeof(*keys));
+	    if(tmp == NULL) {
+		ret = ENOMEM;
+		goto out;
+	    }
+	    keys = tmp;
+	    keys[num_keys++] = key;
     }
+    }
 
-    ret = krb5_string_to_key (context->context,
-			      ETYPE_DES3_CBC_SHA1,
-			      password,
-			      ent->principal,
-			      &keys[n_des_types].key);
+    if(num_keys == 0) {
+	/* if we didn't manage to find a single valid key, create a
+           default set */
+	/* XXX only do this is there is no `default_keys'? */
+	krb5_salt v5_salt;
+	tmp = realloc(keys, (num_keys + 4) * sizeof(*keys));
+	if(tmp == NULL) {
+	    ret = ENOMEM;
+	    goto out;
+	}
+	keys = tmp;
+	ret = krb5_get_pw_salt(context, principal, &v5_salt);
     if (ret)
 	goto out;
+	for(i = 0; i < 4; i++) {
+	    memset(&key, 0, sizeof(key));
+	    ret = krb5_string_to_key_salt(context, all_etypes[i], password, 
+					  v5_salt, &key.key);
+	    if(ret) {
+		krb5_free_salt(context, v5_salt);
+		goto out;
+	    }
+	    keys[num_keys++] = key;
+	}
+	krb5_free_salt(context, v5_salt);
+    }
 
+  out:
+    if(ret == 0) {
+	*keys_ret = keys;
+	*num_keys_ret = num_keys;
+    } else {
+	for(i = 0; i < num_keys; i++) {
+	    free_Key(&keys[i]);
+	}
+	free(keys);
+    }
+    return ret;
+}
+
+/*
+ * Set the keys of `ent' to the string-to-key of `password'
+ */
+
+kadm5_ret_t
+_kadm5_set_keys(kadm5_server_context *context,
+		hdb_entry *ent, 
+		const char *password)
+{
+    kadm5_ret_t ret;
+    Key *keys;
+    size_t num_keys;
+
+    ret = make_keys(context->context, ent->principal, password, 
+		    &keys, &num_keys);
+
+    if(ret)
+	return ret;
+    
     free_keys (context, ent->keys.len, ent->keys.val);
-    ent->keys.len = len;
     ent->keys.val = keys;
+    ent->keys.len = num_keys;
     ent->kvno++;
-    return ret;
-out:
-    krb5_data_free (&salt.saltvalue);
-    free_keys (context, len, keys);
-    return ret;
+    return 0;
 }
 
 /*