Beispiel #1
0
static krb5_error_code
add_enctype_to_key_set(Key **key_set, size_t *nkeyset,
		       krb5_enctype enctype, krb5_salt *salt)
{
    krb5_error_code ret;
    Key key, *tmp;

    memset(&key, 0, sizeof(key));

    tmp = realloc(*key_set, (*nkeyset + 1) * sizeof((*key_set)[0]));
    if (tmp == NULL)
	return ENOMEM;

    *key_set = tmp;

    key.key.keytype = enctype;
    key.key.keyvalue.length = 0;
    key.key.keyvalue.data = NULL;

    if (salt) {
	key.salt = calloc(1, sizeof(*key.salt));
	if (key.salt == NULL) {
	    free_Key(&key);
	    return ENOMEM;
	}

	key.salt->type = salt->salttype;
	krb5_data_zero (&key.salt->salt);

	ret = krb5_data_copy(&key.salt->salt,
			     salt->saltvalue.data,
			     salt->saltvalue.length);
	if (ret) {
	    free_Key(&key);
	    return ret;
	}
    } else
	key.salt = NULL;

    (*key_set)[*nkeyset] = key;

    *nkeyset += 1;

    return 0;
}
Beispiel #2
0
void
hdb_free_key(Key *key)
{
    memset(key->key.keyvalue.data,
	   0,
	   key->key.keyvalue.length);
    free_Key(key);
    free(key);
}
Beispiel #3
0
kadm5_ret_t
kadm5_log_replay_modify (kadm5_server_context *context,
			 u_int32_t ver,
			 u_int32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    int32_t mask;
    krb5_data value;
    hdb_entry ent, log_ent;

    krb5_ret_int32 (sp, &mask);
    len -= 4;
    ret = krb5_data_alloc (&value, len);
    if (ret)
	return ret;
    krb5_storage_read (sp, value.data, len);
    ret = hdb_value2entry (context->context, &value, &log_ent);
    krb5_data_free(&value);
    if (ret)
	return ret;
    ent.principal = log_ent.principal;
    log_ent.principal = NULL;
    ret = context->db->hdb_fetch(context->context, context->db, 
				 HDB_F_DECRYPT, &ent);
    if (ret)
	return ret;
    if (mask & KADM5_PRINC_EXPIRE_TIME) {
	if (log_ent.valid_end == NULL) {
	    ent.valid_end = NULL;
	} else {
	    if (ent.valid_end == NULL)
		ent.valid_end = malloc(sizeof(*ent.valid_end));
	    *ent.valid_end = *log_ent.valid_end;
	}
    }
    if (mask & KADM5_PW_EXPIRATION) {
	if (log_ent.pw_end == NULL) {
	    ent.pw_end = NULL;
	} else {
	    if (ent.pw_end == NULL)
		ent.pw_end = malloc(sizeof(*ent.pw_end));
	    *ent.pw_end = *log_ent.pw_end;
	}
    }
    if (mask & KADM5_LAST_PWD_CHANGE) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_ATTRIBUTES) {
	ent.flags = log_ent.flags;
    }
    if (mask & KADM5_MAX_LIFE) {
	if (log_ent.max_life == NULL) {
	    ent.max_life = NULL;
	} else {
	    if (ent.max_life == NULL)
		ent.max_life = malloc (sizeof(*ent.max_life));
	    *ent.max_life = *log_ent.max_life;
	}
    }
    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
	if (ent.modified_by == NULL) {
	    ent.modified_by = malloc(sizeof(*ent.modified_by));
	} else
	    free_Event(ent.modified_by);
	copy_Event(log_ent.modified_by, ent.modified_by);
    }
    if (mask & KADM5_KVNO) {
	ent.kvno = log_ent.kvno;
    }
    if (mask & KADM5_MKVNO) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_AUX_ATTRIBUTES) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY_CLR) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_MAX_RLIFE) {
	if (log_ent.max_renew == NULL) {
	    ent.max_renew = NULL;
	} else {
	    if (ent.max_renew == NULL)
		ent.max_renew = malloc (sizeof(*ent.max_renew));
	    *ent.max_renew = *log_ent.max_renew;
	}
    }
    if (mask & KADM5_LAST_SUCCESS) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_LAST_FAILED) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_FAIL_AUTH_COUNT) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_KEY_DATA) {
	size_t len;
	int i;

	for (i = 0; i < ent.keys.len; ++i)
	    free_Key(&ent.keys.val[i]);
	free (ent.keys.val);

	len = log_ent.keys.len;

	ent.keys.len = len;
	ent.keys.val = malloc(len * sizeof(*ent.keys.val));
	for (i = 0; i < ent.keys.len; ++i)
	    copy_Key(&log_ent.keys.val[i],
		     &ent.keys.val[i]);
    }
    ret = context->db->hdb_store(context->context, context->db, 
				 HDB_F_REPLACE, &ent);
    hdb_free_entry (context->context, &ent);
    hdb_free_entry (context->context, &log_ent);
    return ret;
}
Beispiel #4
0
static kadm5_ret_t
kadm5_log_replay_modify (kadm5_server_context *context,
			 uint32_t ver,
			 uint32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    int32_t mask;
    krb5_data value;
    hdb_entry_ex ent, log_ent;

    memset(&log_ent, 0, sizeof(log_ent));

    krb5_ret_int32 (sp, &mask);
    len -= 4;
    ret = krb5_data_alloc (&value, len);
    if (ret) {
	krb5_set_error_message(context->context, ret, "out of memory");
	return ret;
    }
    krb5_storage_read (sp, value.data, len);
    ret = hdb_value2entry (context->context, &value, &log_ent.entry);
    krb5_data_free(&value);
    if (ret)
	return ret;

    memset(&ent, 0, sizeof(ent));
    ret = context->db->hdb_fetch_kvno(context->context, context->db,
				      log_ent.entry.principal,
				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret)
	goto out;
    if (mask & KADM5_PRINC_EXPIRE_TIME) {
	if (log_ent.entry.valid_end == NULL) {
	    ent.entry.valid_end = NULL;
	} else {
	    if (ent.entry.valid_end == NULL) {
		ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
		if (ent.entry.valid_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.valid_end = *log_ent.entry.valid_end;
	}
    }
    if (mask & KADM5_PW_EXPIRATION) {
	if (log_ent.entry.pw_end == NULL) {
	    ent.entry.pw_end = NULL;
	} else {
	    if (ent.entry.pw_end == NULL) {
		ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
		if (ent.entry.pw_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.pw_end = *log_ent.entry.pw_end;
	}
    }
    if (mask & KADM5_LAST_PWD_CHANGE) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_ATTRIBUTES) {
	ent.entry.flags = log_ent.entry.flags;
    }
    if (mask & KADM5_MAX_LIFE) {
	if (log_ent.entry.max_life == NULL) {
	    ent.entry.max_life = NULL;
	} else {
	    if (ent.entry.max_life == NULL) {
		ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
		if (ent.entry.max_life == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_life = *log_ent.entry.max_life;
	}
    }
    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
	if (ent.entry.modified_by == NULL) {
	    ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
	    if (ent.entry.modified_by == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	} else
	    free_Event(ent.entry.modified_by);
	ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    goto out;
	}
    }
    if (mask & KADM5_KVNO) {
	ent.entry.kvno = log_ent.entry.kvno;
    }
    if (mask & KADM5_MKVNO) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_AUX_ATTRIBUTES) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY_CLR) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_MAX_RLIFE) {
	if (log_ent.entry.max_renew == NULL) {
	    ent.entry.max_renew = NULL;
	} else {
	    if (ent.entry.max_renew == NULL) {
		ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
		if (ent.entry.max_renew == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_renew = *log_ent.entry.max_renew;
	}
    }
    if (mask & KADM5_LAST_SUCCESS) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_LAST_FAILED) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_FAIL_AUTH_COUNT) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_KEY_DATA) {
	size_t num;
	int i;

	for (i = 0; i < ent.entry.keys.len; ++i)
	    free_Key(&ent.entry.keys.val[i]);
	free (ent.entry.keys.val);

	num = log_ent.entry.keys.len;

	ent.entry.keys.len = num;
	ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
	if (ent.entry.keys.val == NULL) {
	    krb5_set_error_message(context->context, ENOMEM, "out of memory");
	    return ENOMEM;
	}
	for (i = 0; i < ent.entry.keys.len; ++i) {
	    ret = copy_Key(&log_ent.entry.keys.val[i],
			   &ent.entry.keys.val[i]);
	    if (ret) {
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	}
    }
    if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
	HDB_extensions *es = ent.entry.extensions;

	ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
	if (ent.entry.extensions == NULL)
	    goto out;

	ret = copy_HDB_extensions(log_ent.entry.extensions,
				  ent.entry.extensions);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    free(ent.entry.extensions);
	    ent.entry.extensions = es;
	    goto out;
	}
	if (es) {
	    free_HDB_extensions(es);
	    free(es);
	}
    }
    ret = context->db->hdb_store(context->context, context->db,
				 HDB_F_REPLACE, &ent);
 out:
    hdb_free_entry (context->context, &ent);
    hdb_free_entry (context->context, &log_ent);
    return ret;
}
Beispiel #5
0
krb5_error_code
hdb_generate_key_set(krb5_context context, krb5_principal principal,
		     Key **ret_key_set, size_t *nkeyset, int no_salt)
{
    char **ktypes, **kp;
    krb5_error_code ret;
    Key *k, *key_set;
    size_t i, j;
    static const char *default_keytypes[] = {
	"aes256-cts-hmac-sha1-96:pw-salt",
	"des3-cbc-sha1:pw-salt",
	"arcfour-hmac-md5:pw-salt",
	NULL
    };

    ktypes = krb5_config_get_strings(context, NULL, "kadmin",
				     "default_keys", NULL);
    if (ktypes == NULL)
	ktypes = (char **)(intptr_t)default_keytypes;

    *ret_key_set = key_set = NULL;
    *nkeyset = 0;

    ret = 0;

    for(kp = ktypes; kp && *kp; kp++) {
	const char *p;
	krb5_salt salt;
	krb5_enctype *enctypes;
	size_t num_enctypes;

	p = *kp;
	/* check alias */
	if(strcmp(p, "v5") == 0)
	    p = "pw-salt";
	else if(strcmp(p, "v4") == 0)
	    p = "des:pw-salt:";
	else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0)
	    p = "des:afs3-salt";
	else if (strcmp(p, "arcfour-hmac-md5") == 0)
	    p = "arcfour-hmac-md5:pw-salt";

	memset(&salt, 0, sizeof(salt));

	ret = parse_key_set(context, p,
			    &enctypes, &num_enctypes, &salt, principal);
	if (ret) {
	    krb5_warn(context, ret, "bad value for default_keys `%s'", *kp);
	    ret = 0;
	    continue;
	}

	for (i = 0; i < num_enctypes; i++) {
	    /* find duplicates */
	    for (j = 0; j < *nkeyset; j++) {

		k = &key_set[j];

		if (k->key.keytype == enctypes[i]) {
		    if (no_salt)
			break;
		    if (k->salt == NULL && salt.salttype == KRB5_PW_SALT)
			break;
		    if (k->salt->type == salt.salttype &&
			k->salt->salt.length == salt.saltvalue.length &&
			memcmp(k->salt->salt.data, salt.saltvalue.data,
			       salt.saltvalue.length) == 0)
			break;
		}
	    }
	    /* not a duplicate, lets add it */
	    if (j == *nkeyset) {
		ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i],
					     no_salt ? NULL : &salt);
		if (ret) {
		    free(enctypes);
		    krb5_free_salt(context, salt);
		    goto out;
		}
	    }
	}
	free(enctypes);
	krb5_free_salt(context, salt);
    }

    *ret_key_set = key_set;

 out:
    if (ktypes != (char **)(intptr_t)default_keytypes)
	krb5_config_free_strings(ktypes);

    if (ret) {
	krb5_warn(context, ret,
		  "failed to parse the [kadmin]default_keys values");

	for (i = 0; i < *nkeyset; i++)
	    free_Key(&key_set[i]);
	free(key_set);
    } else if (*nkeyset == 0) {
	krb5_warnx(context,
		   "failed to parse any of the [kadmin]default_keys values");
	ret = EINVAL; /* XXX */
    }

    return ret;
}
Beispiel #6
0
Datei: log.c Projekt: lha/heimdal
static kadm5_ret_t
kadm5_log_replay_modify (kadm5_server_context *context,
			 uint32_t ver,
			 uint32_t len,
			 krb5_storage *sp)
{
    krb5_error_code ret;
    int32_t mask;
    krb5_data value;
    hdb_entry_ex ent, log_ent;

    memset(&log_ent, 0, sizeof(log_ent));

    krb5_ret_int32 (sp, &mask);
    len -= 4;
    ret = krb5_data_alloc (&value, len);
    if (ret) {
	krb5_set_error_message(context->context, ret, "out of memory");
	return ret;
    }
    krb5_storage_read (sp, value.data, len);
    ret = hdb_value2entry (context->context, &value, &log_ent.entry);
    krb5_data_free(&value);
    if (ret)
	return ret;

    memset(&ent, 0, sizeof(ent));
    ret = context->db->hdb_fetch_kvno(context->context, context->db,
				      log_ent.entry.principal,
				      HDB_F_DECRYPT|HDB_F_ALL_KVNOS|
				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret)
	goto out;
    if (mask & KADM5_PRINC_EXPIRE_TIME) {
	if (log_ent.entry.valid_end == NULL) {
	    ent.entry.valid_end = NULL;
	} else {
	    if (ent.entry.valid_end == NULL) {
		ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
		if (ent.entry.valid_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.valid_end = *log_ent.entry.valid_end;
	}
    }
    if (mask & KADM5_PW_EXPIRATION) {
	if (log_ent.entry.pw_end == NULL) {
	    ent.entry.pw_end = NULL;
	} else {
	    if (ent.entry.pw_end == NULL) {
		ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
		if (ent.entry.pw_end == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.pw_end = *log_ent.entry.pw_end;
	}
    }
    if (mask & KADM5_LAST_PWD_CHANGE) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_ATTRIBUTES) {
	ent.entry.flags = log_ent.entry.flags;
    }
    if (mask & KADM5_MAX_LIFE) {
	if (log_ent.entry.max_life == NULL) {
	    ent.entry.max_life = NULL;
	} else {
	    if (ent.entry.max_life == NULL) {
		ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
		if (ent.entry.max_life == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_life = *log_ent.entry.max_life;
	}
    }
    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
	if (ent.entry.modified_by == NULL) {
	    ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
	    if (ent.entry.modified_by == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	} else
	    free_Event(ent.entry.modified_by);
	ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    goto out;
	}
    }
    if (mask & KADM5_KVNO) {
	ent.entry.kvno = log_ent.entry.kvno;
    }
    if (mask & KADM5_MKVNO) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_AUX_ATTRIBUTES) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_POLICY_CLR) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_MAX_RLIFE) {
	if (log_ent.entry.max_renew == NULL) {
	    ent.entry.max_renew = NULL;
	} else {
	    if (ent.entry.max_renew == NULL) {
		ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
		if (ent.entry.max_renew == NULL) {
		    ret = ENOMEM;
		    krb5_set_error_message(context->context, ret, "out of memory");
		    goto out;
		}
	    }
	    *ent.entry.max_renew = *log_ent.entry.max_renew;
	}
    }
    if (mask & KADM5_LAST_SUCCESS) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_LAST_FAILED) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_FAIL_AUTH_COUNT) {
	abort ();		/* XXX */
    }
    if (mask & KADM5_KEY_DATA) {
	size_t num;
	size_t i;

	/*
	 * We don't need to do anything about key history here because
	 * we always log KADM5_TL_DATA when we change keys/passwords, so
	 * the code below this will handle key history implicitly.
	 * However, if we had to, the code to handle key history here
	 * would look like this:
	 *
	 * HDB_extension *ext;
	 * ...
	 * ext = hdb_find_extension(&log_ent.entry,
	 *                          choice_HDB_extension_data_hist_keys);
	 * if (ext);
	 *    ret = hdb_replace_extension(context->context, &ent.entry, ext);
	 * else
	 *    ret = hdb_clear_extension(context->context, &ent.entry,
	 *                              choice_HDB_extension_data_hist_keys);
	 *
	 * Maybe we should do this here anyways, wasteful as it would
	 * be, as a defensive programming measure?  For now we heim_assert().
	 */
	heim_assert((mask & KADM5_TL_DATA),
		    "Wouldn't log and replay key history");

	for (i = 0; i < ent.entry.keys.len; ++i)
	    free_Key(&ent.entry.keys.val[i]);
	free (ent.entry.keys.val);

	num = log_ent.entry.keys.len;

	ent.entry.keys.len = num;
	ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
	if (ent.entry.keys.val == NULL) {
	    krb5_set_error_message(context->context, ENOMEM, "out of memory");
	    return ENOMEM;
	}
	for (i = 0; i < ent.entry.keys.len; ++i) {
	    ret = copy_Key(&log_ent.entry.keys.val[i],
			   &ent.entry.keys.val[i]);
	    if (ret) {
		krb5_set_error_message(context->context, ret, "out of memory");
		goto out;
	    }
	}
    }
    if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
	HDB_extensions *es = ent.entry.extensions;

	ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
	if (ent.entry.extensions == NULL)
	    goto out;

	ret = copy_HDB_extensions(log_ent.entry.extensions,
				  ent.entry.extensions);
	if (ret) {
	    krb5_set_error_message(context->context, ret, "out of memory");
	    free(ent.entry.extensions);
	    ent.entry.extensions = es;
	    goto out;
	}
	if (es) {
	    free_HDB_extensions(es);
	    free(es);
	}
    }
    ret = context->db->hdb_store(context->context, context->db,
				 HDB_F_REPLACE, &ent);
 out:
    hdb_free_entry (context->context, &ent);
    hdb_free_entry (context->context, &log_ent);
    return ret;
}
Beispiel #7
0
static krb5_error_code
mdb_value2entry(krb5_context context, krb5_data *data, hdb_entry *entry)
{
    krb5_error_code ret;
    krb5_storage *sp;
    uint32_t u32;
    uint16_t u16, num_keys, num_tl;
    size_t i, j;
    char *p = NULL;

    sp = krb5_storage_from_data(data);
    if (sp == NULL) {
	krb5_set_error_message(context, ENOMEM, "out of memory");
	return ENOMEM;
    }
    
    krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);

    /* 16: baselength */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; }
    /* 32: attributes */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    entry->flags.postdate =	 !(u16 & KRB5_KDB_DISALLOW_POSTDATED);
    entry->flags.forwardable =	 !(u16 & KRB5_KDB_DISALLOW_FORWARDABLE);
    entry->flags.initial =	!!(u16 & KRB5_KDB_DISALLOW_TGT_BASED);
    entry->flags.renewable =	 !(u16 & KRB5_KDB_DISALLOW_RENEWABLE);
    entry->flags.proxiable =	 !(u16 & KRB5_KDB_DISALLOW_PROXIABLE);
    /* DUP_SKEY */
    entry->flags.invalid =	!!(u16 & KRB5_KDB_DISALLOW_ALL_TIX);
    entry->flags.require_preauth =!!(u16 & KRB5_KDB_REQUIRES_PRE_AUTH);
    entry->flags.require_hwauth =!!(u16 & KRB5_KDB_REQUIRES_HW_AUTH);
    entry->flags.server =	 !(u16 & KRB5_KDB_DISALLOW_SVR);
    entry->flags.change_pw = 	!!(u16 & KRB5_KDB_PWCHANGE_SERVICE);
    entry->flags.client =	   1; /* XXX */

    /* 32: max time */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
	entry->max_life = malloc(sizeof(*entry->max_life));
	*entry->max_life = u32;
    }
    /* 32: max renewable time */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
	entry->max_renew = malloc(sizeof(*entry->max_renew));
	*entry->max_renew = u32;
    }
    /* 32: client expire */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
	entry->valid_end = malloc(sizeof(*entry->valid_end));
	*entry->valid_end = u32;
    }
    /* 32: passwd expire */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
	entry->pw_end = malloc(sizeof(*entry->pw_end));
	*entry->pw_end = u32;
    }
    /* 32: last successful passwd */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    /* 32: last failed attempt */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    /* 32: num of failed attempts */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    /* 16: num tl data */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    num_tl = u16;
    /* 16: num key data */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    num_keys = u16;
    /* 16: principal length */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    /* length: principal */
    {
	p = malloc(u16 + 1);
	krb5_storage_read(sp, p, u16);
	p[u16] = '\0';
	CHECK(ret = krb5_parse_name(context, p, &entry->principal));
	free(p); p = NULL;
    }
    /* for num tl data times
           16: tl data type
           16: tl data length
           length: length */
    for (i = 0; i < num_tl; i++) {
	CHECK(ret = krb5_ret_uint16(sp, &u16));
	CHECK(ret = krb5_ret_uint16(sp, &u16));
	krb5_storage_seek(sp, u16, SEEK_CUR);
    }
    /* for num key data times
       16: version (num keyblocks)
       16: kvno
       for version times:
           16: type
           16: length
           length: keydata */
    for (i = 0; i < num_keys; i++) {
	int keep = 0;
	uint16_t version;
	void *ptr;

	CHECK(ret = krb5_ret_uint16(sp, &u16));
	version = u16;
	CHECK(ret = krb5_ret_uint16(sp, &u16));

	if (entry->kvno < u16) {
	    keep = 1;
	    entry->kvno = u16;
	    for (j = 0; j < entry->keys.len; j++) {
		free_Key(&entry->keys.val[j]);
		free(entry->keys.val);
		entry->keys.len = 0;
		entry->keys.val = NULL;
	    }
	} else if (entry->kvno == u16)
	    keep = 1;

	if (keep) {
	    Key *k;

	    ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));
	    if (ptr == NULL) {
		ret = ENOMEM;
		goto out;
	    }
	    entry->keys.val = ptr;

	    /* k points to current Key */
	    k = &entry->keys.val[entry->keys.len];

	    memset(k, 0, sizeof(*k));
	    entry->keys.len += 1;

	    entry->keys.val[i].mkvno = malloc(sizeof(*entry->keys.val[i].mkvno));
	    if (entry->keys.val[i].mkvno == NULL) {
		ret = ENOMEM;
		goto out;
	    }
	    *entry->keys.val[i].mkvno = 1;

	    for (j = 0; j < version; j++) {
		uint16_t type;
		CHECK(ret = krb5_ret_uint16(sp, &type));
		CHECK(ret = krb5_ret_uint16(sp, &u16));
		if (j == 0) { /* key */
		    k->key.keytype = type;
		    if (u16 < 2) {
			ret = EINVAL;
			goto out;
		    }
		    krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */
		    k->key.keyvalue.length = u16 - 2;
		    k->key.keyvalue.data = malloc(k->key.keyvalue.length);
		    krb5_storage_read(sp, k->key.keyvalue.data, k->key.keyvalue.length);
		} else if (j == 1) { /* salt */
		    k->salt = calloc(1, sizeof(*k->salt));
		    if (k->salt == NULL) {
			ret = ENOMEM;
			goto out;
		    }
		    k->salt->type = type;
		    if (u16 != 0) {
			k->salt->salt.data = malloc(u16);
			if (k->salt->salt.data == NULL) {
			    ret = ENOMEM;
			    goto out;
			}
			k->salt->salt.length = u16;
			krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
		    }			
		    fix_salt(context, entry, entry->keys.len - 1);
		} else {
		    krb5_storage_seek(sp, u16, SEEK_CUR);
		}
	    }
	} else {
	    /* skip */
	    for (j = 0; j < version; j++) {
		CHECK(ret = krb5_ret_uint16(sp, &u16));
		CHECK(ret = krb5_ret_uint16(sp, &u16));
		krb5_storage_seek(sp, u16, u16);
	    }
	}
    }

    return 0;
 out:
    if (p)
	free(p);
    free_hdb_entry(entry);
    return ret;
}
Beispiel #8
0
static krb5_error_code
mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry)
{
    krb5_error_code ret;
    krb5_storage *sp;
    uint32_t u32;
    uint16_t u16, num_keys, num_tl;
    size_t i, j;
    char *p;

    sp = krb5_storage_from_data(data);
    if (sp == NULL) {
        krb5_set_error_message(context, ENOMEM, "out of memory");
        return ENOMEM;
    }

    krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);

    /*
     * 16: baselength
     *
     * The story here is that these 16 bits have to be a constant:
     * KDB_V1_BASE_LENGTH.  Once upon a time a different value here
     * would have been used to indicate the presence of "extra data"
     * between the "base" contents and the {principal name, TL data,
     * keys} that follow it.  Nothing supports such "extra data"
     * nowadays, so neither do we here.
     *
     * XXX But... surely we ought to log about this extra data, or skip
     * it, or something, in case anyone has MIT KDBs with ancient
     * entries in them...  Logging would allow the admin to know which
     * entries to dump with MIT krb5's kdb5_util.
     */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    if (u16 != KDB_V1_BASE_LENGTH) {
        ret = EINVAL;
        goto out;
    }
    /* 32: attributes */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    entry->flags.postdate =	 !(u32 & KRB5_KDB_DISALLOW_POSTDATED);
    entry->flags.forwardable =	 !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE);
    entry->flags.initial =	!!(u32 & KRB5_KDB_DISALLOW_TGT_BASED);
    entry->flags.renewable =	 !(u32 & KRB5_KDB_DISALLOW_RENEWABLE);
    entry->flags.proxiable =	 !(u32 & KRB5_KDB_DISALLOW_PROXIABLE);
    /* DUP_SKEY */
    entry->flags.invalid =	!!(u32 & KRB5_KDB_DISALLOW_ALL_TIX);
    entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH);
    entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH);
    entry->flags.server =	 !(u32 & KRB5_KDB_DISALLOW_SVR);
    entry->flags.change_pw = 	!!(u32 & KRB5_KDB_PWCHANGE_SERVICE);
    entry->flags.client =	   1; /* XXX */

    /* 32: max time */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
        entry->max_life = malloc(sizeof(*entry->max_life));
        *entry->max_life = u32;
    }
    /* 32: max renewable time */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
        entry->max_renew = malloc(sizeof(*entry->max_renew));
        *entry->max_renew = u32;
    }
    /* 32: client expire */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
        entry->valid_end = malloc(sizeof(*entry->valid_end));
        *entry->valid_end = u32;
    }
    /* 32: passwd expire */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    if (u32) {
        entry->pw_end = malloc(sizeof(*entry->pw_end));
        *entry->pw_end = u32;
    }
    /* 32: last successful passwd */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    /* 32: last failed attempt */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    /* 32: num of failed attempts */
    CHECK(ret = krb5_ret_uint32(sp, &u32));
    /* 16: num tl data */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    num_tl = u16;
    /* 16: num key data */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    num_keys = u16;
    /* 16: principal length */
    CHECK(ret = krb5_ret_uint16(sp, &u16));
    /* length: principal */
    {
        /*
         * Note that the principal name includes the NUL in the entry,
         * but we don't want to take chances, so we add an extra NUL.
         */
        p = malloc(u16 + 1);
        if (p == NULL) {
            ret = ENOMEM;
            goto out;
        }
        krb5_storage_read(sp, p, u16);
        p[u16] = '\0';
        CHECK(ret = krb5_parse_name(context, p, &entry->principal));
        free(p);
    }
    /* for num tl data times
           16: tl data type
           16: tl data length
           length: length */
    for (i = 0; i < num_tl; i++) {
        /* 16: TL data type */
        CHECK(ret = krb5_ret_uint16(sp, &u16));
        /* 16: TL data length */
        CHECK(ret = krb5_ret_uint16(sp, &u16));
        krb5_storage_seek(sp, u16, SEEK_CUR);
    }
    /*
     * for num key data times
     * 16: "version"
     * 16: kvno
     * for version times:
     *     16: type
     *     16: length
     *     length: keydata
     *
     * "version" here is really 1 or 2, the first meaning there's only
     * keys for this kvno, the second meaning there's keys and salt[s?].
     * That's right... hold that gag reflex, you can do it.
     */
    for (i = 0; i < num_keys; i++) {
        int keep = 0;
        uint16_t version;
        void *ptr;

        CHECK(ret = krb5_ret_uint16(sp, &u16));
        version = u16;
        CHECK(ret = krb5_ret_uint16(sp, &u16));

        /*
         * First time through, and until we find one matching key,
         * entry->kvno == 0.
         */
        if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) {
            keep = 1;
            entry->kvno = u16;
            /*
             * Found a higher kvno than earlier, so free the old highest
             * kvno keys.
             *
             * XXX Of course, we actually want to extract the old kvnos
             * as well, for some of the kadm5 APIs.  We shouldn't free
             * these keys, but keep them elsewhere.
             */
            for (j = 0; j < entry->keys.len; j++)
                free_Key(&entry->keys.val[j]);
            free(entry->keys.val);
            entry->keys.len = 0;
            entry->keys.val = NULL;
        } else if (entry->kvno == u16)
            /* Accumulate keys */
            keep = 1;

        if (keep) {
            Key *k;

            ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1));
            if (ptr == NULL) {
                ret = ENOMEM;
                goto out;
            }
            entry->keys.val = ptr;

            /* k points to current Key */
            k = &entry->keys.val[entry->keys.len];

            memset(k, 0, sizeof(*k));
            entry->keys.len += 1;

            k->mkvno = malloc(sizeof(*k->mkvno));
            if (k->mkvno == NULL) {
                ret = ENOMEM;
                goto out;
            }
            *k->mkvno = 1;

            for (j = 0; j < version; j++) {
                uint16_t type;
                CHECK(ret = krb5_ret_uint16(sp, &type));
                CHECK(ret = krb5_ret_uint16(sp, &u16));
                if (j == 0) {
                    /* This "version" means we have a key */
                    k->key.keytype = type;
                    if (u16 < 2) {
                        ret = EINVAL;
                        goto out;
                    }
                    /*
                     * MIT stores keys encrypted keys as {16-bit length
                     * of plaintext key, {encrypted key}}.  The reason
                     * for this is that the Kerberos cryptosystem is not
                     * length-preserving.  Heimdal's approach is to
                     * truncate the plaintext to the expected length of
                     * the key given its enctype, so we ignore this
                     * 16-bit length-of-plaintext-key field.
                     */
                    krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */
                    k->key.keyvalue.length = u16 - 2;   /* adjust cipher len */
                    k->key.keyvalue.data = malloc(k->key.keyvalue.length);
                    krb5_storage_read(sp, k->key.keyvalue.data,
                                      k->key.keyvalue.length);
                } else if (j == 1) {
                    /* This "version" means we have a salt */
                    k->salt = calloc(1, sizeof(*k->salt));
                    if (k->salt == NULL) {
                        ret = ENOMEM;
                        goto out;
                    }
                    k->salt->type = type;
                    if (u16 != 0) {
                        k->salt->salt.data = malloc(u16);
                        if (k->salt->salt.data == NULL) {
                            ret = ENOMEM;
                            goto out;
                        }
                        k->salt->salt.length = u16;
                        krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length);
                    }
                    fix_salt(context, entry, entry->keys.len - 1);
                } else {
                    /*
                     * Whatever this "version" might be, we skip it
                     *
                     * XXX A krb5.conf parameter requesting that we log
                     * about strangeness like this, or return an error
                     * from here, might be nice.
                     */
                    krb5_storage_seek(sp, u16, SEEK_CUR);
                }
            }
        } else {
            /*
             * XXX For now we skip older kvnos, but we should extract
             * them...
             */
            for (j = 0; j < version; j++) {
                /* enctype */
                CHECK(ret = krb5_ret_uint16(sp, &u16));
                /* encrypted key (or plaintext salt) */
                CHECK(ret = krb5_ret_uint16(sp, &u16));
                krb5_storage_seek(sp, u16, SEEK_CUR);
            }
        }
    }

    if (entry->kvno == 0 && kvno != 0) {
        ret = HDB_ERR_NOT_FOUND_HERE;
        goto out;
    }

    return 0;
out:
    if (ret == HEIM_ERR_EOF)
        /* Better error code than "end of file" */
        ret = HEIM_ERR_BAD_HDBENT_ENCODING;
    return ret;
}