static krb5_error_code hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry) { hdb_keytab k = (hdb_keytab)db->hdb_db; krb5_error_code ret; krb5_keytab_entry ktentry; if (!(flags & HDB_F_KVNO_SPECIFIED)) { /* Preserve previous behaviour if no kvno specified */ kvno = 0; } memset(&ktentry, 0, sizeof(ktentry)); entry->entry.flags.server = 1; entry->entry.flags.forwardable = 1; entry->entry.flags.renewable = 1; /* Not recorded in the OD backend, make something up */ ret = krb5_parse_name(context, "hdb/keytab@WELL-KNOWN:KEYTAB-BACKEND", &entry->entry.created_by.principal); if (ret) goto out; /* * XXX really needs to try all enctypes and just not pick the * first one, even if that happens to be des3-cbc-sha1 (ie best * enctype) in the Apple case. A while loop over all known * enctypes should work. */ ret = krb5_kt_get_entry(context, k->keytab, principal, kvno, 0, &ktentry); if (ret) { ret = HDB_ERR_NOENTRY; goto out; } ret = krb5_copy_principal(context, principal, &entry->entry.principal); if (ret) goto out; ret = _hdb_keytab2hdb_entry(context, &ktentry, entry); out: if (ret) { free_hdb_entry(&entry->entry); memset(&entry->entry, 0, sizeof(entry->entry)); } krb5_kt_free_entry(context, &ktentry); return ret; }
void hdb_free_entry(krb5_context context, hdb_entry_ex *ent) { int i; if (ent->free_entry) (*ent->free_entry)(context, ent); for(i = 0; i < ent->entry.keys.len; ++i) { Key *k = &ent->entry.keys.val[i]; memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); } free_hdb_entry(&ent->entry); }
static krb5_error_code mdb_value2entry(krb5_context context, krb5_data *data, hdb_entry *entry) { krb5_error_code ret; krb5_storage *sp; uint32_t u32; uint16_t u16, num_keys, num_tl; size_t i, j; char *p = NULL; sp = krb5_storage_from_data(data); if (sp == NULL) { krb5_set_error_message(context, ENOMEM, "out of memory"); return ENOMEM; } krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); /* 16: baselength */ CHECK(ret = krb5_ret_uint16(sp, &u16)); if (u16 != KDB_V1_BASE_LENGTH) { ret = EINVAL; goto out; } /* 32: attributes */ CHECK(ret = krb5_ret_uint32(sp, &u32)); entry->flags.postdate = !(u16 & KRB5_KDB_DISALLOW_POSTDATED); entry->flags.forwardable = !(u16 & KRB5_KDB_DISALLOW_FORWARDABLE); entry->flags.initial = !!(u16 & KRB5_KDB_DISALLOW_TGT_BASED); entry->flags.renewable = !(u16 & KRB5_KDB_DISALLOW_RENEWABLE); entry->flags.proxiable = !(u16 & KRB5_KDB_DISALLOW_PROXIABLE); /* DUP_SKEY */ entry->flags.invalid = !!(u16 & KRB5_KDB_DISALLOW_ALL_TIX); entry->flags.require_preauth =!!(u16 & KRB5_KDB_REQUIRES_PRE_AUTH); entry->flags.require_hwauth =!!(u16 & KRB5_KDB_REQUIRES_HW_AUTH); entry->flags.server = !(u16 & KRB5_KDB_DISALLOW_SVR); entry->flags.change_pw = !!(u16 & KRB5_KDB_PWCHANGE_SERVICE); entry->flags.client = 1; /* XXX */ /* 32: max time */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->max_life = malloc(sizeof(*entry->max_life)); *entry->max_life = u32; } /* 32: max renewable time */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->max_renew = malloc(sizeof(*entry->max_renew)); *entry->max_renew = u32; } /* 32: client expire */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->valid_end = malloc(sizeof(*entry->valid_end)); *entry->valid_end = u32; } /* 32: passwd expire */ CHECK(ret = krb5_ret_uint32(sp, &u32)); if (u32) { entry->pw_end = malloc(sizeof(*entry->pw_end)); *entry->pw_end = u32; } /* 32: last successful passwd */ CHECK(ret = krb5_ret_uint32(sp, &u32)); /* 32: last failed attempt */ CHECK(ret = krb5_ret_uint32(sp, &u32)); /* 32: num of failed attempts */ CHECK(ret = krb5_ret_uint32(sp, &u32)); /* 16: num tl data */ CHECK(ret = krb5_ret_uint16(sp, &u16)); num_tl = u16; /* 16: num key data */ CHECK(ret = krb5_ret_uint16(sp, &u16)); num_keys = u16; /* 16: principal length */ CHECK(ret = krb5_ret_uint16(sp, &u16)); /* length: principal */ { p = malloc(u16 + 1); krb5_storage_read(sp, p, u16); p[u16] = '\0'; CHECK(ret = krb5_parse_name(context, p, &entry->principal)); free(p); p = NULL; } /* for num tl data times 16: tl data type 16: tl data length length: length */ for (i = 0; i < num_tl; i++) { CHECK(ret = krb5_ret_uint16(sp, &u16)); CHECK(ret = krb5_ret_uint16(sp, &u16)); krb5_storage_seek(sp, u16, SEEK_CUR); } /* for num key data times 16: version (num keyblocks) 16: kvno for version times: 16: type 16: length length: keydata */ for (i = 0; i < num_keys; i++) { int keep = 0; uint16_t version; void *ptr; CHECK(ret = krb5_ret_uint16(sp, &u16)); version = u16; CHECK(ret = krb5_ret_uint16(sp, &u16)); if (entry->kvno < u16) { keep = 1; entry->kvno = u16; for (j = 0; j < entry->keys.len; j++) { free_Key(&entry->keys.val[j]); free(entry->keys.val); entry->keys.len = 0; entry->keys.val = NULL; } } else if (entry->kvno == u16) keep = 1; if (keep) { Key *k; ptr = realloc(entry->keys.val, sizeof(entry->keys.val[0]) * (entry->keys.len + 1)); if (ptr == NULL) { ret = ENOMEM; goto out; } entry->keys.val = ptr; /* k points to current Key */ k = &entry->keys.val[entry->keys.len]; memset(k, 0, sizeof(*k)); entry->keys.len += 1; entry->keys.val[i].mkvno = malloc(sizeof(*entry->keys.val[i].mkvno)); if (entry->keys.val[i].mkvno == NULL) { ret = ENOMEM; goto out; } *entry->keys.val[i].mkvno = 1; for (j = 0; j < version; j++) { uint16_t type; CHECK(ret = krb5_ret_uint16(sp, &type)); CHECK(ret = krb5_ret_uint16(sp, &u16)); if (j == 0) { /* key */ k->key.keytype = type; if (u16 < 2) { ret = EINVAL; goto out; } krb5_storage_seek(sp, 2, SEEK_CUR); /* skip real length */ k->key.keyvalue.length = u16 - 2; k->key.keyvalue.data = malloc(k->key.keyvalue.length); krb5_storage_read(sp, k->key.keyvalue.data, k->key.keyvalue.length); } else if (j == 1) { /* salt */ k->salt = calloc(1, sizeof(*k->salt)); if (k->salt == NULL) { ret = ENOMEM; goto out; } k->salt->type = type; if (u16 != 0) { k->salt->salt.data = malloc(u16); if (k->salt->salt.data == NULL) { ret = ENOMEM; goto out; } k->salt->salt.length = u16; krb5_storage_read(sp, k->salt->salt.data, k->salt->salt.length); } fix_salt(context, entry, entry->keys.len - 1); } else { krb5_storage_seek(sp, u16, SEEK_CUR); } } } else { /* skip */ for (j = 0; j < version; j++) { CHECK(ret = krb5_ret_uint16(sp, &u16)); CHECK(ret = krb5_ret_uint16(sp, &u16)); krb5_storage_seek(sp, u16, u16); } } } return 0; out: if (p) free(p); free_hdb_entry(entry); return ret; }
static void print_entry(kadm5_server_context *server_context, uint32_t ver, time_t timestamp, enum kadm_ops op, uint32_t len, krb5_storage *sp, void *ctx) { char t[256]; int32_t mask; hdb_entry ent; krb5_principal source; char *name1, *name2; krb5_data data; krb5_context scontext = server_context->context; off_t end = krb5_storage_seek(sp, 0, SEEK_CUR) + len; krb5_error_code ret; strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); if((int)op < (int)kadm_get || (int)op > (int)kadm_nop) { printf("unknown op: %d\n", op); krb5_storage_seek(sp, end, SEEK_SET); return; } printf ("%s: ver = %u, timestamp = %s, len = %u\n", op_names[op], ver, t, len); switch(op) { case kadm_delete: krb5_ret_principal(sp, &source); krb5_unparse_name(scontext, source, &name1); printf(" %s\n", name1); free(name1); krb5_free_principal(scontext, source); break; case kadm_rename: ret = krb5_data_alloc(&data, len); if (ret) krb5_err (scontext, 1, ret, "kadm_rename: data alloc: %d", len); krb5_ret_principal(sp, &source); krb5_storage_read(sp, data.data, data.length); hdb_value2entry(scontext, &data, &ent); krb5_unparse_name(scontext, source, &name1); krb5_unparse_name(scontext, ent.principal, &name2); printf(" %s -> %s\n", name1, name2); free(name1); free(name2); krb5_free_principal(scontext, source); free_hdb_entry(&ent); break; case kadm_create: ret = krb5_data_alloc(&data, len); if (ret) krb5_err (scontext, 1, ret, "kadm_create: data alloc: %d", len); krb5_storage_read(sp, data.data, data.length); ret = hdb_value2entry(scontext, &data, &ent); if(ret) abort(); mask = ~0; goto foo; case kadm_modify: ret = krb5_data_alloc(&data, len); if (ret) krb5_err (scontext, 1, ret, "kadm_modify: data alloc: %d", len); krb5_ret_int32(sp, &mask); krb5_storage_read(sp, data.data, data.length); ret = hdb_value2entry(scontext, &data, &ent); if(ret) abort(); foo: if(ent.principal /* mask & KADM5_PRINCIPAL */) { krb5_unparse_name(scontext, ent.principal, &name1); printf(" principal = %s\n", name1); free(name1); } if(mask & KADM5_PRINC_EXPIRE_TIME) { if(ent.valid_end == NULL) { strlcpy(t, "never", sizeof(t)); } else { strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(ent.valid_end)); } printf(" expires = %s\n", t); } if(mask & KADM5_PW_EXPIRATION) { if(ent.pw_end == NULL) { strlcpy(t, "never", sizeof(t)); } else { strftime(t, sizeof(t), "%Y-%m-%d %H:%M:%S", localtime(ent.pw_end)); } printf(" password exp = %s\n", t); } if(mask & KADM5_LAST_PWD_CHANGE) { } if(mask & KADM5_ATTRIBUTES) { unparse_flags(HDBFlags2int(ent.flags), asn1_HDBFlags_units(), t, sizeof(t)); printf(" attributes = %s\n", t); } if(mask & KADM5_MAX_LIFE) { if(ent.max_life == NULL) strlcpy(t, "for ever", sizeof(t)); else unparse_time(*ent.max_life, t, sizeof(t)); printf(" max life = %s\n", t); } if(mask & KADM5_MAX_RLIFE) { if(ent.max_renew == NULL) strlcpy(t, "for ever", sizeof(t)); else unparse_time(*ent.max_renew, t, sizeof(t)); printf(" max rlife = %s\n", t); } if(mask & KADM5_MOD_TIME) { printf(" mod time\n"); } if(mask & KADM5_MOD_NAME) { printf(" mod name\n"); } if(mask & KADM5_KVNO) { printf(" kvno = %d\n", ent.kvno); } if(mask & KADM5_MKVNO) { printf(" mkvno\n"); } if(mask & KADM5_AUX_ATTRIBUTES) { printf(" aux attributes\n"); } if(mask & KADM5_POLICY) { printf(" policy\n"); } if(mask & KADM5_POLICY_CLR) { printf(" mod time\n"); } if(mask & KADM5_LAST_SUCCESS) { printf(" last success\n"); } if(mask & KADM5_LAST_FAILED) { printf(" last failed\n"); } if(mask & KADM5_FAIL_AUTH_COUNT) { printf(" fail auth count\n"); } if(mask & KADM5_KEY_DATA) { printf(" key data\n"); } if(mask & KADM5_TL_DATA) { printf(" tl data\n"); } free_hdb_entry(&ent); break; case kadm_nop : break; default: abort(); } krb5_storage_seek(sp, end, SEEK_SET); }