1 /* $NetBSD: common.c,v 1.2 2017/01/28 21:31:48 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "hdb_locl.h"
37
38 int
hdb_principal2key(krb5_context context,krb5_const_principal p,krb5_data * key)39 hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key)
40 {
41 Principal new;
42 size_t len = 0;
43 int ret;
44
45 ret = copy_Principal(p, &new);
46 if(ret)
47 return ret;
48 new.name.name_type = 0;
49
50 ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret);
51 if (ret == 0 && key->length != len)
52 krb5_abortx(context, "internal asn.1 encoder error");
53 free_Principal(&new);
54 return ret;
55 }
56
57 int
hdb_key2principal(krb5_context context,krb5_data * key,krb5_principal p)58 hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p)
59 {
60 return decode_Principal(key->data, key->length, p, NULL);
61 }
62
63 int
hdb_entry2value(krb5_context context,const hdb_entry * ent,krb5_data * value)64 hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value)
65 {
66 size_t len = 0;
67 int ret;
68
69 ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret);
70 if (ret == 0 && value->length != len)
71 krb5_abortx(context, "internal asn.1 encoder error");
72 return ret;
73 }
74
75 int
hdb_value2entry(krb5_context context,krb5_data * value,hdb_entry * ent)76 hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent)
77 {
78 return decode_hdb_entry(value->data, value->length, ent, NULL);
79 }
80
81 int
hdb_entry_alias2value(krb5_context context,const hdb_entry_alias * alias,krb5_data * value)82 hdb_entry_alias2value(krb5_context context,
83 const hdb_entry_alias *alias,
84 krb5_data *value)
85 {
86 size_t len = 0;
87 int ret;
88
89 ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length,
90 alias, &len, ret);
91 if (ret == 0 && value->length != len)
92 krb5_abortx(context, "internal asn.1 encoder error");
93 return ret;
94 }
95
96 int
hdb_value2entry_alias(krb5_context context,krb5_data * value,hdb_entry_alias * ent)97 hdb_value2entry_alias(krb5_context context, krb5_data *value,
98 hdb_entry_alias *ent)
99 {
100 return decode_hdb_entry_alias(value->data, value->length, ent, NULL);
101 }
102
103 krb5_error_code
_hdb_fetch_kvno(krb5_context context,HDB * db,krb5_const_principal principal,unsigned flags,krb5_kvno kvno,hdb_entry_ex * entry)104 _hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
105 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
106 {
107 krb5_principal enterprise_principal = NULL;
108 krb5_data key, value;
109 krb5_error_code ret;
110
111 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
112 if (principal->name.name_string.len != 1) {
113 ret = KRB5_PARSE_MALFORMED;
114 krb5_set_error_message(context, ret, "malformed principal: "
115 "enterprise name with %d name components",
116 principal->name.name_string.len);
117 return ret;
118 }
119 ret = krb5_parse_name(context, principal->name.name_string.val[0],
120 &enterprise_principal);
121 if (ret)
122 return ret;
123 principal = enterprise_principal;
124 }
125
126 hdb_principal2key(context, principal, &key);
127 if (enterprise_principal)
128 krb5_free_principal(context, enterprise_principal);
129 ret = db->hdb__get(context, db, key, &value);
130 krb5_data_free(&key);
131 if(ret)
132 return ret;
133 ret = hdb_value2entry(context, &value, &entry->entry);
134 if (ret == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) {
135 krb5_data_free(&value);
136 return HDB_ERR_NOENTRY;
137 } else if (ret == ASN1_BAD_ID) {
138 hdb_entry_alias alias;
139
140 ret = hdb_value2entry_alias(context, &value, &alias);
141 if (ret) {
142 krb5_data_free(&value);
143 return ret;
144 }
145 hdb_principal2key(context, alias.principal, &key);
146 krb5_data_free(&value);
147 free_hdb_entry_alias(&alias);
148
149 ret = db->hdb__get(context, db, key, &value);
150 krb5_data_free(&key);
151 if (ret)
152 return ret;
153 ret = hdb_value2entry(context, &value, &entry->entry);
154 if (ret) {
155 krb5_data_free(&value);
156 return ret;
157 }
158 }
159 krb5_data_free(&value);
160 if ((flags & HDB_F_DECRYPT) && (flags & HDB_F_ALL_KVNOS)) {
161 /* Decrypt the current keys */
162 ret = hdb_unseal_keys(context, db, &entry->entry);
163 if (ret) {
164 hdb_free_entry(context, entry);
165 return ret;
166 }
167 /* Decrypt the key history too */
168 ret = hdb_unseal_keys_kvno(context, db, 0, flags, &entry->entry);
169 if (ret) {
170 hdb_free_entry(context, entry);
171 return ret;
172 }
173 } else if ((flags & HDB_F_DECRYPT)) {
174 if ((flags & HDB_F_KVNO_SPECIFIED) == 0 || kvno == entry->entry.kvno) {
175 /* Decrypt the current keys */
176 ret = hdb_unseal_keys(context, db, &entry->entry);
177 if (ret) {
178 hdb_free_entry(context, entry);
179 return ret;
180 }
181 } else {
182 if ((flags & HDB_F_ALL_KVNOS))
183 kvno = 0;
184 /*
185 * Find and decrypt the keys from the history that we want,
186 * and swap them with the current keys
187 */
188 ret = hdb_unseal_keys_kvno(context, db, kvno, flags, &entry->entry);
189 if (ret) {
190 hdb_free_entry(context, entry);
191 return ret;
192 }
193 }
194 }
195
196 return 0;
197 }
198
199 static krb5_error_code
hdb_remove_aliases(krb5_context context,HDB * db,krb5_data * key)200 hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
201 {
202 const HDB_Ext_Aliases *aliases;
203 krb5_error_code code;
204 hdb_entry oldentry;
205 krb5_data value;
206 size_t i;
207
208 code = db->hdb__get(context, db, *key, &value);
209 if (code == HDB_ERR_NOENTRY)
210 return 0;
211 else if (code)
212 return code;
213
214 code = hdb_value2entry(context, &value, &oldentry);
215 krb5_data_free(&value);
216 if (code)
217 return code;
218
219 code = hdb_entry_get_aliases(&oldentry, &aliases);
220 if (code || aliases == NULL) {
221 free_hdb_entry(&oldentry);
222 return code;
223 }
224 for (i = 0; i < aliases->aliases.len; i++) {
225 krb5_data akey;
226
227 code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
228 if (code == 0) {
229 code = db->hdb__del(context, db, akey);
230 krb5_data_free(&akey);
231 }
232 if (code) {
233 free_hdb_entry(&oldentry);
234 return code;
235 }
236 }
237 free_hdb_entry(&oldentry);
238 return 0;
239 }
240
241 static krb5_error_code
hdb_add_aliases(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)242 hdb_add_aliases(krb5_context context, HDB *db,
243 unsigned flags, hdb_entry_ex *entry)
244 {
245 const HDB_Ext_Aliases *aliases;
246 krb5_error_code code;
247 krb5_data key, value;
248 size_t i;
249
250 code = hdb_entry_get_aliases(&entry->entry, &aliases);
251 if (code || aliases == NULL)
252 return code;
253
254 for (i = 0; i < aliases->aliases.len; i++) {
255 hdb_entry_alias entryalias;
256 entryalias.principal = entry->entry.principal;
257
258 code = hdb_entry_alias2value(context, &entryalias, &value);
259 if (code)
260 return code;
261
262 code = hdb_principal2key(context, &aliases->aliases.val[i], &key);
263 if (code == 0) {
264 code = db->hdb__put(context, db, flags, key, value);
265 krb5_data_free(&key);
266 }
267 krb5_data_free(&value);
268 if (code)
269 return code;
270 }
271 return 0;
272 }
273
274 static krb5_error_code
hdb_check_aliases(krb5_context context,HDB * db,hdb_entry_ex * entry)275 hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry)
276 {
277 const HDB_Ext_Aliases *aliases;
278 int code;
279 size_t i;
280
281 /* check if new aliases already is used */
282
283 code = hdb_entry_get_aliases(&entry->entry, &aliases);
284 if (code)
285 return code;
286
287 for (i = 0; aliases && i < aliases->aliases.len; i++) {
288 hdb_entry_alias alias;
289 krb5_data akey, value;
290
291 code = hdb_principal2key(context, &aliases->aliases.val[i], &akey);
292 if (code == 0) {
293 code = db->hdb__get(context, db, akey, &value);
294 krb5_data_free(&akey);
295 }
296 if (code == HDB_ERR_NOENTRY)
297 continue;
298 else if (code)
299 return code;
300
301 code = hdb_value2entry_alias(context, &value, &alias);
302 krb5_data_free(&value);
303
304 if (code == ASN1_BAD_ID)
305 return HDB_ERR_EXISTS;
306 else if (code)
307 return code;
308
309 code = krb5_principal_compare(context, alias.principal,
310 entry->entry.principal);
311 free_hdb_entry_alias(&alias);
312 if (code == 0)
313 return HDB_ERR_EXISTS;
314 }
315 return 0;
316 }
317
318 krb5_error_code
_hdb_store(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)319 _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
320 {
321 krb5_data key, value;
322 int code;
323
324 if (entry->entry.flags.do_not_store)
325 return HDB_ERR_MISUSE;
326 /* check if new aliases already is used */
327 code = hdb_check_aliases(context, db, entry);
328 if (code)
329 return code;
330
331 if ((flags & HDB_F_PRECHECK) && (flags & HDB_F_REPLACE))
332 return 0;
333
334 if ((flags & HDB_F_PRECHECK)) {
335 code = hdb_principal2key(context, entry->entry.principal, &key);
336 if (code)
337 return code;
338 code = db->hdb__get(context, db, key, &value);
339 krb5_data_free(&key);
340 if (code == 0)
341 krb5_data_free(&value);
342 if (code == HDB_ERR_NOENTRY)
343 return 0;
344 return code ? code : HDB_ERR_EXISTS;
345 }
346
347 if(entry->entry.generation == NULL) {
348 struct timeval t;
349 entry->entry.generation = malloc(sizeof(*entry->entry.generation));
350 if(entry->entry.generation == NULL) {
351 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
352 return ENOMEM;
353 }
354 gettimeofday(&t, NULL);
355 entry->entry.generation->time = t.tv_sec;
356 entry->entry.generation->usec = t.tv_usec;
357 entry->entry.generation->gen = 0;
358 } else
359 entry->entry.generation->gen++;
360
361 code = hdb_seal_keys(context, db, &entry->entry);
362 if (code)
363 return code;
364
365 hdb_principal2key(context, entry->entry.principal, &key);
366
367 /* remove aliases */
368 code = hdb_remove_aliases(context, db, &key);
369 if (code) {
370 krb5_data_free(&key);
371 return code;
372 }
373 hdb_entry2value(context, &entry->entry, &value);
374 code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
375 krb5_data_free(&value);
376 krb5_data_free(&key);
377 if (code)
378 return code;
379
380 code = hdb_add_aliases(context, db, flags, entry);
381
382 return code;
383 }
384
385 krb5_error_code
_hdb_remove(krb5_context context,HDB * db,unsigned flags,krb5_const_principal principal)386 _hdb_remove(krb5_context context, HDB *db,
387 unsigned flags, krb5_const_principal principal)
388 {
389 krb5_data key, value;
390 int code;
391
392 hdb_principal2key(context, principal, &key);
393
394 if ((flags & HDB_F_PRECHECK)) {
395 /*
396 * We don't check that we can delete the aliases because we
397 * assume that the DB is consistent. If we did check for alias
398 * consistency we'd also have to provide a way to fsck the DB,
399 * otherwise admins would have no way to recover -- papering
400 * over this here is less work, but we really ought to provide
401 * an HDB fsck.
402 */
403 code = db->hdb__get(context, db, key, &value);
404 krb5_data_free(&key);
405 if (code == 0) {
406 krb5_data_free(&value);
407 return 0;
408 }
409 return code;
410 }
411
412 code = hdb_remove_aliases(context, db, &key);
413 if (code) {
414 krb5_data_free(&key);
415 return code;
416 }
417 code = db->hdb__del(context, db, key);
418 krb5_data_free(&key);
419 return code;
420 }
421
422