155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kadm5_locl.h"
3555682Smarkm
36233294SstasRCSID("$Id$");
3755682Smarkm
38178825Sdfrstatic kadm5_ret_t
39233294Sstasadd_tl_data(kadm5_principal_ent_t ent, int16_t type,
40178825Sdfr	    const void *data, size_t size)
41178825Sdfr{
42178825Sdfr    krb5_tl_data *tl;
43178825Sdfr
44178825Sdfr    tl = calloc(1, sizeof(*tl));
45178825Sdfr    if (tl == NULL)
46178825Sdfr	return _kadm5_error_code(ENOMEM);
47178825Sdfr
48178825Sdfr    tl->tl_data_type = type;
49178825Sdfr    tl->tl_data_length = size;
50178825Sdfr    tl->tl_data_contents = malloc(size);
51233294Sstas    if (tl->tl_data_contents == NULL && size != 0) {
52178825Sdfr	free(tl);
53178825Sdfr	return _kadm5_error_code(ENOMEM);
54178825Sdfr    }
55178825Sdfr    memcpy(tl->tl_data_contents, data, size);
56178825Sdfr
57178825Sdfr    tl->tl_data_next = ent->tl_data;
58178825Sdfr    ent->tl_data = tl;
59178825Sdfr    ent->n_tl_data++;
60178825Sdfr
61178825Sdfr    return 0;
62178825Sdfr}
63178825Sdfr
64233294SstasKRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
65178825Sdfr_krb5_put_int(void *buffer, unsigned long value, size_t size); /* XXX */
66178825Sdfr
6755682Smarkmkadm5_ret_t
68233294Sstaskadm5_s_get_principal(void *server_handle,
69233294Sstas		      krb5_principal princ,
70233294Sstas		      kadm5_principal_ent_t out,
71178825Sdfr		      uint32_t mask)
7255682Smarkm{
7355682Smarkm    kadm5_server_context *context = server_handle;
7455682Smarkm    kadm5_ret_t ret;
75178825Sdfr    hdb_entry_ex ent;
76233294Sstas
77178825Sdfr    memset(&ent, 0, sizeof(ent));
78178825Sdfr    ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0);
7955682Smarkm    if(ret)
8055682Smarkm	return ret;
81233294Sstas    ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
82233294Sstas				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
83178825Sdfr    context->db->hdb_close(context->context, context->db);
8455682Smarkm    if(ret)
8555682Smarkm	return _kadm5_error_code(ret);
8655682Smarkm
8755682Smarkm    memset(out, 0, sizeof(*out));
8855682Smarkm    if(mask & KADM5_PRINCIPAL)
89233294Sstas	ret  = krb5_copy_principal(context->context, ent.entry.principal,
9055682Smarkm				   &out->principal);
9155682Smarkm    if(ret)
9255682Smarkm	goto out;
93178825Sdfr    if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end)
94178825Sdfr	out->princ_expire_time = *ent.entry.valid_end;
95178825Sdfr    if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end)
96178825Sdfr	out->pw_expiration = *ent.entry.pw_end;
9755682Smarkm    if(mask & KADM5_LAST_PWD_CHANGE)
98178825Sdfr	hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change);
9955682Smarkm    if(mask & KADM5_ATTRIBUTES){
100178825Sdfr	out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED;
101178825Sdfr	out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE;
102178825Sdfr	out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0;
103178825Sdfr	out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE;
104178825Sdfr	out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE;
105178825Sdfr	out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0;
106178825Sdfr	out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0;
107178825Sdfr	out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR;
108178825Sdfr	out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0;
109178825Sdfr	out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0;
110178825Sdfr	out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0;
111178825Sdfr	out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0;
112178825Sdfr	out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0;
11355682Smarkm    }
11472445Sassar    if(mask & KADM5_MAX_LIFE) {
115178825Sdfr	if(ent.entry.max_life)
116178825Sdfr	    out->max_life = *ent.entry.max_life;
11772445Sassar	else
11872445Sassar	    out->max_life = INT_MAX;
11972445Sassar    }
12055682Smarkm    if(mask & KADM5_MOD_TIME) {
121178825Sdfr	if(ent.entry.modified_by)
122178825Sdfr	    out->mod_date = ent.entry.modified_by->time;
12355682Smarkm	else
124178825Sdfr	    out->mod_date = ent.entry.created_by.time;
12555682Smarkm    }
12655682Smarkm    if(mask & KADM5_MOD_NAME) {
127178825Sdfr	if(ent.entry.modified_by) {
128178825Sdfr	    if (ent.entry.modified_by->principal != NULL)
129233294Sstas		ret = krb5_copy_principal(context->context,
130178825Sdfr					  ent.entry.modified_by->principal,
13155682Smarkm					  &out->mod_name);
132178825Sdfr	} else if(ent.entry.created_by.principal != NULL)
133233294Sstas	    ret = krb5_copy_principal(context->context,
134178825Sdfr				      ent.entry.created_by.principal,
13555682Smarkm				      &out->mod_name);
13672445Sassar	else
13772445Sassar	    out->mod_name = NULL;
13855682Smarkm    }
13955682Smarkm    if(ret)
14055682Smarkm	goto out;
14155682Smarkm
14255682Smarkm    if(mask & KADM5_KVNO)
143178825Sdfr	out->kvno = ent.entry.kvno;
14455682Smarkm    if(mask & KADM5_MKVNO) {
145233294Sstas	size_t n;
14655682Smarkm	out->mkvno = 0; /* XXX */
147178825Sdfr	for(n = 0; n < ent.entry.keys.len; n++)
148178825Sdfr	    if(ent.entry.keys.val[n].mkvno) {
149178825Sdfr		out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */
15055682Smarkm		break;
15155682Smarkm	    }
15255682Smarkm    }
153233294Sstas#if 0 /* XXX implement */
15455682Smarkm    if(mask & KADM5_AUX_ATTRIBUTES)
155233294Sstas	;
156233294Sstas    if(mask & KADM5_LAST_SUCCESS)
157233294Sstas	;
158233294Sstas    if(mask & KADM5_LAST_FAILED)
159233294Sstas	;
160233294Sstas    if(mask & KADM5_FAIL_AUTH_COUNT)
161233294Sstas	;
162233294Sstas#endif
16355682Smarkm    if(mask & KADM5_POLICY)
16455682Smarkm	out->policy = NULL;
16572445Sassar    if(mask & KADM5_MAX_RLIFE) {
166178825Sdfr	if(ent.entry.max_renew)
167178825Sdfr	    out->max_renewable_life = *ent.entry.max_renew;
16872445Sassar	else
16972445Sassar	    out->max_renewable_life = INT_MAX;
17072445Sassar    }
17155682Smarkm    if(mask & KADM5_KEY_DATA){
172233294Sstas	size_t i;
17355682Smarkm	Key *key;
17455682Smarkm	krb5_key_data *kd;
17555682Smarkm	krb5_salt salt;
17655682Smarkm	krb5_data *sp;
177178825Sdfr	krb5_get_pw_salt(context->context, ent.entry.principal, &salt);
178178825Sdfr	out->key_data = malloc(ent.entry.keys.len * sizeof(*out->key_data));
179233294Sstas	if (out->key_data == NULL && ent.entry.keys.len != 0) {
180178825Sdfr	    ret = ENOMEM;
181178825Sdfr	    goto out;
182178825Sdfr	}
183178825Sdfr	for(i = 0; i < ent.entry.keys.len; i++){
184178825Sdfr	    key = &ent.entry.keys.val[i];
18555682Smarkm	    kd = &out->key_data[i];
18655682Smarkm	    kd->key_data_ver = 2;
187178825Sdfr	    kd->key_data_kvno = ent.entry.kvno;
18855682Smarkm	    kd->key_data_type[0] = key->key.keytype;
18955682Smarkm	    if(key->salt)
19055682Smarkm		kd->key_data_type[1] = key->salt->type;
19155682Smarkm	    else
19272445Sassar		kd->key_data_type[1] = KRB5_PADATA_PW_SALT;
19355682Smarkm	    /* setup key */
19455682Smarkm	    kd->key_data_length[0] = key->key.keyvalue.length;
19555682Smarkm	    kd->key_data_contents[0] = malloc(kd->key_data_length[0]);
196233294Sstas	    if(kd->key_data_contents[0] == NULL && kd->key_data_length[0] != 0){
19755682Smarkm		ret = ENOMEM;
19855682Smarkm		break;
19955682Smarkm	    }
200233294Sstas	    memcpy(kd->key_data_contents[0], key->key.keyvalue.data,
20155682Smarkm		   kd->key_data_length[0]);
20255682Smarkm	    /* setup salt */
20355682Smarkm	    if(key->salt)
20455682Smarkm		sp = &key->salt->salt;
20555682Smarkm	    else
20655682Smarkm		sp = &salt.saltvalue;
20755682Smarkm	    kd->key_data_length[1] = sp->length;
20855682Smarkm	    kd->key_data_contents[1] = malloc(kd->key_data_length[1]);
20955682Smarkm	    if(kd->key_data_length[1] != 0
21055682Smarkm	       && kd->key_data_contents[1] == NULL) {
21155682Smarkm		memset(kd->key_data_contents[0], 0, kd->key_data_length[0]);
21255682Smarkm		ret = ENOMEM;
21355682Smarkm		break;
21455682Smarkm	    }
21555682Smarkm	    memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]);
21655682Smarkm	    out->n_key_data = i + 1;
21755682Smarkm	}
21855682Smarkm	krb5_free_salt(context->context, salt);
21955682Smarkm    }
22055682Smarkm    if(ret){
22155682Smarkm	kadm5_free_principal_ent(context, out);
22255682Smarkm	goto out;
22355682Smarkm    }
224178825Sdfr    if(mask & KADM5_TL_DATA) {
225178825Sdfr	time_t last_pw_expire;
226233294Sstas	const HDB_Ext_PKINIT_acl *acl;
227178825Sdfr	const HDB_Ext_Aliases *aliases;
228178825Sdfr
229178825Sdfr	ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire);
230178825Sdfr	if (ret == 0 && last_pw_expire) {
231178825Sdfr	    unsigned char buf[4];
232178825Sdfr	    _krb5_put_int(buf, last_pw_expire, sizeof(buf));
233178825Sdfr	    ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf));
234178825Sdfr	}
235178825Sdfr	if(ret){
236178825Sdfr	    kadm5_free_principal_ent(context, out);
237178825Sdfr	    goto out;
238178825Sdfr	}
239233294Sstas	/*
240178825Sdfr	 * If the client was allowed to get key data, let it have the
241178825Sdfr	 * password too.
242178825Sdfr	 */
243178825Sdfr	if(mask & KADM5_KEY_DATA) {
244178825Sdfr	    heim_utf8_string pw;
245178825Sdfr
246233294Sstas	    ret = hdb_entry_get_password(context->context,
247178825Sdfr					 context->db, &ent.entry, &pw);
248178825Sdfr	    if (ret == 0) {
249178825Sdfr		ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1);
250178825Sdfr		free(pw);
251178825Sdfr	    }
252233294Sstas	    krb5_clear_error_message(context->context);
253178825Sdfr	}
254178825Sdfr
255233294Sstas	ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl);
256233294Sstas	if (ret == 0 && acl) {
257233294Sstas	    krb5_data buf;
258233294Sstas	    size_t len;
259233294Sstas
260233294Sstas	    ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length,
261233294Sstas				acl, &len, ret);
262233294Sstas	    if (ret) {
263233294Sstas		kadm5_free_principal_ent(context, out);
264233294Sstas		goto out;
265233294Sstas	    }
266233294Sstas	    if (len != buf.length)
267233294Sstas		krb5_abortx(context->context,
268233294Sstas			    "internal ASN.1 encoder error");
269233294Sstas	    ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length);
270233294Sstas	    free(buf.data);
271233294Sstas	    if (ret) {
272233294Sstas		kadm5_free_principal_ent(context, out);
273233294Sstas		goto out;
274233294Sstas	    }
275233294Sstas	}
276233294Sstas	if(ret){
277233294Sstas	    kadm5_free_principal_ent(context, out);
278233294Sstas	    goto out;
279233294Sstas	}
280233294Sstas
281178825Sdfr	ret = hdb_entry_get_aliases(&ent.entry, &aliases);
282178825Sdfr	if (ret == 0 && aliases) {
283178825Sdfr	    krb5_data buf;
284178825Sdfr	    size_t len;
285178825Sdfr
286178825Sdfr	    ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length,
287178825Sdfr			       aliases, &len, ret);
288178825Sdfr	    if (ret) {
289178825Sdfr		kadm5_free_principal_ent(context, out);
290178825Sdfr		goto out;
291178825Sdfr	    }
292178825Sdfr	    if (len != buf.length)
293178825Sdfr		krb5_abortx(context->context,
294178825Sdfr			    "internal ASN.1 encoder error");
295178825Sdfr	    ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length);
296178825Sdfr	    free(buf.data);
297178825Sdfr	    if (ret) {
298178825Sdfr		kadm5_free_principal_ent(context, out);
299178825Sdfr		goto out;
300178825Sdfr	    }
301178825Sdfr	}
302178825Sdfr	if(ret){
303178825Sdfr	    kadm5_free_principal_ent(context, out);
304178825Sdfr	    goto out;
305178825Sdfr	}
306178825Sdfr
307178825Sdfr    }
30855682Smarkmout:
30955682Smarkm    hdb_free_entry(context->context, &ent);
31055682Smarkm
31155682Smarkm    return _kadm5_error_code(ret);
31255682Smarkm}
313