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