2 * Copyright (c) 2004 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 hdb_entry_check_mandatory(krb5_context context
, const hdb_entry
*ent
)
42 if (ent
->extensions
== NULL
)
46 * check for unknown extensions and if they where tagged mandatory
49 for (i
= 0; i
< ent
->extensions
->len
; i
++) {
50 if (ent
->extensions
->val
[i
].data
.element
!=
51 choice_HDB_extension_data_asn1_ellipsis
)
53 if (ent
->extensions
->val
[i
].mandatory
) {
54 krb5_set_error_message(context
, HDB_ERR_MANDATORY_OPTION
,
55 "Principal have unknown "
56 "mandatory extension");
57 return HDB_ERR_MANDATORY_OPTION
;
64 hdb_find_extension(const hdb_entry
*entry
, int type
)
68 if (entry
->extensions
== NULL
)
71 for (i
= 0; i
< entry
->extensions
->len
; i
++)
72 if (entry
->extensions
->val
[i
].data
.element
== (unsigned)type
)
73 return &entry
->extensions
->val
[i
];
78 * Replace the extension `ext' in `entry'. Make a copy of the
79 * extension, so the caller must still free `ext' on both success and
80 * failure. Returns 0 or error code.
84 hdb_replace_extension(krb5_context context
,
86 const HDB_extension
*ext
)
94 if (entry
->extensions
== NULL
) {
95 entry
->extensions
= calloc(1, sizeof(*entry
->extensions
));
96 if (entry
->extensions
== NULL
) {
97 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
100 } else if (ext
->data
.element
!= choice_HDB_extension_data_asn1_ellipsis
) {
101 ext2
= hdb_find_extension(entry
, ext
->data
.element
);
104 * This is an unknown extension, and we are asked to replace a
105 * possible entry in `entry' that is of the same type. This
106 * might seem impossible, but ASN.1 CHOICE comes to our
107 * rescue. The first tag in each branch in the CHOICE is
108 * unique, so just find the element in the list that have the
109 * same tag was we are putting into the list.
111 Der_class replace_class
, list_class
;
112 Der_type replace_type
, list_type
;
113 unsigned int replace_tag
, list_tag
;
117 ret
= der_get_tag(ext
->data
.u
.asn1_ellipsis
.data
,
118 ext
->data
.u
.asn1_ellipsis
.length
,
119 &replace_class
, &replace_type
, &replace_tag
,
122 krb5_set_error_message(context
, ret
, "hdb: failed to decode "
123 "replacement hdb extension");
127 for (i
= 0; i
< entry
->extensions
->len
; i
++) {
128 HDB_extension
*ext3
= &entry
->extensions
->val
[i
];
130 if (ext3
->data
.element
!= choice_HDB_extension_data_asn1_ellipsis
)
133 ret
= der_get_tag(ext3
->data
.u
.asn1_ellipsis
.data
,
134 ext3
->data
.u
.asn1_ellipsis
.length
,
135 &list_class
, &list_type
, &list_tag
,
138 krb5_set_error_message(context
, ret
, "hdb: failed to decode "
139 "present hdb extension");
143 if (MAKE_TAG(replace_class
,replace_type
,replace_type
) ==
144 MAKE_TAG(list_class
,list_type
,list_type
)) {
152 free_HDB_extension(ext2
);
153 ret
= copy_HDB_extension(ext
, ext2
);
155 krb5_set_error_message(context
, ret
, "hdb: failed to copy replacement "
160 es
= realloc(entry
->extensions
->val
,
161 (entry
->extensions
->len
+1)*sizeof(entry
->extensions
->val
[0]));
163 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
166 entry
->extensions
->val
= es
;
168 ret
= copy_HDB_extension(ext
,
169 &entry
->extensions
->val
[entry
->extensions
->len
]);
171 entry
->extensions
->len
++;
173 krb5_set_error_message(context
, ret
, "hdb: failed to copy new extension");
179 hdb_clear_extension(krb5_context context
,
185 if (entry
->extensions
== NULL
)
188 for (i
= 0; i
< entry
->extensions
->len
; i
++) {
189 if (entry
->extensions
->val
[i
].data
.element
== (unsigned)type
) {
190 free_HDB_extension(&entry
->extensions
->val
[i
]);
191 memmove(&entry
->extensions
->val
[i
],
192 &entry
->extensions
->val
[i
+ 1],
193 sizeof(entry
->extensions
->val
[i
]) * (entry
->extensions
->len
- i
- 1));
194 entry
->extensions
->len
--;
197 if (entry
->extensions
->len
== 0) {
198 free(entry
->extensions
->val
);
199 free(entry
->extensions
);
200 entry
->extensions
= NULL
;
208 hdb_entry_get_pkinit_acl(const hdb_entry
*entry
, const HDB_Ext_PKINIT_acl
**a
)
210 const HDB_extension
*ext
;
212 ext
= hdb_find_extension(entry
, choice_HDB_extension_data_pkinit_acl
);
214 *a
= &ext
->data
.u
.pkinit_acl
;
222 hdb_entry_get_pkinit_hash(const hdb_entry
*entry
, const HDB_Ext_PKINIT_hash
**a
)
224 const HDB_extension
*ext
;
226 ext
= hdb_find_extension(entry
, choice_HDB_extension_data_pkinit_cert_hash
);
228 *a
= &ext
->data
.u
.pkinit_cert_hash
;
236 hdb_entry_get_pkinit_cert(const hdb_entry
*entry
, const HDB_Ext_PKINIT_cert
**a
)
238 const HDB_extension
*ext
;
240 ext
= hdb_find_extension(entry
, choice_HDB_extension_data_pkinit_cert
);
242 *a
= &ext
->data
.u
.pkinit_cert
;
250 hdb_entry_get_pw_change_time(const hdb_entry
*entry
, time_t *t
)
252 const HDB_extension
*ext
;
254 ext
= hdb_find_extension(entry
, choice_HDB_extension_data_last_pw_change
);
256 *t
= ext
->data
.u
.last_pw_change
;
264 hdb_entry_set_pw_change_time(krb5_context context
,
270 ext
.mandatory
= FALSE
;
271 ext
.data
.element
= choice_HDB_extension_data_last_pw_change
;
274 ext
.data
.u
.last_pw_change
= t
;
276 return hdb_replace_extension(context
, entry
, &ext
);
280 hdb_entry_get_password(krb5_context context
, HDB
*db
,
281 const hdb_entry
*entry
, char **p
)
287 ext
= hdb_find_extension(entry
, choice_HDB_extension_data_password
);
289 heim_utf8_string xstr
;
290 heim_octet_string pw
;
292 if (db
->hdb_master_key_set
&& ext
->data
.u
.password
.mkvno
) {
295 key
= _hdb_find_master_key(ext
->data
.u
.password
.mkvno
,
299 krb5_set_error_message(context
, HDB_ERR_NO_MKEY
,
300 "master key %d missing",
301 *ext
->data
.u
.password
.mkvno
);
302 return HDB_ERR_NO_MKEY
;
305 ret
= _hdb_mkey_decrypt(context
, key
, HDB_KU_MKEY
,
306 ext
->data
.u
.password
.password
.data
,
307 ext
->data
.u
.password
.password
.length
,
310 ret
= der_copy_octet_string(&ext
->data
.u
.password
.password
, &pw
);
313 krb5_clear_error_message(context
);
318 if (xstr
[pw
.length
- 1] != '\0') {
319 krb5_set_error_message(context
, EINVAL
, "malformed password");
325 der_free_octet_string(&pw
);
327 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
333 ret
= krb5_unparse_name(context
, entry
->principal
, &str
);
335 krb5_set_error_message(context
, ENOENT
,
336 "no password attribute for %s", str
);
339 krb5_clear_error_message(context
);
345 hdb_entry_set_password(krb5_context context
, HDB
*db
,
346 hdb_entry
*entry
, const char *p
)
352 ext
.mandatory
= FALSE
;
353 ext
.data
.element
= choice_HDB_extension_data_password
;
355 if (db
->hdb_master_key_set
) {
357 key
= _hdb_find_master_key(NULL
, db
->hdb_master_key
);
359 krb5_set_error_message(context
, HDB_ERR_NO_MKEY
,
360 "hdb_entry_set_password: "
361 "failed to find masterkey");
362 return HDB_ERR_NO_MKEY
;
365 ret
= _hdb_mkey_encrypt(context
, key
, HDB_KU_MKEY
,
367 &ext
.data
.u
.password
.password
);
371 ext
.data
.u
.password
.mkvno
=
372 malloc(sizeof(*ext
.data
.u
.password
.mkvno
));
373 if (ext
.data
.u
.password
.mkvno
== NULL
) {
374 free_HDB_extension(&ext
);
375 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
378 *ext
.data
.u
.password
.mkvno
= _hdb_mkey_version(key
);
381 ext
.data
.u
.password
.mkvno
= NULL
;
383 ret
= krb5_data_copy(&ext
.data
.u
.password
.password
,
386 krb5_set_error_message(context
, ret
, "malloc: out of memory");
387 free_HDB_extension(&ext
);
392 ret
= hdb_replace_extension(context
, entry
, &ext
);
394 free_HDB_extension(&ext
);
400 hdb_entry_clear_password(krb5_context context
, hdb_entry
*entry
)
402 return hdb_clear_extension(context
, entry
,
403 choice_HDB_extension_data_password
);
407 hdb_entry_get_ConstrainedDelegACL(const hdb_entry
*entry
,
408 const HDB_Ext_Constrained_delegation_acl
**a
)
410 const HDB_extension
*ext
;
412 ext
= hdb_find_extension(entry
,
413 choice_HDB_extension_data_allowed_to_delegate_to
);
415 *a
= &ext
->data
.u
.allowed_to_delegate_to
;
423 hdb_entry_get_aliases(const hdb_entry
*entry
, const HDB_Ext_Aliases
**a
)
425 const HDB_extension
*ext
;
427 ext
= hdb_find_extension(entry
, choice_HDB_extension_data_aliases
);
429 *a
= &ext
->data
.u
.aliases
;
437 hdb_entry_get_kvno_diff_clnt(const hdb_entry
*entry
)
439 const HDB_extension
*ext
;
441 ext
= hdb_find_extension(entry
,
442 choice_HDB_extension_data_hist_kvno_diff_clnt
);
444 return ext
->data
.u
.hist_kvno_diff_clnt
;
449 hdb_entry_set_kvno_diff_clnt(krb5_context context
, hdb_entry
*entry
,
456 ext
.mandatory
= FALSE
;
457 ext
.data
.element
= choice_HDB_extension_data_hist_kvno_diff_clnt
;
458 ext
.data
.u
.hist_kvno_diff_clnt
= diff
;
459 return hdb_replace_extension(context
, entry
, &ext
);
463 hdb_entry_clear_kvno_diff_clnt(krb5_context context
, hdb_entry
*entry
)
465 return hdb_clear_extension(context
, entry
,
466 choice_HDB_extension_data_hist_kvno_diff_clnt
);
470 hdb_entry_get_kvno_diff_svc(const hdb_entry
*entry
)
472 const HDB_extension
*ext
;
474 ext
= hdb_find_extension(entry
,
475 choice_HDB_extension_data_hist_kvno_diff_svc
);
477 return ext
->data
.u
.hist_kvno_diff_svc
;
478 return 1024; /* max_life effectively provides a better default */
482 hdb_entry_set_kvno_diff_svc(krb5_context context
, hdb_entry
*entry
,
489 ext
.mandatory
= FALSE
;
490 ext
.data
.element
= choice_HDB_extension_data_hist_kvno_diff_svc
;
491 ext
.data
.u
.hist_kvno_diff_svc
= diff
;
492 return hdb_replace_extension(context
, entry
, &ext
);
496 hdb_entry_clear_kvno_diff_svc(krb5_context context
, hdb_entry
*entry
)
498 return hdb_clear_extension(context
, entry
,
499 choice_HDB_extension_data_hist_kvno_diff_svc
);
503 hdb_set_last_modified_by(krb5_context context
, hdb_entry
*entry
,
504 krb5_principal modby
, time_t modtime
)
510 old_ev
= entry
->modified_by
;
512 ev
= calloc(1, sizeof (*ev
));
516 ret
= krb5_copy_principal(context
, modby
, &ev
->principal
);
518 ret
= krb5_parse_name(context
, "root/admin", &ev
->principal
);
527 entry
->modified_by
= ev
;