2 * Copyright (c) 1997-2002 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
34 #include "krb5_locl.h"
38 hdb_principal2key(krb5_context context
, krb5_const_principal p
, krb5_data
*key
)
44 ret
= copy_Principal(p
, &new);
47 new.name
.name_type
= 0;
49 ASN1_MALLOC_ENCODE(Principal
, key
->data
, key
->length
, &new, &len
, ret
);
50 if (ret
== 0 && key
->length
!= len
)
51 krb5_abortx(context
, "internal asn.1 encoder error");
57 hdb_key2principal(krb5_context context
, krb5_data
*key
, krb5_principal p
)
59 return decode_Principal(key
->data
, key
->length
, p
, NULL
);
63 hdb_entry2value(krb5_context context
, const hdb_entry
*ent
, krb5_data
*value
)
68 ASN1_MALLOC_ENCODE(hdb_entry
, value
->data
, value
->length
, ent
, &len
, ret
);
69 if (ret
== 0 && value
->length
!= len
)
70 krb5_abortx(context
, "internal asn.1 encoder error");
75 hdb_value2entry(krb5_context context
, krb5_data
*value
, hdb_entry
*ent
)
77 return decode_hdb_entry(value
->data
, value
->length
, ent
, NULL
);
81 hdb_entry_alias2value(krb5_context context
,
82 const hdb_entry_alias
*alias
,
88 ASN1_MALLOC_ENCODE(hdb_entry_alias
, value
->data
, value
->length
,
90 if (ret
== 0 && value
->length
!= len
)
91 krb5_abortx(context
, "internal asn.1 encoder error");
96 hdb_value2entry_alias(krb5_context context
, krb5_data
*value
,
99 return decode_hdb_entry_alias(value
->data
, value
->length
, ent
, NULL
);
103 * Some old databases may not have stored the salt with each key, which will
104 * break clients when aliases or canonicalization are used. Generate a
105 * default salt based on the real principal name in the entry to handle
108 static krb5_error_code
109 add_default_salts(krb5_context context
, HDB
*db
, hdb_entry
*entry
)
115 ret
= krb5_get_pw_salt(context
, entry
->principal
, &pwsalt
);
119 for (i
= 0; i
< entry
->keys
.len
; i
++) {
120 Key
*key
= &entry
->keys
.val
[i
];
122 if (key
->salt
!= NULL
||
123 _krb5_enctype_requires_random_salt(context
, key
->key
.keytype
))
126 key
->salt
= calloc(1, sizeof(*key
->salt
));
127 if (key
->salt
== NULL
) {
128 ret
= krb5_enomem(context
);
132 key
->salt
->type
= KRB5_PADATA_PW_SALT
;
134 ret
= krb5_data_copy(&key
->salt
->salt
,
135 pwsalt
.saltvalue
.data
,
136 pwsalt
.saltvalue
.length
);
141 krb5_free_salt(context
, pwsalt
);
147 _hdb_fetch_kvno(krb5_context context
, HDB
*db
, krb5_const_principal principal
,
148 unsigned flags
, krb5_kvno kvno
, hdb_entry_ex
*entry
)
150 krb5_principal enterprise_principal
= NULL
;
151 krb5_data key
, value
;
154 if (principal
->name
.name_type
== KRB5_NT_ENTERPRISE_PRINCIPAL
) {
155 if (principal
->name
.name_string
.len
!= 1) {
156 ret
= KRB5_PARSE_MALFORMED
;
157 krb5_set_error_message(context
, ret
, "malformed principal: "
158 "enterprise name with %d name components",
159 principal
->name
.name_string
.len
);
162 ret
= krb5_parse_name(context
, principal
->name
.name_string
.val
[0],
163 &enterprise_principal
);
166 principal
= enterprise_principal
;
169 hdb_principal2key(context
, principal
, &key
);
170 if (enterprise_principal
)
171 krb5_free_principal(context
, enterprise_principal
);
172 ret
= db
->hdb__get(context
, db
, key
, &value
);
173 krb5_data_free(&key
);
176 ret
= hdb_value2entry(context
, &value
, &entry
->entry
);
177 /* HDB_F_GET_ANY indicates request originated from KDC (not kadmin) */
178 if (ret
== ASN1_BAD_ID
&& (flags
& (HDB_F_CANON
|HDB_F_GET_ANY
)) == 0) {
179 krb5_data_free(&value
);
180 return HDB_ERR_NOENTRY
;
181 } else if (ret
== ASN1_BAD_ID
) {
182 hdb_entry_alias alias
;
184 ret
= hdb_value2entry_alias(context
, &value
, &alias
);
186 krb5_data_free(&value
);
189 hdb_principal2key(context
, alias
.principal
, &key
);
190 krb5_data_free(&value
);
191 free_hdb_entry_alias(&alias
);
193 ret
= db
->hdb__get(context
, db
, key
, &value
);
194 krb5_data_free(&key
);
197 ret
= hdb_value2entry(context
, &value
, &entry
->entry
);
199 krb5_data_free(&value
);
203 krb5_data_free(&value
);
204 if ((flags
& HDB_F_DECRYPT
) && (flags
& HDB_F_ALL_KVNOS
)) {
205 /* Decrypt the current keys */
206 ret
= hdb_unseal_keys(context
, db
, &entry
->entry
);
208 hdb_free_entry(context
, entry
);
211 /* Decrypt the key history too */
212 ret
= hdb_unseal_keys_kvno(context
, db
, 0, flags
, &entry
->entry
);
214 hdb_free_entry(context
, entry
);
217 } else if ((flags
& HDB_F_DECRYPT
)) {
218 if ((flags
& HDB_F_KVNO_SPECIFIED
) == 0 || kvno
== entry
->entry
.kvno
) {
219 /* Decrypt the current keys */
220 ret
= hdb_unseal_keys(context
, db
, &entry
->entry
);
222 hdb_free_entry(context
, entry
);
226 if ((flags
& HDB_F_ALL_KVNOS
))
229 * Find and decrypt the keys from the history that we want,
230 * and swap them with the current keys
232 ret
= hdb_unseal_keys_kvno(context
, db
, kvno
, flags
, &entry
->entry
);
234 hdb_free_entry(context
, entry
);
239 if ((flags
& HDB_F_FOR_AS_REQ
) && (flags
& HDB_F_GET_CLIENT
)) {
241 * Generate default salt for any principals missing one; note such
242 * principals could include those for which a random (non-password)
243 * key was generated, but given the salt will be ignored by a keytab
244 * client it doesn't hurt to include the default salt.
246 ret
= add_default_salts(context
, db
, &entry
->entry
);
248 hdb_free_entry(context
, entry
);
252 if (enterprise_principal
) {
254 * Whilst Windows does not canonicalize enterprise principal names if
255 * the canonicalize flag is unset, the original specification in
256 * draft-ietf-krb-wg-kerberos-referrals-03.txt says we should.
258 entry
->entry
.flags
.force_canonicalize
= 1;
264 static krb5_error_code
265 hdb_remove_aliases(krb5_context context
, HDB
*db
, krb5_data
*key
)
267 const HDB_Ext_Aliases
*aliases
;
268 krb5_error_code code
;
273 code
= db
->hdb__get(context
, db
, *key
, &value
);
274 if (code
== HDB_ERR_NOENTRY
)
279 code
= hdb_value2entry(context
, &value
, &oldentry
);
280 krb5_data_free(&value
);
284 code
= hdb_entry_get_aliases(&oldentry
, &aliases
);
285 if (code
|| aliases
== NULL
) {
286 free_hdb_entry(&oldentry
);
289 for (i
= 0; i
< aliases
->aliases
.len
; i
++) {
292 code
= hdb_principal2key(context
, &aliases
->aliases
.val
[i
], &akey
);
294 code
= db
->hdb__del(context
, db
, akey
);
295 krb5_data_free(&akey
);
298 free_hdb_entry(&oldentry
);
302 free_hdb_entry(&oldentry
);
306 static krb5_error_code
307 hdb_add_aliases(krb5_context context
, HDB
*db
,
308 unsigned flags
, hdb_entry_ex
*entry
)
310 const HDB_Ext_Aliases
*aliases
;
311 krb5_error_code code
;
312 krb5_data key
, value
;
315 code
= hdb_entry_get_aliases(&entry
->entry
, &aliases
);
316 if (code
|| aliases
== NULL
)
319 for (i
= 0; i
< aliases
->aliases
.len
; i
++) {
320 hdb_entry_alias entryalias
;
321 entryalias
.principal
= entry
->entry
.principal
;
323 code
= hdb_entry_alias2value(context
, &entryalias
, &value
);
327 code
= hdb_principal2key(context
, &aliases
->aliases
.val
[i
], &key
);
329 code
= db
->hdb__put(context
, db
, flags
, key
, value
);
330 krb5_data_free(&key
);
332 krb5_data_free(&value
);
339 static krb5_error_code
340 hdb_check_aliases(krb5_context context
, HDB
*db
, hdb_entry_ex
*entry
)
342 const HDB_Ext_Aliases
*aliases
;
346 /* check if new aliases already is used */
348 code
= hdb_entry_get_aliases(&entry
->entry
, &aliases
);
352 for (i
= 0; aliases
&& i
< aliases
->aliases
.len
; i
++) {
353 hdb_entry_alias alias
;
354 krb5_data akey
, value
;
356 code
= hdb_principal2key(context
, &aliases
->aliases
.val
[i
], &akey
);
358 code
= db
->hdb__get(context
, db
, akey
, &value
);
359 krb5_data_free(&akey
);
361 if (code
== HDB_ERR_NOENTRY
)
366 code
= hdb_value2entry_alias(context
, &value
, &alias
);
367 krb5_data_free(&value
);
369 if (code
== ASN1_BAD_ID
)
370 return HDB_ERR_EXISTS
;
374 code
= krb5_principal_compare(context
, alias
.principal
,
375 entry
->entry
.principal
);
376 free_hdb_entry_alias(&alias
);
378 return HDB_ERR_EXISTS
;
384 _hdb_store(krb5_context context
, HDB
*db
, unsigned flags
, hdb_entry_ex
*entry
)
386 krb5_data key
, value
;
389 if (entry
->entry
.flags
.do_not_store
||
390 entry
->entry
.flags
.force_canonicalize
)
391 return HDB_ERR_MISUSE
;
392 /* check if new aliases already is used */
393 code
= hdb_check_aliases(context
, db
, entry
);
397 if ((flags
& HDB_F_PRECHECK
) && (flags
& HDB_F_REPLACE
))
400 if ((flags
& HDB_F_PRECHECK
)) {
401 code
= hdb_principal2key(context
, entry
->entry
.principal
, &key
);
404 code
= db
->hdb__get(context
, db
, key
, &value
);
405 krb5_data_free(&key
);
407 krb5_data_free(&value
);
408 if (code
== HDB_ERR_NOENTRY
)
410 return code
? code
: HDB_ERR_EXISTS
;
413 if(entry
->entry
.generation
== NULL
) {
415 entry
->entry
.generation
= malloc(sizeof(*entry
->entry
.generation
));
416 if(entry
->entry
.generation
== NULL
) {
417 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
420 gettimeofday(&t
, NULL
);
421 entry
->entry
.generation
->time
= t
.tv_sec
;
422 entry
->entry
.generation
->usec
= t
.tv_usec
;
423 entry
->entry
.generation
->gen
= 0;
425 entry
->entry
.generation
->gen
++;
427 code
= hdb_seal_keys(context
, db
, &entry
->entry
);
431 hdb_principal2key(context
, entry
->entry
.principal
, &key
);
434 code
= hdb_remove_aliases(context
, db
, &key
);
436 krb5_data_free(&key
);
439 hdb_entry2value(context
, &entry
->entry
, &value
);
440 code
= db
->hdb__put(context
, db
, flags
& HDB_F_REPLACE
, key
, value
);
441 krb5_data_free(&value
);
442 krb5_data_free(&key
);
446 code
= hdb_add_aliases(context
, db
, flags
, entry
);
452 _hdb_remove(krb5_context context
, HDB
*db
,
453 unsigned flags
, krb5_const_principal principal
)
455 krb5_data key
, value
;
458 hdb_principal2key(context
, principal
, &key
);
460 if ((flags
& HDB_F_PRECHECK
)) {
462 * We don't check that we can delete the aliases because we
463 * assume that the DB is consistent. If we did check for alias
464 * consistency we'd also have to provide a way to fsck the DB,
465 * otherwise admins would have no way to recover -- papering
466 * over this here is less work, but we really ought to provide
469 code
= db
->hdb__get(context
, db
, key
, &value
);
470 krb5_data_free(&key
);
472 krb5_data_free(&value
);
478 code
= hdb_remove_aliases(context
, db
, &key
);
480 krb5_data_free(&key
);
483 code
= db
->hdb__del(context
, db
, key
);
484 krb5_data_free(&key
);