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 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 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 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 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 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 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 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 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 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 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 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 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