1*ae771770SStanislav Sedov /* 2*ae771770SStanislav Sedov * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan 3*ae771770SStanislav Sedov * (Royal Institute of Technology, Stockholm, Sweden). 4*ae771770SStanislav Sedov * All rights reserved. 5*ae771770SStanislav Sedov * 6*ae771770SStanislav Sedov * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7*ae771770SStanislav Sedov * 8*ae771770SStanislav Sedov * Redistribution and use in source and binary forms, with or without 9*ae771770SStanislav Sedov * modification, are permitted provided that the following conditions 10*ae771770SStanislav Sedov * are met: 11*ae771770SStanislav Sedov * 12*ae771770SStanislav Sedov * 1. Redistributions of source code must retain the above copyright 13*ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer. 14*ae771770SStanislav Sedov * 15*ae771770SStanislav Sedov * 2. Redistributions in binary form must reproduce the above copyright 16*ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer in the 17*ae771770SStanislav Sedov * documentation and/or other materials provided with the distribution. 18*ae771770SStanislav Sedov * 19*ae771770SStanislav Sedov * 3. Neither the name of the Institute nor the names of its contributors 20*ae771770SStanislav Sedov * may be used to endorse or promote products derived from this software 21*ae771770SStanislav Sedov * without specific prior written permission. 22*ae771770SStanislav Sedov * 23*ae771770SStanislav Sedov * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24*ae771770SStanislav Sedov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25*ae771770SStanislav Sedov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26*ae771770SStanislav Sedov * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27*ae771770SStanislav Sedov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28*ae771770SStanislav Sedov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29*ae771770SStanislav Sedov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30*ae771770SStanislav Sedov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31*ae771770SStanislav Sedov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32*ae771770SStanislav Sedov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33*ae771770SStanislav Sedov * SUCH DAMAGE. 34*ae771770SStanislav Sedov */ 35*ae771770SStanislav Sedov 36*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_POSTDATED 0x00000001 37*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_FORWARDABLE 0x00000002 38*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_TGT_BASED 0x00000004 39*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_RENEWABLE 0x00000008 40*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_PROXIABLE 0x00000010 41*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_DUP_SKEY 0x00000020 42*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_ALL_TIX 0x00000040 43*ae771770SStanislav Sedov #define KRB5_KDB_REQUIRES_PRE_AUTH 0x00000080 44*ae771770SStanislav Sedov #define KRB5_KDB_REQUIRES_HW_AUTH 0x00000100 45*ae771770SStanislav Sedov #define KRB5_KDB_REQUIRES_PWCHANGE 0x00000200 46*ae771770SStanislav Sedov #define KRB5_KDB_DISALLOW_SVR 0x00001000 47*ae771770SStanislav Sedov #define KRB5_KDB_PWCHANGE_SERVICE 0x00002000 48*ae771770SStanislav Sedov #define KRB5_KDB_SUPPORT_DESMD5 0x00004000 49*ae771770SStanislav Sedov #define KRB5_KDB_NEW_PRINC 0x00008000 50*ae771770SStanislav Sedov 51*ae771770SStanislav Sedov /* 52*ae771770SStanislav Sedov 53*ae771770SStanislav Sedov key: krb5_unparse_name + NUL 54*ae771770SStanislav Sedov 55*ae771770SStanislav Sedov 16: baselength 56*ae771770SStanislav Sedov 32: attributes 57*ae771770SStanislav Sedov 32: max time 58*ae771770SStanislav Sedov 32: max renewable time 59*ae771770SStanislav Sedov 32: client expire 60*ae771770SStanislav Sedov 32: passwd expire 61*ae771770SStanislav Sedov 32: last successful passwd 62*ae771770SStanislav Sedov 32: last failed attempt 63*ae771770SStanislav Sedov 32: num of failed attempts 64*ae771770SStanislav Sedov 16: num tl data 65*ae771770SStanislav Sedov 16: num data data 66*ae771770SStanislav Sedov 16: principal length 67*ae771770SStanislav Sedov length: principal 68*ae771770SStanislav Sedov for num tl data times 69*ae771770SStanislav Sedov 16: tl data type 70*ae771770SStanislav Sedov 16: tl data length 71*ae771770SStanislav Sedov length: length 72*ae771770SStanislav Sedov for num key data times 73*ae771770SStanislav Sedov 16: version (num keyblocks) 74*ae771770SStanislav Sedov 16: kvno 75*ae771770SStanislav Sedov for version times: 76*ae771770SStanislav Sedov 16: type 77*ae771770SStanislav Sedov 16: length 78*ae771770SStanislav Sedov length: keydata 79*ae771770SStanislav Sedov 80*ae771770SStanislav Sedov 81*ae771770SStanislav Sedov key_data_contents[0] 82*ae771770SStanislav Sedov 83*ae771770SStanislav Sedov int16: length 84*ae771770SStanislav Sedov read-of-data: key-encrypted, key-usage 0, master-key 85*ae771770SStanislav Sedov 86*ae771770SStanislav Sedov salt: 87*ae771770SStanislav Sedov version2 = salt in key_data->key_data_contents[1] 88*ae771770SStanislav Sedov else default salt. 89*ae771770SStanislav Sedov 90*ae771770SStanislav Sedov */ 91*ae771770SStanislav Sedov 92*ae771770SStanislav Sedov #include "hdb_locl.h" 93*ae771770SStanislav Sedov 94*ae771770SStanislav Sedov #define KDB_V1_BASE_LENGTH 38 95*ae771770SStanislav Sedov 96*ae771770SStanislav Sedov #if HAVE_DB1 97*ae771770SStanislav Sedov 98*ae771770SStanislav Sedov #if defined(HAVE_DB_185_H) 99*ae771770SStanislav Sedov #include <db_185.h> 100*ae771770SStanislav Sedov #elif defined(HAVE_DB_H) 101*ae771770SStanislav Sedov #include <db.h> 102*ae771770SStanislav Sedov #endif 103*ae771770SStanislav Sedov 104*ae771770SStanislav Sedov #define CHECK(x) do { if ((x)) goto out; } while(0) 105*ae771770SStanislav Sedov 106*ae771770SStanislav Sedov static krb5_error_code 107*ae771770SStanislav Sedov mdb_principal2key(krb5_context context, 108*ae771770SStanislav Sedov krb5_const_principal principal, 109*ae771770SStanislav Sedov krb5_data *key) 110*ae771770SStanislav Sedov { 111*ae771770SStanislav Sedov krb5_error_code ret; 112*ae771770SStanislav Sedov char *str; 113*ae771770SStanislav Sedov 114*ae771770SStanislav Sedov ret = krb5_unparse_name(context, principal, &str); 115*ae771770SStanislav Sedov if (ret) 116*ae771770SStanislav Sedov return ret; 117*ae771770SStanislav Sedov key->data = str; 118*ae771770SStanislav Sedov key->length = strlen(str) + 1; 119*ae771770SStanislav Sedov return 0; 120*ae771770SStanislav Sedov } 121*ae771770SStanislav Sedov 122*ae771770SStanislav Sedov #define KRB5_KDB_SALTTYPE_NORMAL 0 123*ae771770SStanislav Sedov #define KRB5_KDB_SALTTYPE_V4 1 124*ae771770SStanislav Sedov #define KRB5_KDB_SALTTYPE_NOREALM 2 125*ae771770SStanislav Sedov #define KRB5_KDB_SALTTYPE_ONLYREALM 3 126*ae771770SStanislav Sedov #define KRB5_KDB_SALTTYPE_SPECIAL 4 127*ae771770SStanislav Sedov #define KRB5_KDB_SALTTYPE_AFS3 5 128*ae771770SStanislav Sedov #define KRB5_KDB_SALTTYPE_CERTHASH 6 129*ae771770SStanislav Sedov 130*ae771770SStanislav Sedov static krb5_error_code 131*ae771770SStanislav Sedov fix_salt(krb5_context context, hdb_entry *ent, int key_num) 132*ae771770SStanislav Sedov { 133*ae771770SStanislav Sedov krb5_error_code ret; 134*ae771770SStanislav Sedov Salt *salt = ent->keys.val[key_num].salt; 135*ae771770SStanislav Sedov /* fix salt type */ 136*ae771770SStanislav Sedov switch((int)salt->type) { 137*ae771770SStanislav Sedov case KRB5_KDB_SALTTYPE_NORMAL: 138*ae771770SStanislav Sedov salt->type = KRB5_PADATA_PW_SALT; 139*ae771770SStanislav Sedov break; 140*ae771770SStanislav Sedov case KRB5_KDB_SALTTYPE_V4: 141*ae771770SStanislav Sedov krb5_data_free(&salt->salt); 142*ae771770SStanislav Sedov salt->type = KRB5_PADATA_PW_SALT; 143*ae771770SStanislav Sedov break; 144*ae771770SStanislav Sedov case KRB5_KDB_SALTTYPE_NOREALM: 145*ae771770SStanislav Sedov { 146*ae771770SStanislav Sedov size_t len; 147*ae771770SStanislav Sedov size_t i; 148*ae771770SStanislav Sedov char *p; 149*ae771770SStanislav Sedov 150*ae771770SStanislav Sedov len = 0; 151*ae771770SStanislav Sedov for (i = 0; i < ent->principal->name.name_string.len; ++i) 152*ae771770SStanislav Sedov len += strlen(ent->principal->name.name_string.val[i]); 153*ae771770SStanislav Sedov ret = krb5_data_alloc (&salt->salt, len); 154*ae771770SStanislav Sedov if (ret) 155*ae771770SStanislav Sedov return ret; 156*ae771770SStanislav Sedov p = salt->salt.data; 157*ae771770SStanislav Sedov for (i = 0; i < ent->principal->name.name_string.len; ++i) { 158*ae771770SStanislav Sedov memcpy (p, 159*ae771770SStanislav Sedov ent->principal->name.name_string.val[i], 160*ae771770SStanislav Sedov strlen(ent->principal->name.name_string.val[i])); 161*ae771770SStanislav Sedov p += strlen(ent->principal->name.name_string.val[i]); 162*ae771770SStanislav Sedov } 163*ae771770SStanislav Sedov 164*ae771770SStanislav Sedov salt->type = KRB5_PADATA_PW_SALT; 165*ae771770SStanislav Sedov break; 166*ae771770SStanislav Sedov } 167*ae771770SStanislav Sedov case KRB5_KDB_SALTTYPE_ONLYREALM: 168*ae771770SStanislav Sedov krb5_data_free(&salt->salt); 169*ae771770SStanislav Sedov ret = krb5_data_copy(&salt->salt, 170*ae771770SStanislav Sedov ent->principal->realm, 171*ae771770SStanislav Sedov strlen(ent->principal->realm)); 172*ae771770SStanislav Sedov if(ret) 173*ae771770SStanislav Sedov return ret; 174*ae771770SStanislav Sedov salt->type = KRB5_PADATA_PW_SALT; 175*ae771770SStanislav Sedov break; 176*ae771770SStanislav Sedov case KRB5_KDB_SALTTYPE_SPECIAL: 177*ae771770SStanislav Sedov salt->type = KRB5_PADATA_PW_SALT; 178*ae771770SStanislav Sedov break; 179*ae771770SStanislav Sedov case KRB5_KDB_SALTTYPE_AFS3: 180*ae771770SStanislav Sedov krb5_data_free(&salt->salt); 181*ae771770SStanislav Sedov ret = krb5_data_copy(&salt->salt, 182*ae771770SStanislav Sedov ent->principal->realm, 183*ae771770SStanislav Sedov strlen(ent->principal->realm)); 184*ae771770SStanislav Sedov if(ret) 185*ae771770SStanislav Sedov return ret; 186*ae771770SStanislav Sedov salt->type = KRB5_PADATA_AFS3_SALT; 187*ae771770SStanislav Sedov break; 188*ae771770SStanislav Sedov case KRB5_KDB_SALTTYPE_CERTHASH: 189*ae771770SStanislav Sedov krb5_data_free(&salt->salt); 190*ae771770SStanislav Sedov free(ent->keys.val[key_num].salt); 191*ae771770SStanislav Sedov ent->keys.val[key_num].salt = NULL; 192*ae771770SStanislav Sedov break; 193*ae771770SStanislav Sedov default: 194*ae771770SStanislav Sedov abort(); 195*ae771770SStanislav Sedov } 196*ae771770SStanislav Sedov return 0; 197*ae771770SStanislav Sedov } 198*ae771770SStanislav Sedov 199*ae771770SStanislav Sedov 200*ae771770SStanislav Sedov static krb5_error_code 201*ae771770SStanislav Sedov mdb_value2entry(krb5_context context, krb5_data *data, krb5_kvno kvno, hdb_entry *entry) 202*ae771770SStanislav Sedov { 203*ae771770SStanislav Sedov krb5_error_code ret; 204*ae771770SStanislav Sedov krb5_storage *sp; 205*ae771770SStanislav Sedov uint32_t u32; 206*ae771770SStanislav Sedov uint16_t u16, num_keys, num_tl; 207*ae771770SStanislav Sedov size_t i, j; 208*ae771770SStanislav Sedov char *p; 209*ae771770SStanislav Sedov 210*ae771770SStanislav Sedov sp = krb5_storage_from_data(data); 211*ae771770SStanislav Sedov if (sp == NULL) { 212*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "out of memory"); 213*ae771770SStanislav Sedov return ENOMEM; 214*ae771770SStanislav Sedov } 215*ae771770SStanislav Sedov 216*ae771770SStanislav Sedov krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); 217*ae771770SStanislav Sedov 218*ae771770SStanislav Sedov /* 219*ae771770SStanislav Sedov * 16: baselength 220*ae771770SStanislav Sedov * 221*ae771770SStanislav Sedov * The story here is that these 16 bits have to be a constant: 222*ae771770SStanislav Sedov * KDB_V1_BASE_LENGTH. Once upon a time a different value here 223*ae771770SStanislav Sedov * would have been used to indicate the presence of "extra data" 224*ae771770SStanislav Sedov * between the "base" contents and the {principal name, TL data, 225*ae771770SStanislav Sedov * keys} that follow it. Nothing supports such "extra data" 226*ae771770SStanislav Sedov * nowadays, so neither do we here. 227*ae771770SStanislav Sedov * 228*ae771770SStanislav Sedov * XXX But... surely we ought to log about this extra data, or skip 229*ae771770SStanislav Sedov * it, or something, in case anyone has MIT KDBs with ancient 230*ae771770SStanislav Sedov * entries in them... Logging would allow the admin to know which 231*ae771770SStanislav Sedov * entries to dump with MIT krb5's kdb5_util. 232*ae771770SStanislav Sedov */ 233*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 234*ae771770SStanislav Sedov if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; } 235*ae771770SStanislav Sedov /* 32: attributes */ 236*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 237*ae771770SStanislav Sedov entry->flags.postdate = !(u32 & KRB5_KDB_DISALLOW_POSTDATED); 238*ae771770SStanislav Sedov entry->flags.forwardable = !(u32 & KRB5_KDB_DISALLOW_FORWARDABLE); 239*ae771770SStanislav Sedov entry->flags.initial = !!(u32 & KRB5_KDB_DISALLOW_TGT_BASED); 240*ae771770SStanislav Sedov entry->flags.renewable = !(u32 & KRB5_KDB_DISALLOW_RENEWABLE); 241*ae771770SStanislav Sedov entry->flags.proxiable = !(u32 & KRB5_KDB_DISALLOW_PROXIABLE); 242*ae771770SStanislav Sedov /* DUP_SKEY */ 243*ae771770SStanislav Sedov entry->flags.invalid = !!(u32 & KRB5_KDB_DISALLOW_ALL_TIX); 244*ae771770SStanislav Sedov entry->flags.require_preauth =!!(u32 & KRB5_KDB_REQUIRES_PRE_AUTH); 245*ae771770SStanislav Sedov entry->flags.require_hwauth =!!(u32 & KRB5_KDB_REQUIRES_HW_AUTH); 246*ae771770SStanislav Sedov entry->flags.server = !(u32 & KRB5_KDB_DISALLOW_SVR); 247*ae771770SStanislav Sedov entry->flags.change_pw = !!(u32 & KRB5_KDB_PWCHANGE_SERVICE); 248*ae771770SStanislav Sedov entry->flags.client = 1; /* XXX */ 249*ae771770SStanislav Sedov 250*ae771770SStanislav Sedov /* 32: max time */ 251*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 252*ae771770SStanislav Sedov if (u32) { 253*ae771770SStanislav Sedov entry->max_life = malloc(sizeof(*entry->max_life)); 254*ae771770SStanislav Sedov *entry->max_life = u32; 255*ae771770SStanislav Sedov } 256*ae771770SStanislav Sedov /* 32: max renewable time */ 257*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 258*ae771770SStanislav Sedov if (u32) { 259*ae771770SStanislav Sedov entry->max_renew = malloc(sizeof(*entry->max_renew)); 260*ae771770SStanislav Sedov *entry->max_renew = u32; 261*ae771770SStanislav Sedov } 262*ae771770SStanislav Sedov /* 32: client expire */ 263*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 264*ae771770SStanislav Sedov if (u32) { 265*ae771770SStanislav Sedov entry->valid_end = malloc(sizeof(*entry->valid_end)); 266*ae771770SStanislav Sedov *entry->valid_end = u32; 267*ae771770SStanislav Sedov } 268*ae771770SStanislav Sedov /* 32: passwd expire */ 269*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 270*ae771770SStanislav Sedov if (u32) { 271*ae771770SStanislav Sedov entry->pw_end = malloc(sizeof(*entry->pw_end)); 272*ae771770SStanislav Sedov *entry->pw_end = u32; 273*ae771770SStanislav Sedov } 274*ae771770SStanislav Sedov /* 32: last successful passwd */ 275*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 276*ae771770SStanislav Sedov /* 32: last failed attempt */ 277*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 278*ae771770SStanislav Sedov /* 32: num of failed attempts */ 279*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint32(sp, &u32)); 280*ae771770SStanislav Sedov /* 16: num tl data */ 281*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 282*ae771770SStanislav Sedov num_tl = u16; 283*ae771770SStanislav Sedov /* 16: num key data */ 284*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 285*ae771770SStanislav Sedov num_keys = u16; 286*ae771770SStanislav Sedov /* 16: principal length */ 287*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 288*ae771770SStanislav Sedov /* length: principal */ 289*ae771770SStanislav Sedov { 290*ae771770SStanislav Sedov /* 291*ae771770SStanislav Sedov * Note that the principal name includes the NUL in the entry, 292*ae771770SStanislav Sedov * but we don't want to take chances, so we add an extra NUL. 293*ae771770SStanislav Sedov */ 294*ae771770SStanislav Sedov p = malloc(u16 + 1); 295*ae771770SStanislav Sedov if (p == NULL) { 296*ae771770SStanislav Sedov ret = ENOMEM; 297*ae771770SStanislav Sedov goto out; 298*ae771770SStanislav Sedov } 299*ae771770SStanislav Sedov krb5_storage_read(sp, p, u16); 300*ae771770SStanislav Sedov p[u16] = '\0'; 301*ae771770SStanislav Sedov CHECK(ret = krb5_parse_name(context, p, &entry->principal)); 302*ae771770SStanislav Sedov free(p); 303*ae771770SStanislav Sedov } 304*ae771770SStanislav Sedov /* for num tl data times 305*ae771770SStanislav Sedov 16: tl data type 306*ae771770SStanislav Sedov 16: tl data length 307*ae771770SStanislav Sedov length: length */ 308*ae771770SStanislav Sedov for (i = 0; i < num_tl; i++) { 309*ae771770SStanislav Sedov /* 16: TL data type */ 310*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 311*ae771770SStanislav Sedov /* 16: TL data length */ 312*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 313*ae771770SStanislav Sedov krb5_storage_seek(sp, u16, SEEK_CUR); 314*ae771770SStanislav Sedov } 315*ae771770SStanislav Sedov /* 316*ae771770SStanislav Sedov * for num key data times 317*ae771770SStanislav Sedov * 16: "version" 318*ae771770SStanislav Sedov * 16: kvno 319*ae771770SStanislav Sedov * for version times: 320*ae771770SStanislav Sedov * 16: type 321*ae771770SStanislav Sedov * 16: length 322*ae771770SStanislav Sedov * length: keydata 323*ae771770SStanislav Sedov * 324*ae771770SStanislav Sedov * "version" here is really 1 or 2, the first meaning there's only 325*ae771770SStanislav Sedov * keys for this kvno, the second meaning there's keys and salt[s?]. 326*ae771770SStanislav Sedov * That's right... hold that gag reflex, you can do it. 327*ae771770SStanislav Sedov */ 328*ae771770SStanislav Sedov for (i = 0; i < num_keys; i++) { 329*ae771770SStanislav Sedov int keep = 0; 330*ae771770SStanislav Sedov uint16_t version; 331*ae771770SStanislav Sedov void *ptr; 332*ae771770SStanislav Sedov 333*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 334*ae771770SStanislav Sedov version = u16; 335*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 336*ae771770SStanislav Sedov 337*ae771770SStanislav Sedov /* 338*ae771770SStanislav Sedov * First time through, and until we find one matching key, 339*ae771770SStanislav Sedov * entry->kvno == 0. 340*ae771770SStanislav Sedov */ 341*ae771770SStanislav Sedov if ((entry->kvno < u16) && (kvno == 0 || kvno == u16)) { 342*ae771770SStanislav Sedov keep = 1; 343*ae771770SStanislav Sedov entry->kvno = u16; 344*ae771770SStanislav Sedov /* 345*ae771770SStanislav Sedov * Found a higher kvno than earlier, so free the old highest 346*ae771770SStanislav Sedov * kvno keys. 347*ae771770SStanislav Sedov * 348*ae771770SStanislav Sedov * XXX Of course, we actually want to extract the old kvnos 349*ae771770SStanislav Sedov * as well, for some of the kadm5 APIs. We shouldn't free 350*ae771770SStanislav Sedov * these keys, but keep them elsewhere. 351*ae771770SStanislav Sedov */ 352*ae771770SStanislav Sedov for (j = 0; j < entry->keys.len; j++) 353*ae771770SStanislav Sedov free_Key(&entry->keys.val[j]); 354*ae771770SStanislav Sedov free(entry->keys.val); 355*ae771770SStanislav Sedov entry->keys.len = 0; 356*ae771770SStanislav Sedov entry->keys.val = NULL; 357*ae771770SStanislav Sedov } else if (entry->kvno == u16) 358*ae771770SStanislav Sedov /* Accumulate keys */ 359*ae771770SStanislav Sedov keep = 1; 360*ae771770SStanislav Sedov 361*ae771770SStanislav Sedov if (keep) { 362*ae771770SStanislav Sedov Key *k; 363*ae771770SStanislav Sedov 364*ae771770SStanislav Sedov ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1)); 365*ae771770SStanislav Sedov if (ptr == NULL) { 366*ae771770SStanislav Sedov ret = ENOMEM; 367*ae771770SStanislav Sedov goto out; 368*ae771770SStanislav Sedov } 369*ae771770SStanislav Sedov entry->keys.val = ptr; 370*ae771770SStanislav Sedov 371*ae771770SStanislav Sedov /* k points to current Key */ 372*ae771770SStanislav Sedov k = &entry->keys.val[entry->keys.len]; 373*ae771770SStanislav Sedov 374*ae771770SStanislav Sedov memset(k, 0, sizeof(*k)); 375*ae771770SStanislav Sedov entry->keys.len += 1; 376*ae771770SStanislav Sedov 377*ae771770SStanislav Sedov k->mkvno = malloc(sizeof(*k->mkvno)); 378*ae771770SStanislav Sedov if (k->mkvno == NULL) { 379*ae771770SStanislav Sedov ret = ENOMEM; 380*ae771770SStanislav Sedov goto out; 381*ae771770SStanislav Sedov } 382*ae771770SStanislav Sedov *k->mkvno = 1; 383*ae771770SStanislav Sedov 384*ae771770SStanislav Sedov for (j = 0; j < version; j++) { 385*ae771770SStanislav Sedov uint16_t type; 386*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &type)); 387*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 388*ae771770SStanislav Sedov if (j == 0) { 389*ae771770SStanislav Sedov /* This "version" means we have a key */ 390*ae771770SStanislav Sedov k->key.keytype = type; 391*ae771770SStanislav Sedov if (u16 < 2) { 392*ae771770SStanislav Sedov ret = EINVAL; 393*ae771770SStanislav Sedov goto out; 394*ae771770SStanislav Sedov } 395*ae771770SStanislav Sedov /* 396*ae771770SStanislav Sedov * MIT stores keys encrypted keys as {16-bit length 397*ae771770SStanislav Sedov * of plaintext key, {encrypted key}}. The reason 398*ae771770SStanislav Sedov * for this is that the Kerberos cryptosystem is not 399*ae771770SStanislav Sedov * length-preserving. Heimdal's approach is to 400*ae771770SStanislav Sedov * truncate the plaintext to the expected length of 401*ae771770SStanislav Sedov * the key given its enctype, so we ignore this 402*ae771770SStanislav Sedov * 16-bit length-of-plaintext-key field. 403*ae771770SStanislav Sedov */ 404*ae771770SStanislav Sedov krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ 405*ae771770SStanislav Sedov k->key.keyvalue.length = u16 - 2; /* adjust cipher len */ 406*ae771770SStanislav Sedov k->key.keyvalue.data = malloc(k->key.keyvalue.length); 407*ae771770SStanislav Sedov krb5_storage_read(sp, k->key.keyvalue.data, 408*ae771770SStanislav Sedov k->key.keyvalue.length); 409*ae771770SStanislav Sedov } else if (j == 1) { 410*ae771770SStanislav Sedov /* This "version" means we have a salt */ 411*ae771770SStanislav Sedov k->salt = calloc(1, sizeof(*k->salt)); 412*ae771770SStanislav Sedov if (k->salt == NULL) { 413*ae771770SStanislav Sedov ret = ENOMEM; 414*ae771770SStanislav Sedov goto out; 415*ae771770SStanislav Sedov } 416*ae771770SStanislav Sedov k->salt->type = type; 417*ae771770SStanislav Sedov if (u16 != 0) { 418*ae771770SStanislav Sedov k->salt->salt.data = malloc(u16); 419*ae771770SStanislav Sedov if (k->salt->salt.data == NULL) { 420*ae771770SStanislav Sedov ret = ENOMEM; 421*ae771770SStanislav Sedov goto out; 422*ae771770SStanislav Sedov } 423*ae771770SStanislav Sedov k->salt->salt.length = u16; 424*ae771770SStanislav Sedov krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); 425*ae771770SStanislav Sedov } 426*ae771770SStanislav Sedov fix_salt(context, entry, entry->keys.len - 1); 427*ae771770SStanislav Sedov } else { 428*ae771770SStanislav Sedov /* 429*ae771770SStanislav Sedov * Whatever this "version" might be, we skip it 430*ae771770SStanislav Sedov * 431*ae771770SStanislav Sedov * XXX A krb5.conf parameter requesting that we log 432*ae771770SStanislav Sedov * about strangeness like this, or return an error 433*ae771770SStanislav Sedov * from here, might be nice. 434*ae771770SStanislav Sedov */ 435*ae771770SStanislav Sedov krb5_storage_seek(sp, u16, SEEK_CUR); 436*ae771770SStanislav Sedov } 437*ae771770SStanislav Sedov } 438*ae771770SStanislav Sedov } else { 439*ae771770SStanislav Sedov /* 440*ae771770SStanislav Sedov * XXX For now we skip older kvnos, but we should extract 441*ae771770SStanislav Sedov * them... 442*ae771770SStanislav Sedov */ 443*ae771770SStanislav Sedov for (j = 0; j < version; j++) { 444*ae771770SStanislav Sedov /* enctype */ 445*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 446*ae771770SStanislav Sedov /* encrypted key (or plaintext salt) */ 447*ae771770SStanislav Sedov CHECK(ret = krb5_ret_uint16(sp, &u16)); 448*ae771770SStanislav Sedov krb5_storage_seek(sp, u16, SEEK_CUR); 449*ae771770SStanislav Sedov } 450*ae771770SStanislav Sedov } 451*ae771770SStanislav Sedov } 452*ae771770SStanislav Sedov 453*ae771770SStanislav Sedov if (entry->kvno == 0 && kvno != 0) { 454*ae771770SStanislav Sedov ret = HDB_ERR_NOT_FOUND_HERE; 455*ae771770SStanislav Sedov goto out; 456*ae771770SStanislav Sedov } 457*ae771770SStanislav Sedov 458*ae771770SStanislav Sedov return 0; 459*ae771770SStanislav Sedov out: 460*ae771770SStanislav Sedov if (ret == HEIM_ERR_EOF) 461*ae771770SStanislav Sedov /* Better error code than "end of file" */ 462*ae771770SStanislav Sedov ret = HEIM_ERR_BAD_HDBENT_ENCODING; 463*ae771770SStanislav Sedov return ret; 464*ae771770SStanislav Sedov } 465*ae771770SStanislav Sedov 466*ae771770SStanislav Sedov #if 0 467*ae771770SStanislav Sedov static krb5_error_code 468*ae771770SStanislav Sedov mdb_entry2value(krb5_context context, hdb_entry *entry, krb5_data *data) 469*ae771770SStanislav Sedov { 470*ae771770SStanislav Sedov return EINVAL; 471*ae771770SStanislav Sedov } 472*ae771770SStanislav Sedov #endif 473*ae771770SStanislav Sedov 474*ae771770SStanislav Sedov 475*ae771770SStanislav Sedov static krb5_error_code 476*ae771770SStanislav Sedov mdb_close(krb5_context context, HDB *db) 477*ae771770SStanislav Sedov { 478*ae771770SStanislav Sedov DB *d = (DB*)db->hdb_db; 479*ae771770SStanislav Sedov (*d->close)(d); 480*ae771770SStanislav Sedov return 0; 481*ae771770SStanislav Sedov } 482*ae771770SStanislav Sedov 483*ae771770SStanislav Sedov static krb5_error_code 484*ae771770SStanislav Sedov mdb_destroy(krb5_context context, HDB *db) 485*ae771770SStanislav Sedov { 486*ae771770SStanislav Sedov krb5_error_code ret; 487*ae771770SStanislav Sedov 488*ae771770SStanislav Sedov ret = hdb_clear_master_key (context, db); 489*ae771770SStanislav Sedov free(db->hdb_name); 490*ae771770SStanislav Sedov free(db); 491*ae771770SStanislav Sedov return ret; 492*ae771770SStanislav Sedov } 493*ae771770SStanislav Sedov 494*ae771770SStanislav Sedov static krb5_error_code 495*ae771770SStanislav Sedov mdb_lock(krb5_context context, HDB *db, int operation) 496*ae771770SStanislav Sedov { 497*ae771770SStanislav Sedov DB *d = (DB*)db->hdb_db; 498*ae771770SStanislav Sedov int fd = (*d->fd)(d); 499*ae771770SStanislav Sedov if(fd < 0) { 500*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 501*ae771770SStanislav Sedov "Can't lock database: %s", db->hdb_name); 502*ae771770SStanislav Sedov return HDB_ERR_CANT_LOCK_DB; 503*ae771770SStanislav Sedov } 504*ae771770SStanislav Sedov return hdb_lock(fd, operation); 505*ae771770SStanislav Sedov } 506*ae771770SStanislav Sedov 507*ae771770SStanislav Sedov static krb5_error_code 508*ae771770SStanislav Sedov mdb_unlock(krb5_context context, HDB *db) 509*ae771770SStanislav Sedov { 510*ae771770SStanislav Sedov DB *d = (DB*)db->hdb_db; 511*ae771770SStanislav Sedov int fd = (*d->fd)(d); 512*ae771770SStanislav Sedov if(fd < 0) { 513*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 514*ae771770SStanislav Sedov "Can't unlock database: %s", db->hdb_name); 515*ae771770SStanislav Sedov return HDB_ERR_CANT_LOCK_DB; 516*ae771770SStanislav Sedov } 517*ae771770SStanislav Sedov return hdb_unlock(fd); 518*ae771770SStanislav Sedov } 519*ae771770SStanislav Sedov 520*ae771770SStanislav Sedov 521*ae771770SStanislav Sedov static krb5_error_code 522*ae771770SStanislav Sedov mdb_seq(krb5_context context, HDB *db, 523*ae771770SStanislav Sedov unsigned flags, hdb_entry_ex *entry, int flag) 524*ae771770SStanislav Sedov { 525*ae771770SStanislav Sedov DB *d = (DB*)db->hdb_db; 526*ae771770SStanislav Sedov DBT key, value; 527*ae771770SStanislav Sedov krb5_data key_data, data; 528*ae771770SStanislav Sedov int code; 529*ae771770SStanislav Sedov 530*ae771770SStanislav Sedov code = db->hdb_lock(context, db, HDB_RLOCK); 531*ae771770SStanislav Sedov if(code == -1) { 532*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); 533*ae771770SStanislav Sedov return HDB_ERR_DB_INUSE; 534*ae771770SStanislav Sedov } 535*ae771770SStanislav Sedov code = (*d->seq)(d, &key, &value, flag); 536*ae771770SStanislav Sedov db->hdb_unlock(context, db); /* XXX check value */ 537*ae771770SStanislav Sedov if(code == -1) { 538*ae771770SStanislav Sedov code = errno; 539*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s seq error: %s", 540*ae771770SStanislav Sedov db->hdb_name, strerror(code)); 541*ae771770SStanislav Sedov return code; 542*ae771770SStanislav Sedov } 543*ae771770SStanislav Sedov if(code == 1) { 544*ae771770SStanislav Sedov krb5_clear_error_message(context); 545*ae771770SStanislav Sedov return HDB_ERR_NOENTRY; 546*ae771770SStanislav Sedov } 547*ae771770SStanislav Sedov 548*ae771770SStanislav Sedov key_data.data = key.data; 549*ae771770SStanislav Sedov key_data.length = key.size; 550*ae771770SStanislav Sedov data.data = value.data; 551*ae771770SStanislav Sedov data.length = value.size; 552*ae771770SStanislav Sedov memset(entry, 0, sizeof(*entry)); 553*ae771770SStanislav Sedov 554*ae771770SStanislav Sedov if (mdb_value2entry(context, &data, 0, &entry->entry)) 555*ae771770SStanislav Sedov return mdb_seq(context, db, flags, entry, R_NEXT); 556*ae771770SStanislav Sedov 557*ae771770SStanislav Sedov if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 558*ae771770SStanislav Sedov code = hdb_unseal_keys (context, db, &entry->entry); 559*ae771770SStanislav Sedov if (code) 560*ae771770SStanislav Sedov hdb_free_entry (context, entry); 561*ae771770SStanislav Sedov } 562*ae771770SStanislav Sedov 563*ae771770SStanislav Sedov return code; 564*ae771770SStanislav Sedov } 565*ae771770SStanislav Sedov 566*ae771770SStanislav Sedov 567*ae771770SStanislav Sedov static krb5_error_code 568*ae771770SStanislav Sedov mdb_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 569*ae771770SStanislav Sedov { 570*ae771770SStanislav Sedov return mdb_seq(context, db, flags, entry, R_FIRST); 571*ae771770SStanislav Sedov } 572*ae771770SStanislav Sedov 573*ae771770SStanislav Sedov 574*ae771770SStanislav Sedov static krb5_error_code 575*ae771770SStanislav Sedov mdb_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 576*ae771770SStanislav Sedov { 577*ae771770SStanislav Sedov return mdb_seq(context, db, flags, entry, R_NEXT); 578*ae771770SStanislav Sedov } 579*ae771770SStanislav Sedov 580*ae771770SStanislav Sedov static krb5_error_code 581*ae771770SStanislav Sedov mdb_rename(krb5_context context, HDB *db, const char *new_name) 582*ae771770SStanislav Sedov { 583*ae771770SStanislav Sedov int ret; 584*ae771770SStanislav Sedov char *old, *new; 585*ae771770SStanislav Sedov 586*ae771770SStanislav Sedov asprintf(&old, "%s.db", db->hdb_name); 587*ae771770SStanislav Sedov asprintf(&new, "%s.db", new_name); 588*ae771770SStanislav Sedov ret = rename(old, new); 589*ae771770SStanislav Sedov free(old); 590*ae771770SStanislav Sedov free(new); 591*ae771770SStanislav Sedov if(ret) 592*ae771770SStanislav Sedov return errno; 593*ae771770SStanislav Sedov 594*ae771770SStanislav Sedov free(db->hdb_name); 595*ae771770SStanislav Sedov db->hdb_name = strdup(new_name); 596*ae771770SStanislav Sedov return 0; 597*ae771770SStanislav Sedov } 598*ae771770SStanislav Sedov 599*ae771770SStanislav Sedov static krb5_error_code 600*ae771770SStanislav Sedov mdb__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 601*ae771770SStanislav Sedov { 602*ae771770SStanislav Sedov DB *d = (DB*)db->hdb_db; 603*ae771770SStanislav Sedov DBT k, v; 604*ae771770SStanislav Sedov int code; 605*ae771770SStanislav Sedov 606*ae771770SStanislav Sedov k.data = key.data; 607*ae771770SStanislav Sedov k.size = key.length; 608*ae771770SStanislav Sedov code = db->hdb_lock(context, db, HDB_RLOCK); 609*ae771770SStanislav Sedov if(code) 610*ae771770SStanislav Sedov return code; 611*ae771770SStanislav Sedov code = (*d->get)(d, &k, &v, 0); 612*ae771770SStanislav Sedov db->hdb_unlock(context, db); 613*ae771770SStanislav Sedov if(code < 0) { 614*ae771770SStanislav Sedov code = errno; 615*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s get error: %s", 616*ae771770SStanislav Sedov db->hdb_name, strerror(code)); 617*ae771770SStanislav Sedov return code; 618*ae771770SStanislav Sedov } 619*ae771770SStanislav Sedov if(code == 1) { 620*ae771770SStanislav Sedov krb5_clear_error_message(context); 621*ae771770SStanislav Sedov return HDB_ERR_NOENTRY; 622*ae771770SStanislav Sedov } 623*ae771770SStanislav Sedov 624*ae771770SStanislav Sedov krb5_data_copy(reply, v.data, v.size); 625*ae771770SStanislav Sedov return 0; 626*ae771770SStanislav Sedov } 627*ae771770SStanislav Sedov 628*ae771770SStanislav Sedov static krb5_error_code 629*ae771770SStanislav Sedov mdb__put(krb5_context context, HDB *db, int replace, 630*ae771770SStanislav Sedov krb5_data key, krb5_data value) 631*ae771770SStanislav Sedov { 632*ae771770SStanislav Sedov DB *d = (DB*)db->hdb_db; 633*ae771770SStanislav Sedov DBT k, v; 634*ae771770SStanislav Sedov int code; 635*ae771770SStanislav Sedov 636*ae771770SStanislav Sedov k.data = key.data; 637*ae771770SStanislav Sedov k.size = key.length; 638*ae771770SStanislav Sedov v.data = value.data; 639*ae771770SStanislav Sedov v.size = value.length; 640*ae771770SStanislav Sedov code = db->hdb_lock(context, db, HDB_WLOCK); 641*ae771770SStanislav Sedov if(code) 642*ae771770SStanislav Sedov return code; 643*ae771770SStanislav Sedov code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 644*ae771770SStanislav Sedov db->hdb_unlock(context, db); 645*ae771770SStanislav Sedov if(code < 0) { 646*ae771770SStanislav Sedov code = errno; 647*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s put error: %s", 648*ae771770SStanislav Sedov db->hdb_name, strerror(code)); 649*ae771770SStanislav Sedov return code; 650*ae771770SStanislav Sedov } 651*ae771770SStanislav Sedov if(code == 1) { 652*ae771770SStanislav Sedov krb5_clear_error_message(context); 653*ae771770SStanislav Sedov return HDB_ERR_EXISTS; 654*ae771770SStanislav Sedov } 655*ae771770SStanislav Sedov return 0; 656*ae771770SStanislav Sedov } 657*ae771770SStanislav Sedov 658*ae771770SStanislav Sedov static krb5_error_code 659*ae771770SStanislav Sedov mdb__del(krb5_context context, HDB *db, krb5_data key) 660*ae771770SStanislav Sedov { 661*ae771770SStanislav Sedov DB *d = (DB*)db->hdb_db; 662*ae771770SStanislav Sedov DBT k; 663*ae771770SStanislav Sedov krb5_error_code code; 664*ae771770SStanislav Sedov k.data = key.data; 665*ae771770SStanislav Sedov k.size = key.length; 666*ae771770SStanislav Sedov code = db->hdb_lock(context, db, HDB_WLOCK); 667*ae771770SStanislav Sedov if(code) 668*ae771770SStanislav Sedov return code; 669*ae771770SStanislav Sedov code = (*d->del)(d, &k, 0); 670*ae771770SStanislav Sedov db->hdb_unlock(context, db); 671*ae771770SStanislav Sedov if(code == 1) { 672*ae771770SStanislav Sedov code = errno; 673*ae771770SStanislav Sedov krb5_set_error_message(context, code, "Database %s put error: %s", 674*ae771770SStanislav Sedov db->hdb_name, strerror(code)); 675*ae771770SStanislav Sedov return code; 676*ae771770SStanislav Sedov } 677*ae771770SStanislav Sedov if(code < 0) 678*ae771770SStanislav Sedov return errno; 679*ae771770SStanislav Sedov return 0; 680*ae771770SStanislav Sedov } 681*ae771770SStanislav Sedov 682*ae771770SStanislav Sedov static krb5_error_code 683*ae771770SStanislav Sedov mdb_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, 684*ae771770SStanislav Sedov unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) 685*ae771770SStanislav Sedov { 686*ae771770SStanislav Sedov krb5_data key, value; 687*ae771770SStanislav Sedov krb5_error_code code; 688*ae771770SStanislav Sedov 689*ae771770SStanislav Sedov code = mdb_principal2key(context, principal, &key); 690*ae771770SStanislav Sedov if (code) 691*ae771770SStanislav Sedov return code; 692*ae771770SStanislav Sedov code = db->hdb__get(context, db, key, &value); 693*ae771770SStanislav Sedov krb5_data_free(&key); 694*ae771770SStanislav Sedov if(code) 695*ae771770SStanislav Sedov return code; 696*ae771770SStanislav Sedov code = mdb_value2entry(context, &value, kvno, &entry->entry); 697*ae771770SStanislav Sedov krb5_data_free(&value); 698*ae771770SStanislav Sedov if (code) 699*ae771770SStanislav Sedov return code; 700*ae771770SStanislav Sedov 701*ae771770SStanislav Sedov if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 702*ae771770SStanislav Sedov code = hdb_unseal_keys (context, db, &entry->entry); 703*ae771770SStanislav Sedov if (code) 704*ae771770SStanislav Sedov hdb_free_entry(context, entry); 705*ae771770SStanislav Sedov } 706*ae771770SStanislav Sedov 707*ae771770SStanislav Sedov return 0; 708*ae771770SStanislav Sedov } 709*ae771770SStanislav Sedov 710*ae771770SStanislav Sedov static krb5_error_code 711*ae771770SStanislav Sedov mdb_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 712*ae771770SStanislav Sedov { 713*ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, "can't set principal in mdb"); 714*ae771770SStanislav Sedov return EINVAL; 715*ae771770SStanislav Sedov } 716*ae771770SStanislav Sedov 717*ae771770SStanislav Sedov static krb5_error_code 718*ae771770SStanislav Sedov mdb_remove(krb5_context context, HDB *db, krb5_const_principal principal) 719*ae771770SStanislav Sedov { 720*ae771770SStanislav Sedov krb5_error_code code; 721*ae771770SStanislav Sedov krb5_data key; 722*ae771770SStanislav Sedov 723*ae771770SStanislav Sedov mdb_principal2key(context, principal, &key); 724*ae771770SStanislav Sedov code = db->hdb__del(context, db, key); 725*ae771770SStanislav Sedov krb5_data_free(&key); 726*ae771770SStanislav Sedov return code; 727*ae771770SStanislav Sedov } 728*ae771770SStanislav Sedov 729*ae771770SStanislav Sedov static krb5_error_code 730*ae771770SStanislav Sedov mdb_open(krb5_context context, HDB *db, int flags, mode_t mode) 731*ae771770SStanislav Sedov { 732*ae771770SStanislav Sedov char *fn; 733*ae771770SStanislav Sedov krb5_error_code ret; 734*ae771770SStanislav Sedov 735*ae771770SStanislav Sedov asprintf(&fn, "%s.db", db->hdb_name); 736*ae771770SStanislav Sedov if (fn == NULL) { 737*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 738*ae771770SStanislav Sedov return ENOMEM; 739*ae771770SStanislav Sedov } 740*ae771770SStanislav Sedov db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); 741*ae771770SStanislav Sedov free(fn); 742*ae771770SStanislav Sedov 743*ae771770SStanislav Sedov if (db->hdb_db == NULL) { 744*ae771770SStanislav Sedov switch (errno) { 745*ae771770SStanislav Sedov #ifdef EFTYPE 746*ae771770SStanislav Sedov case EFTYPE: 747*ae771770SStanislav Sedov #endif 748*ae771770SStanislav Sedov case EINVAL: 749*ae771770SStanislav Sedov db->hdb_db = dbopen(fn, flags, mode, DB_BTREE, NULL); 750*ae771770SStanislav Sedov } 751*ae771770SStanislav Sedov } 752*ae771770SStanislav Sedov 753*ae771770SStanislav Sedov /* try to open without .db extension */ 754*ae771770SStanislav Sedov if(db->hdb_db == NULL && errno == ENOENT) 755*ae771770SStanislav Sedov db->hdb_db = dbopen(db->hdb_name, flags, mode, DB_BTREE, NULL); 756*ae771770SStanislav Sedov if(db->hdb_db == NULL) { 757*ae771770SStanislav Sedov ret = errno; 758*ae771770SStanislav Sedov krb5_set_error_message(context, ret, "dbopen (%s): %s", 759*ae771770SStanislav Sedov db->hdb_name, strerror(ret)); 760*ae771770SStanislav Sedov return ret; 761*ae771770SStanislav Sedov } 762*ae771770SStanislav Sedov if((flags & O_ACCMODE) == O_RDONLY) 763*ae771770SStanislav Sedov ret = hdb_check_db_format(context, db); 764*ae771770SStanislav Sedov else 765*ae771770SStanislav Sedov ret = hdb_init_db(context, db); 766*ae771770SStanislav Sedov if(ret == HDB_ERR_NOENTRY) { 767*ae771770SStanislav Sedov krb5_clear_error_message(context); 768*ae771770SStanislav Sedov return 0; 769*ae771770SStanislav Sedov } 770*ae771770SStanislav Sedov if (ret) { 771*ae771770SStanislav Sedov mdb_close(context, db); 772*ae771770SStanislav Sedov krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 773*ae771770SStanislav Sedov (flags & O_ACCMODE) == O_RDONLY ? 774*ae771770SStanislav Sedov "checking format of" : "initialize", 775*ae771770SStanislav Sedov db->hdb_name); 776*ae771770SStanislav Sedov } 777*ae771770SStanislav Sedov return ret; 778*ae771770SStanislav Sedov } 779*ae771770SStanislav Sedov 780*ae771770SStanislav Sedov krb5_error_code 781*ae771770SStanislav Sedov hdb_mdb_create(krb5_context context, HDB **db, 782*ae771770SStanislav Sedov const char *filename) 783*ae771770SStanislav Sedov { 784*ae771770SStanislav Sedov *db = calloc(1, sizeof(**db)); 785*ae771770SStanislav Sedov if (*db == NULL) { 786*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 787*ae771770SStanislav Sedov return ENOMEM; 788*ae771770SStanislav Sedov } 789*ae771770SStanislav Sedov 790*ae771770SStanislav Sedov (*db)->hdb_db = NULL; 791*ae771770SStanislav Sedov (*db)->hdb_name = strdup(filename); 792*ae771770SStanislav Sedov if ((*db)->hdb_name == NULL) { 793*ae771770SStanislav Sedov free(*db); 794*ae771770SStanislav Sedov *db = NULL; 795*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 796*ae771770SStanislav Sedov return ENOMEM; 797*ae771770SStanislav Sedov } 798*ae771770SStanislav Sedov (*db)->hdb_master_key_set = 0; 799*ae771770SStanislav Sedov (*db)->hdb_openp = 0; 800*ae771770SStanislav Sedov (*db)->hdb_capability_flags = 0; 801*ae771770SStanislav Sedov (*db)->hdb_open = mdb_open; 802*ae771770SStanislav Sedov (*db)->hdb_close = mdb_close; 803*ae771770SStanislav Sedov (*db)->hdb_fetch_kvno = mdb_fetch_kvno; 804*ae771770SStanislav Sedov (*db)->hdb_store = mdb_store; 805*ae771770SStanislav Sedov (*db)->hdb_remove = mdb_remove; 806*ae771770SStanislav Sedov (*db)->hdb_firstkey = mdb_firstkey; 807*ae771770SStanislav Sedov (*db)->hdb_nextkey= mdb_nextkey; 808*ae771770SStanislav Sedov (*db)->hdb_lock = mdb_lock; 809*ae771770SStanislav Sedov (*db)->hdb_unlock = mdb_unlock; 810*ae771770SStanislav Sedov (*db)->hdb_rename = mdb_rename; 811*ae771770SStanislav Sedov (*db)->hdb__get = mdb__get; 812*ae771770SStanislav Sedov (*db)->hdb__put = mdb__put; 813*ae771770SStanislav Sedov (*db)->hdb__del = mdb__del; 814*ae771770SStanislav Sedov (*db)->hdb_destroy = mdb_destroy; 815*ae771770SStanislav Sedov return 0; 816*ae771770SStanislav Sedov } 817*ae771770SStanislav Sedov 818*ae771770SStanislav Sedov #endif /* HAVE_DB1 */ 819