1 /* $NetBSD: common.c,v 1.1.1.2 2014/04/24 12:45:28 pettai 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 int code;
111
112 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
113 if (principal->name.name_string.len != 1) {
114 ret = KRB5_PARSE_MALFORMED;
115 krb5_set_error_message(context, ret, "malformed principal: "
116 "enterprise name with %d name components",
117 principal->name.name_string.len);
118 return ret;
119 }
120 ret = krb5_parse_name(context, principal->name.name_string.val[0],
121 &enterprise_principal);
122 if (ret)
123 return ret;
124 principal = enterprise_principal;
125 }
126
127 hdb_principal2key(context, principal, &key);
128 if (enterprise_principal)
129 krb5_free_principal(context, enterprise_principal);
130 code = db->hdb__get(context, db, key, &value);
131 krb5_data_free(&key);
132 if(code)
133 return code;
134 code = hdb_value2entry(context, &value, &entry->entry);
135 if (code == ASN1_BAD_ID && (flags & HDB_F_CANON) == 0) {
136 krb5_data_free(&value);
137 return HDB_ERR_NOENTRY;
138 } else if (code == ASN1_BAD_ID) {
139 hdb_entry_alias alias;
140
141 code = hdb_value2entry_alias(context, &value, &alias);
142 if (code) {
143 krb5_data_free(&value);
144 return code;
145 }
146 hdb_principal2key(context, alias.principal, &key);
147 krb5_data_free(&value);
148 free_hdb_entry_alias(&alias);
149
150 code = db->hdb__get(context, db, key, &value);
151 krb5_data_free(&key);
152 if (code)
153 return code;
154 code = hdb_value2entry(context, &value, &entry->entry);
155 if (code) {
156 krb5_data_free(&value);
157 return code;
158 }
159 }
160 krb5_data_free(&value);
161 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
162 code = hdb_unseal_keys (context, db, &entry->entry);
163 if (code)
164 hdb_free_entry(context, entry);
165 }
166 return code;
167 }
168
169 static krb5_error_code
hdb_remove_aliases(krb5_context context,HDB * db,krb5_data * key)170 hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key)
171 {
172 const HDB_Ext_Aliases *aliases;
173 krb5_error_code code;
174 hdb_entry oldentry;
175 krb5_data value;
176 size_t i;
177
178 code = db->hdb__get(context, db, *key, &value);
179 if (code == HDB_ERR_NOENTRY)
180 return 0;
181 else if (code)
182 return code;
183
184 code = hdb_value2entry(context, &value, &oldentry);
185 krb5_data_free(&value);
186 if (code)
187 return code;
188
189 code = hdb_entry_get_aliases(&oldentry, &aliases);
190 if (code || aliases == NULL) {
191 free_hdb_entry(&oldentry);
192 return code;
193 }
194 for (i = 0; i < aliases->aliases.len; i++) {
195 krb5_data akey;
196
197 hdb_principal2key(context, &aliases->aliases.val[i], &akey);
198 code = db->hdb__del(context, db, akey);
199 krb5_data_free(&akey);
200 if (code) {
201 free_hdb_entry(&oldentry);
202 return code;
203 }
204 }
205 free_hdb_entry(&oldentry);
206 return 0;
207 }
208
209 static krb5_error_code
hdb_add_aliases(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)210 hdb_add_aliases(krb5_context context, HDB *db,
211 unsigned flags, hdb_entry_ex *entry)
212 {
213 const HDB_Ext_Aliases *aliases;
214 krb5_error_code code;
215 krb5_data key, value;
216 size_t i;
217
218 code = hdb_entry_get_aliases(&entry->entry, &aliases);
219 if (code || aliases == NULL)
220 return code;
221
222 for (i = 0; i < aliases->aliases.len; i++) {
223 hdb_entry_alias entryalias;
224 entryalias.principal = entry->entry.principal;
225
226 hdb_principal2key(context, &aliases->aliases.val[i], &key);
227 code = hdb_entry_alias2value(context, &entryalias, &value);
228 if (code) {
229 krb5_data_free(&key);
230 return code;
231 }
232 code = db->hdb__put(context, db, flags, key, value);
233 krb5_data_free(&key);
234 krb5_data_free(&value);
235 if (code)
236 return code;
237 }
238 return 0;
239 }
240
241 static krb5_error_code
hdb_check_aliases(krb5_context context,HDB * db,hdb_entry_ex * entry)242 hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry)
243 {
244 const HDB_Ext_Aliases *aliases;
245 int code;
246 size_t i;
247
248 /* check if new aliases already is used */
249
250 code = hdb_entry_get_aliases(&entry->entry, &aliases);
251 if (code)
252 return code;
253
254 for (i = 0; aliases && i < aliases->aliases.len; i++) {
255 hdb_entry_alias alias;
256 krb5_data akey, value;
257
258 hdb_principal2key(context, &aliases->aliases.val[i], &akey);
259 code = db->hdb__get(context, db, akey, &value);
260 krb5_data_free(&akey);
261 if (code == HDB_ERR_NOENTRY)
262 continue;
263 else if (code)
264 return code;
265
266 code = hdb_value2entry_alias(context, &value, &alias);
267 krb5_data_free(&value);
268
269 if (code == ASN1_BAD_ID)
270 return HDB_ERR_EXISTS;
271 else if (code)
272 return code;
273
274 code = krb5_principal_compare(context, alias.principal,
275 entry->entry.principal);
276 free_hdb_entry_alias(&alias);
277 if (code == 0)
278 return HDB_ERR_EXISTS;
279 }
280 return 0;
281 }
282
283 krb5_error_code
_hdb_store(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)284 _hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
285 {
286 krb5_data key, value;
287 int code;
288
289 /* check if new aliases already is used */
290 code = hdb_check_aliases(context, db, entry);
291 if (code)
292 return code;
293
294 if(entry->entry.generation == NULL) {
295 struct timeval t;
296 entry->entry.generation = malloc(sizeof(*entry->entry.generation));
297 if(entry->entry.generation == NULL) {
298 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
299 return ENOMEM;
300 }
301 gettimeofday(&t, NULL);
302 entry->entry.generation->time = t.tv_sec;
303 entry->entry.generation->usec = t.tv_usec;
304 entry->entry.generation->gen = 0;
305 } else
306 entry->entry.generation->gen++;
307
308 code = hdb_seal_keys(context, db, &entry->entry);
309 if (code)
310 return code;
311
312 hdb_principal2key(context, entry->entry.principal, &key);
313
314 /* remove aliases */
315 code = hdb_remove_aliases(context, db, &key);
316 if (code) {
317 krb5_data_free(&key);
318 return code;
319 }
320 hdb_entry2value(context, &entry->entry, &value);
321 code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value);
322 krb5_data_free(&value);
323 krb5_data_free(&key);
324 if (code)
325 return code;
326
327 code = hdb_add_aliases(context, db, flags, entry);
328
329 return code;
330 }
331
332 krb5_error_code
_hdb_remove(krb5_context context,HDB * db,krb5_const_principal principal)333 _hdb_remove(krb5_context context, HDB *db, krb5_const_principal principal)
334 {
335 krb5_data key;
336 int code;
337
338 hdb_principal2key(context, principal, &key);
339
340 code = hdb_remove_aliases(context, db, &key);
341 if (code) {
342 krb5_data_free(&key);
343 return code;
344 }
345 code = db->hdb__del(context, db, key);
346 krb5_data_free(&key);
347 return code;
348 }
349
350