1/* 2 * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 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. 16 * 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. 20 * 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 31 * SUCH DAMAGE. 32 */ 33 34#include "hdb_locl.h" 35 36int 37hdb_principal2key(krb5_context context, krb5_const_principal p, krb5_data *key) 38{ 39 Principal new; 40 size_t len = 0; 41 int ret; 42 43 ret = copy_Principal(p, &new); 44 if(ret) 45 return ret; 46 new.name.name_type = 0; 47 48 ASN1_MALLOC_ENCODE(Principal, key->data, key->length, &new, &len, ret); 49 if (ret == 0 && key->length != len) 50 krb5_abortx(context, "internal asn.1 encoder error"); 51 free_Principal(&new); 52 return ret; 53} 54 55int 56hdb_key2principal(krb5_context context, krb5_data *key, krb5_principal p) 57{ 58 return decode_Principal(key->data, key->length, p, NULL); 59} 60 61int 62hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value) 63{ 64 size_t len = 0; 65 int ret; 66 67 ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret); 68 if (ret == 0 && value->length != len) 69 krb5_abortx(context, "internal asn.1 encoder error"); 70 return ret; 71} 72 73int 74hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent) 75{ 76 return decode_hdb_entry(value->data, value->length, ent, NULL); 77} 78 79int 80hdb_entry_alias2value(krb5_context context, 81 const hdb_entry_alias *alias, 82 krb5_data *value) 83{ 84 size_t len = 0; 85 int ret; 86 87 ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length, 88 alias, &len, ret); 89 if (ret == 0 && value->length != len) 90 krb5_abortx(context, "internal asn.1 encoder error"); 91 return ret; 92} 93 94int 95hdb_value2entry_alias(krb5_context context, krb5_data *value, 96 hdb_entry_alias *ent) 97{ 98 return decode_hdb_entry_alias(value->data, value->length, ent, NULL); 99} 100 101krb5_error_code 102_hdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, 103 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) 104{ 105 krb5_principal enterprise_principal = NULL; 106 krb5_data key, value; 107 krb5_error_code ret; 108 109 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { 110 if (principal->name.name_string.len != 1) { 111 ret = KRB5_PARSE_MALFORMED; 112 krb5_set_error_message(context, ret, "malformed principal: " 113 "enterprise name with %d name components", 114 principal->name.name_string.len); 115 return ret; 116 } 117 ret = krb5_parse_name(context, principal->name.name_string.val[0], 118 &enterprise_principal); 119 if (ret) 120 return ret; 121 principal = enterprise_principal; 122 } 123 124 ret = hdb_principal2key(context, principal, &key); 125 if (enterprise_principal) 126 krb5_free_principal(context, enterprise_principal); 127 if (ret) 128 return ret; 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 199static krb5_error_code 200hdb_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) { 229 free_hdb_entry(&oldentry); 230 return code; 231 } 232 code = db->hdb__del(context, db, akey); 233 krb5_data_free(&akey); 234 if (code) { 235 free_hdb_entry(&oldentry); 236 return code; 237 } 238 } 239 free_hdb_entry(&oldentry); 240 return 0; 241} 242 243static krb5_error_code 244hdb_add_aliases(krb5_context context, HDB *db, 245 unsigned flags, hdb_entry_ex *entry) 246{ 247 const HDB_Ext_Aliases *aliases; 248 krb5_error_code code; 249 krb5_data key, value; 250 size_t i; 251 252 code = hdb_entry_get_aliases(&entry->entry, &aliases); 253 if (code || aliases == NULL) 254 return code; 255 256 for (i = 0; i < aliases->aliases.len; i++) { 257 hdb_entry_alias entryalias; 258 entryalias.principal = entry->entry.principal; 259 260 code = hdb_principal2key(context, &aliases->aliases.val[i], &key); 261 if (code) 262 return code; 263 code = hdb_entry_alias2value(context, &entryalias, &value); 264 if (code) { 265 krb5_data_free(&key); 266 return code; 267 } 268 code = db->hdb__put(context, db, flags, key, value); 269 krb5_data_free(&key); 270 krb5_data_free(&value); 271 if (code) 272 return code; 273 } 274 return 0; 275} 276 277static krb5_error_code 278hdb_check_aliases(krb5_context context, HDB *db, hdb_entry_ex *entry) 279{ 280 const HDB_Ext_Aliases *aliases; 281 int code; 282 size_t i; 283 284 /* check if new aliases already is used */ 285 286 code = hdb_entry_get_aliases(&entry->entry, &aliases); 287 if (code) 288 return code; 289 290 for (i = 0; aliases && i < aliases->aliases.len; i++) { 291 hdb_entry_alias alias; 292 krb5_data akey, value; 293 294 code = hdb_principal2key(context, &aliases->aliases.val[i], &akey); 295 if (code) 296 return code; 297 code = db->hdb__get(context, db, akey, &value); 298 krb5_data_free(&akey); 299 if (code == HDB_ERR_NOENTRY) 300 continue; 301 else if (code) 302 return code; 303 304 code = hdb_value2entry_alias(context, &value, &alias); 305 krb5_data_free(&value); 306 307 if (code == ASN1_BAD_ID) 308 return HDB_ERR_EXISTS; 309 else if (code) 310 return code; 311 312 code = krb5_principal_compare(context, alias.principal, 313 entry->entry.principal); 314 free_hdb_entry_alias(&alias); 315 if (code == 0) 316 return HDB_ERR_EXISTS; 317 } 318 return 0; 319} 320 321krb5_error_code 322_hdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 323{ 324 krb5_data key, value; 325 int code; 326 327 if (entry->entry.flags.do_not_store) 328 return HDB_ERR_MISUSE; 329 /* check if new aliases already is used */ 330 code = hdb_check_aliases(context, db, entry); 331 if (code) 332 return code; 333 334 if(entry->entry.generation == NULL) { 335 struct timeval t; 336 entry->entry.generation = malloc(sizeof(*entry->entry.generation)); 337 if(entry->entry.generation == NULL) { 338 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 339 return ENOMEM; 340 } 341 gettimeofday(&t, NULL); 342 entry->entry.generation->time = t.tv_sec; 343 entry->entry.generation->usec = t.tv_usec; 344 entry->entry.generation->gen = 0; 345 } else 346 entry->entry.generation->gen++; 347 348 code = hdb_seal_keys(context, db, &entry->entry); 349 if (code) 350 return code; 351 352 hdb_principal2key(context, entry->entry.principal, &key); 353 354 /* remove aliases */ 355 code = hdb_remove_aliases(context, db, &key); 356 if (code) { 357 krb5_data_free(&key); 358 return code; 359 } 360 hdb_entry2value(context, &entry->entry, &value); 361 code = db->hdb__put(context, db, flags & HDB_F_REPLACE, key, value); 362 krb5_data_free(&value); 363 krb5_data_free(&key); 364 if (code) 365 return code; 366 367 code = hdb_add_aliases(context, db, flags, entry); 368 369 return code; 370} 371 372krb5_error_code 373_hdb_remove(krb5_context context, HDB *db, krb5_const_principal principal) 374{ 375 krb5_data key; 376 int code; 377 378 hdb_principal2key(context, principal, &key); 379 380 code = hdb_remove_aliases(context, db, &key); 381 if (code) { 382 krb5_data_free(&key); 383 return code; 384 } 385 code = db->hdb__del(context, db, key); 386 krb5_data_free(&key); 387 return code; 388} 389 390