Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
static int
ka_convert(struct prop_data *pd, int fd, struct ka_entry *ent)
{
    int32_t flags = ntohl(ent->flags);
    krb5_error_code ret;
    hdb_entry_ex hdb;

    if(!kaspecials_flag
       && (flags & KAFNORMAL) == 0) /* remove special entries */
	return 0;
    memset(&hdb, 0, sizeof(hdb));
    ret = krb5_425_conv_principal(pd->context, ent->name, ent->instance, 
				  v4_realm, &hdb.entry.principal);
    if(ret) {
	krb5_warn(pd->context, ret,
		  "krb5_425_conv_principal (%s.%s@%s)",
		  ent->name, ent->instance, v4_realm);
	return 0;
    }
    hdb.entry.kvno = ntohl(ent->kvno);
    hdb.entry.keys.len = 3;
    hdb.entry.keys.val = 
	malloc(hdb.entry.keys.len * sizeof(*hdb.entry.keys.val));
    if (hdb.entry.keys.val == NULL)
	krb5_errx(pd->context, ENOMEM, "malloc");
    hdb.entry.keys.val[0].mkvno = NULL;
    hdb.entry.keys.val[0].salt = calloc(1, sizeof(*hdb.entry.keys.val[0].salt));
    if (hdb.entry.keys.val[0].salt == NULL)
	krb5_errx(pd->context, ENOMEM, "calloc");
    if (ka_use_null_salt) {
	hdb.entry.keys.val[0].salt->type = hdb_pw_salt;
	hdb.entry.keys.val[0].salt->salt.data = NULL;
	hdb.entry.keys.val[0].salt->salt.length = 0;
    } else {
	hdb.entry.keys.val[0].salt->type = hdb_afs3_salt;
	hdb.entry.keys.val[0].salt->salt.data = strdup(afs_cell);
	if (hdb.entry.keys.val[0].salt->salt.data == NULL)
	    krb5_errx(pd->context, ENOMEM, "strdup");
	hdb.entry.keys.val[0].salt->salt.length = strlen(afs_cell);
    }
    
    hdb.entry.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5;
    krb5_data_copy(&hdb.entry.keys.val[0].key.keyvalue,
		   ent->key,
		   sizeof(ent->key));
    copy_Key(&hdb.entry.keys.val[0], &hdb.entry.keys.val[1]);
    hdb.entry.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4;
    copy_Key(&hdb.entry.keys.val[0], &hdb.entry.keys.val[2]);
    hdb.entry.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC;

    ALLOC(hdb.entry.max_life);
    *hdb.entry.max_life = ntohl(ent->max_life);

    if(ntohl(ent->valid_end) != NEVERDATE && ntohl(ent->valid_end) != 0xffffffff) {
	ALLOC(hdb.entry.valid_end);
	*hdb.entry.valid_end = ntohl(ent->valid_end);
    }
    
    if (ntohl(ent->pw_change) != NEVERDATE && 
	ent->pw_expire != 255 &&
	ent->pw_expire != 0) {
	ALLOC(hdb.entry.pw_end);
	*hdb.entry.pw_end = ntohl(ent->pw_change)
	    + 24 * 60 * 60 * ent->pw_expire;
    }

    ret = krb5_make_principal(pd->context, &hdb.entry.created_by.principal,
			      v4_realm,
			      "kadmin",
			      "hprop",
			      NULL);
    hdb.entry.created_by.time = time(NULL);

    if(ent->mod_ptr){
	struct ka_entry mod;
	ALLOC(hdb.entry.modified_by);
	read_block(pd->context, fd, ntohl(ent->mod_ptr), &mod, sizeof(mod));
	
	krb5_425_conv_principal(pd->context, mod.name, mod.instance, v4_realm, 
				&hdb.entry.modified_by->principal);
	hdb.entry.modified_by->time = ntohl(ent->mod_time);
	memset(&mod, 0, sizeof(mod));
    }

    hdb.entry.flags.forwardable = 1;
    hdb.entry.flags.renewable = 1;
    hdb.entry.flags.proxiable = 1;
    hdb.entry.flags.postdate = 1;
    /* XXX - AFS 3.4a creates krbtgt.REALMOFCELL as NOTGS+NOSEAL */
    if (strcmp(ent->name, "krbtgt") == 0 &&
	(flags & (KAFNOTGS|KAFNOSEAL)) == (KAFNOTGS|KAFNOSEAL))
	flags &= ~(KAFNOTGS|KAFNOSEAL);

    hdb.entry.flags.client = (flags & KAFNOTGS) == 0;
    hdb.entry.flags.server = (flags & KAFNOSEAL) == 0;

    ret = v5_prop(pd->context, NULL, &hdb, pd);
    hdb_free_entry(pd->context, &hdb);
    return ret;
}
Ejemplo n.º 4
0
Archivo: log.c Proyecto: 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;
}
Ejemplo n.º 5
0
int
v4_prop(void *arg, struct v4_principal *p)
{
    struct prop_data *pd = arg;
    hdb_entry_ex ent;
    krb5_error_code ret;

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

    ret = krb5_425_conv_principal(pd->context, p->name, p->instance, v4_realm,
				  &ent.entry.principal);
    if(ret) {
	krb5_warn(pd->context, ret,
		  "krb5_425_conv_principal %s.%s@%s",
		  p->name, p->instance, v4_realm);
	return 0;
    }

    if(verbose_flag) {
	char *s;
	krb5_unparse_name_short(pd->context, ent.entry.principal, &s);
	krb5_warnx(pd->context, "%s.%s -> %s", p->name, p->instance, s);
	free(s);
    }

    ent.entry.kvno = p->kvno;
    ent.entry.keys.len = 3;
    ent.entry.keys.val = malloc(ent.entry.keys.len * sizeof(*ent.entry.keys.val));
    if (ent.entry.keys.val == NULL)
	krb5_errx(pd->context, ENOMEM, "malloc");
    if(p->mkvno != -1) {
	ent.entry.keys.val[0].mkvno = malloc (sizeof(*ent.entry.keys.val[0].mkvno));
	if (ent.entry.keys.val[0].mkvno == NULL)
	    krb5_errx(pd->context, ENOMEM, "malloc");
	*(ent.entry.keys.val[0].mkvno) = p->mkvno;
    } else
	ent.entry.keys.val[0].mkvno = NULL;
    ent.entry.keys.val[0].salt = calloc(1, sizeof(*ent.entry.keys.val[0].salt));
    if (ent.entry.keys.val[0].salt == NULL)
	krb5_errx(pd->context, ENOMEM, "calloc");
    ent.entry.keys.val[0].salt->type = KRB5_PADATA_PW_SALT;
    ent.entry.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5;
    krb5_data_alloc(&ent.entry.keys.val[0].key.keyvalue, DES_KEY_SZ);
    memcpy(ent.entry.keys.val[0].key.keyvalue.data, p->key, 8);

    copy_Key(&ent.entry.keys.val[0], &ent.entry.keys.val[1]);
    ent.entry.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4;
    copy_Key(&ent.entry.keys.val[0], &ent.entry.keys.val[2]);
    ent.entry.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC;

    {
	int life = _krb5_krb_life_to_time(0, p->max_life);
	if(life == NEVERDATE){
	    ent.entry.max_life = NULL;
	} else {
	    /* clean up lifetime a bit */
	    if(life > 86400)
		life = (life + 86399) / 86400 * 86400;
	    else if(life > 3600)
		life = (life + 3599) / 3600 * 3600;
	    ALLOC(ent.entry.max_life);
	    *ent.entry.max_life = life;
	}
    }

    ALLOC(ent.entry.valid_end);
    *ent.entry.valid_end = p->exp_date;

    ret = krb5_make_principal(pd->context, &ent.entry.created_by.principal,
			      v4_realm,
			      "kadmin",
			      "hprop",
			      NULL);
    if(ret){
	krb5_warn(pd->context, ret, "krb5_make_principal");
	ret = 0;
	goto out;
    }
    ent.entry.created_by.time = time(NULL);
    ALLOC(ent.entry.modified_by);
    ret = krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance, 
				  v4_realm, &ent.entry.modified_by->principal);
    if(ret){
	krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, v4_realm);
	ent.entry.modified_by->principal = NULL;
	ret = 0;
	goto out;
    }
    ent.entry.modified_by->time = p->mod_date;

    ent.entry.flags.forwardable = 1;
    ent.entry.flags.renewable = 1;
    ent.entry.flags.proxiable = 1;
    ent.entry.flags.postdate = 1;
    ent.entry.flags.client = 1;
    ent.entry.flags.server = 1;
    
    /* special case password changing service */
    if(strcmp(p->name, "changepw") == 0 && 
       strcmp(p->instance, "kerberos") == 0) {
	ent.entry.flags.forwardable = 0;
	ent.entry.flags.renewable = 0;
	ent.entry.flags.proxiable = 0;
	ent.entry.flags.postdate = 0;
	ent.entry.flags.initial = 1;
	ent.entry.flags.change_pw = 1;
    }

    ret = v5_prop(pd->context, NULL, &ent, pd);

    if (strcmp (p->name, "krbtgt") == 0
	&& strcmp (v4_realm, p->instance) != 0) {
	krb5_free_principal (pd->context, ent.entry.principal);
	ret = krb5_425_conv_principal (pd->context, p->name,
				       v4_realm, p->instance,
				       &ent.entry.principal);
	if (ret == 0)
	    ret = v5_prop (pd->context, NULL, &ent, pd);
    }

  out:
    hdb_free_entry(pd->context, &ent);
    return ret;
}