kadm5_ret_t kadm5_s_create_principal_with_key(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask) { kadm5_ret_t ret; hdb_entry_ex ent; kadm5_server_context *context = server_handle; if ((mask & KADM5_KVNO) == 0) { /* create_principal() through _kadm5_setup_entry(), will need this */ princ->kvno = 1; mask |= KADM5_KVNO; } ret = create_principal(context, princ, mask, &ent, KADM5_PRINCIPAL | KADM5_KEY_DATA, KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_MKVNO | KADM5_AUX_ATTRIBUTES | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); if (ret) return ret; if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if (ret) { hdb_free_entry(context->context, &ent); return ret; } } ret = kadm5_log_init(context); if (ret) goto out; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; /* This logs the change for iprop and writes to the HDB */ ret = kadm5_log_create(context, &ent.entry); out2: (void) kadm5_log_end(context); out: if (!context->keep_open) { kadm5_ret_t ret2; ret2 = context->db->hdb_close(context->context, context->db); if (ret == 0 && ret2 != 0) ret = ret2; } hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
static krb5_error_code DB_seq(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry, int flag) { DB *d = (DB*)db->hdb_db; DBT key, value; krb5_data key_data, data; int code; code = db->hdb_lock(context, db, HDB_RLOCK); if(code == -1) { krb5_set_error_message(context, HDB_ERR_DB_INUSE, "Database %s in use", db->hdb_name); return HDB_ERR_DB_INUSE; } code = (*d->seq)(d, &key, &value, flag); db->hdb_unlock(context, db); /* XXX check value */ if(code == -1) { code = errno; krb5_set_error_message(context, code, "Database %s seq error: %s", db->hdb_name, strerror(code)); return code; } if(code == 1) { krb5_clear_error_message(context); return HDB_ERR_NOENTRY; } key_data.data = key.data; key_data.length = key.size; data.data = value.data; data.length = value.size; memset(entry, 0, sizeof(*entry)); if (hdb_value2entry(context, &data, &entry->entry)) return DB_seq(context, db, flags, entry, R_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { code = hdb_unseal_keys (context, db, &entry->entry); if (code) hdb_free_entry (context, entry); } if (code == 0 && entry->entry.principal == NULL) { entry->entry.principal = malloc(sizeof(*entry->entry.principal)); if (entry->entry.principal == NULL) { code = ENOMEM; krb5_set_error_message(context, code, "malloc: out of memory"); hdb_free_entry (context, entry); } else { hdb_key2principal(context, &key_data, entry->entry.principal); } } return code; }
static krb5_error_code LDAP_fetch(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry) { LDAPMessage *msg, *e; krb5_error_code ret; ret = LDAP_principal2message(context, db, entry->principal, &msg); if (ret) return ret; e = ldap_first_entry(HDB2LDAP(db), msg); if (e == NULL) { ret = HDB_ERR_NOENTRY; goto out; } ret = LDAP_message2entry(context, db, e, entry); if (ret == 0) { if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { ret = hdb_unseal_keys(context, db, entry); if (ret) hdb_free_entry(context,entry); } } out: ldap_msgfree(msg); return ret; }
static krb5_error_code mdb_fetch(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, hdb_entry_ex *entry) { krb5_data key, value; krb5_error_code code; code = mdb_principal2key(context, principal, &key); if (code) return code; code = db->hdb__get(context, db, key, &value); krb5_data_free(&key); if(code) return code; code = mdb_value2entry(context, &value, &entry->entry); krb5_data_free(&value); if (code) return code; if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { code = hdb_unseal_keys (context, db, &entry->entry); if (code) hdb_free_entry(context, entry); } return 0; }
static kadm5_ret_t kadm5_log_replay_create (kadm5_server_context *context, uint32_t ver, uint32_t len, krb5_storage *sp) { krb5_error_code ret; krb5_data data; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); ret = krb5_data_alloc (&data, len); if (ret) { krb5_set_error_message(context->context, ret, "out of memory"); return ret; } krb5_storage_read (sp, data.data, len); ret = hdb_value2entry (context->context, &data, &ent.entry); krb5_data_free(&data); if (ret) { krb5_set_error_message(context->context, ret, "Unmarshaling hdb entry failed"); return ret; } ret = context->db->hdb_store(context->context, context->db, 0, &ent); hdb_free_entry (context->context, &ent); return ret; }
/** * Retrieves an entry by searching for the given * principal in the Principal database table, both * for canonical principals and aliases. * * @param context The current krb5_context * @param db Heimdal database handle * @param principal The principal whose entry to search for * @param flags Currently only for HDB_F_DECRYPT * * @return 0 if everything worked, an error code if not */ static krb5_error_code hdb_sqlite_fetch(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, hdb_entry_ex *entry) { int sqlite_error; krb5_error_code ret; char *principal_string; hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); sqlite3_stmt *fetch = hsdb->fetch; krb5_data value; ret = krb5_unparse_name(context, principal, &principal_string); if (ret) { free(principal_string); return ret; } sqlite3_bind_text(fetch, 1, principal_string, -1, SQLITE_STATIC); sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch); if (sqlite_error != SQLITE_ROW) { if(sqlite_error == SQLITE_DONE) { ret = HDB_ERR_NOENTRY; goto out; } else { krb5_set_error_string(context, "sqlite fetch failed: %d", sqlite_error); ret = EINVAL; goto out; } } if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { ret = hdb_unseal_keys(context, db, &entry->entry); if(ret) { hdb_free_entry(context, entry); goto out; } } value.length = sqlite3_column_bytes(fetch, 0); value.data = (void *) sqlite3_column_blob(fetch, 0); ret = hdb_value2entry(context, &value, &entry->entry); if(ret) goto out; ret = 0; out: sqlite3_clear_bindings(fetch); sqlite3_reset(fetch); free(principal_string); return ret; }
static krb5_error_code NDBM_seq(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry, int first) { struct ndbm_db *d = (struct ndbm_db *)db->hdb_db; datum key, value; krb5_data key_data, data; krb5_error_code ret = 0; if(first) key = dbm_firstkey(d->db); else key = dbm_nextkey(d->db); if(key.dptr == NULL) return HDB_ERR_NOENTRY; key_data.data = key.dptr; key_data.length = key.dsize; ret = db->hdb_lock(context, db, HDB_RLOCK); if(ret) return ret; value = dbm_fetch(d->db, key); db->hdb_unlock(context, db); data.data = value.dptr; data.length = value.dsize; memset(entry, 0, sizeof(*entry)); if(hdb_value2entry(context, &data, &entry->entry)) return NDBM_seq(context, db, flags, entry, 0); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { ret = hdb_unseal_keys (context, db, &entry->entry); if (ret) hdb_free_entry (context, entry); } if (ret == 0 && entry->entry.principal == NULL) { entry->entry.principal = malloc (sizeof(*entry->entry.principal)); if (entry->entry.principal == NULL) { hdb_free_entry (context, entry); ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); } else { hdb_key2principal (context, &key_data, entry->entry.principal); } } return ret; }
static krb5_error_code DB_seq(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry, int flag) { DBT key, value; DBC *dbcp = db->hdb_dbc; krb5_data key_data, data; int code; memset(&key, 0, sizeof(DBT)); memset(&value, 0, sizeof(DBT)); if ((*db->hdb_lock)(context, db, HDB_RLOCK)) return HDB_ERR_DB_INUSE; code = (*dbcp->c_get)(dbcp, &key, &value, flag); (*db->hdb_unlock)(context, db); /* XXX check value */ if (code == DB_NOTFOUND) return HDB_ERR_NOENTRY; if (code) return code; key_data.data = key.data; key_data.length = key.size; data.data = value.data; data.length = value.size; memset(entry, 0, sizeof(*entry)); if (hdb_value2entry(context, &data, &entry->entry)) return DB_seq(context, db, flags, entry, DB_NEXT); if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { code = hdb_unseal_keys (context, db, &entry->entry); if (code) hdb_free_entry (context, entry); } if (entry->entry.principal == NULL) { entry->entry.principal = malloc(sizeof(*entry->entry.principal)); if (entry->entry.principal == NULL) { hdb_free_entry (context, entry); krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } else { hdb_key2principal(context, &key_data, entry->entry.principal); } } return 0; }
kadm5_ret_t kadm5_s_create_principal(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask, const char *password, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple) { kadm5_ret_t ret; hdb_entry_ex ent; kadm5_server_context *context = server_handle; if ((mask & KADM5_KVNO) == 0) { /* create_principal() through _kadm5_setup_entry(), will need this */ princ->kvno = 1; mask |= KADM5_KVNO; } ret = create_principal(context, princ, mask, &ent, KADM5_PRINCIPAL, KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_MKVNO | KADM5_AUX_ATTRIBUTES | KADM5_KEY_DATA | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); if(ret) goto out; ent.entry.keys.len = 0; ent.entry.keys.val = NULL; ret = _kadm5_set_keys(context, &ent.entry, password, n_ks_tuple, ks_tuple); if (ret) goto out; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out; if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) goto out; } ret = context->db->hdb_store(context->context, context->db, 0, &ent); if (!context->keep_open) context->db->hdb_close(context->context, context->db); if (ret) goto out; kadm5_log_create (context, &ent.entry); out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_chpass_principal_with_key(void *server_handle, krb5_principal princ, int n_key_data, krb5_key_data *key_data) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent); if(ret == HDB_ERR_NOENTRY) goto out; ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data); if(ret) goto out2; ent.entry.kvno++; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; ret = _kadm5_bump_pw_expire(context, &ent.entry); if (ret) goto out2; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
static kadm5_ret_t modify_principal(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask, uint32_t forbidden_mask) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; if((mask & forbidden_mask)) return KADM5_BAD_MASK; if((mask & KADM5_POLICY) && strcmp(princ->policy, "default")) return KADM5_UNK_POLICY; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch(context->context, context->db, princ->principal, HDB_F_GET_ANY, &ent); if(ret) goto out; ret = _kadm5_setup_entry(context, &ent, mask, princ, mask, NULL, 0); if(ret) goto out2; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, mask | KADM5_MOD_NAME | KADM5_MOD_TIME); out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_create_principal(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask, const char *password) { kadm5_ret_t ret; hdb_entry_ex ent; kadm5_server_context *context = server_handle; ret = create_principal(context, princ, mask, &ent, KADM5_PRINCIPAL, KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_MKVNO | KADM5_AUX_ATTRIBUTES | KADM5_KEY_DATA | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); if(ret) goto out; if ((mask & KADM5_KVNO) == 0) ent.entry.kvno = 1; ent.entry.keys.len = 0; ent.entry.keys.val = NULL; ret = _kadm5_set_keys(context, &ent.entry, password); if (ret) goto out; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out; ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) goto out; ret = context->db->hdb_store(context->context, context->db, 0, &ent); context->db->hdb_close(context->context, context->db); if (ret) goto out; kadm5_log_create (context, &ent.entry); out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
static int KRB5_CALLCONV hdb_end_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor) { struct hdb_cursor *c = cursor->data; if (!c->next) hdb_free_entry(context, &c->hdb_entry); (c->db->hdb_close)(context, c->db); (c->db->hdb_destroy)(context, c->db); free(c); return 0; }
static kadm5_ret_t kadm5_log_replay_rename (kadm5_server_context *context, uint32_t ver, uint32_t len, krb5_storage *sp) { krb5_error_code ret; krb5_principal source; hdb_entry_ex target_ent; krb5_data value; off_t off; size_t princ_len, data_len; memset(&target_ent, 0, sizeof(target_ent)); off = krb5_storage_seek(sp, 0, SEEK_CUR); ret = krb5_ret_principal (sp, &source); if (ret) { krb5_set_error_message(context->context, ret, "Failed to read renamed " "principal in log, version: %ld", (long)ver); return ret; } princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off; data_len = len - princ_len; ret = krb5_data_alloc (&value, data_len); if (ret) { krb5_free_principal (context->context, source); return ret; } krb5_storage_read (sp, value.data, data_len); ret = hdb_value2entry (context->context, &value, &target_ent.entry); krb5_data_free(&value); if (ret) { krb5_free_principal (context->context, source); return ret; } ret = context->db->hdb_store (context->context, context->db, 0, &target_ent); hdb_free_entry (context->context, &target_ent); if (ret) { krb5_free_principal (context->context, source); return ret; } ret = context->db->hdb_remove (context->context, context->db, source); krb5_free_principal (context->context, source); return ret; }
kadm5_ret_t kadm5_log_replay_rename (kadm5_server_context *context, u_int32_t ver, u_int32_t len, krb5_storage *sp) { krb5_error_code ret; krb5_principal source; hdb_entry source_ent, target_ent; krb5_data value; off_t off; size_t princ_len, data_len; off = krb5_storage_seek(sp, 0, SEEK_CUR); krb5_ret_principal (sp, &source); princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off; data_len = len - princ_len; ret = krb5_data_alloc (&value, data_len); if (ret) { krb5_free_principal (context->context, source); return ret; } krb5_storage_read (sp, value.data, data_len); ret = hdb_value2entry (context->context, &value, &target_ent); krb5_data_free(&value); if (ret) { krb5_free_principal (context->context, source); return ret; } ret = context->db->hdb_store (context->context, context->db, 0, &target_ent); hdb_free_entry (context->context, &target_ent); if (ret) { krb5_free_principal (context->context, source); return ret; } source_ent.principal = source; ret = context->db->hdb_remove (context->context, context->db, &source_ent); krb5_free_principal (context->context, source); return ret; }
kadm5_ret_t kadm5_log_replay_create (kadm5_server_context *context, u_int32_t ver, u_int32_t len, krb5_storage *sp) { krb5_error_code ret; krb5_data data; hdb_entry ent; ret = krb5_data_alloc (&data, len); if (ret) return ret; krb5_storage_read (sp, data.data, len); ret = hdb_value2entry (context->context, &data, &ent); krb5_data_free(&data); if (ret) return ret; ret = context->db->hdb_store(context->context, context->db, 0, &ent); hdb_free_entry (context->context, &ent); return ret; }
krb5_error_code hdb_foreach(krb5_context context, HDB *db, unsigned flags, hdb_foreach_func_t func, void *data) { krb5_error_code ret; hdb_entry_ex entry; ret = db->hdb_firstkey(context, db, flags, &entry); if (ret == 0) krb5_clear_error_message(context); while(ret == 0){ ret = (*func)(context, db, &entry, data); hdb_free_entry(context, &entry); if(ret == 0) ret = db->hdb_nextkey(context, db, flags, &entry); } if(ret == HDB_ERR_NOENTRY) ret = 0; return ret; }
kadm5_ret_t kadm5_s_delete_principal(void *server_handle, krb5_principal princ) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) { krb5_warn(context->context, ret, "opening database"); return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret == HDB_ERR_NOENTRY) goto out; if(ent.entry.flags.immutable) { ret = KADM5_PROTECT_PRINCIPAL; goto out2; } ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; ret = context->db->hdb_remove(context->context, context->db, princ); if (ret) goto out2; kadm5_log_delete (context, princ); out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
static int KRB5_CALLCONV hdb_next_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor) { struct hdb_cursor *c = cursor->data; krb5_error_code ret; memset(entry, 0, sizeof(*entry)); if (c->first) { c->first = FALSE; ret = (c->db->hdb_firstkey)(context, c->db, HDB_F_DECRYPT| HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, &c->hdb_entry); if (ret == HDB_ERR_NOENTRY) return KRB5_KT_END; else if (ret) return ret; if (c->hdb_entry.entry.keys.len == 0) hdb_free_entry(context, &c->hdb_entry); else c->next = FALSE; } while (c->next) { ret = (c->db->hdb_nextkey)(context, c->db, HDB_F_DECRYPT| HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, &c->hdb_entry); if (ret == HDB_ERR_NOENTRY) return KRB5_KT_END; else if (ret) return ret; /* If no keys on this entry, try again */ if (c->hdb_entry.entry.keys.len == 0) hdb_free_entry(context, &c->hdb_entry); else c->next = FALSE; } /* * Return next enc type (keytabs are one slot per key, while * hdb is one record per principal. */ ret = krb5_copy_principal(context, c->hdb_entry.entry.principal, &entry->principal); if (ret) return ret; entry->vno = c->hdb_entry.entry.kvno; ret = krb5_copy_keyblock_contents(context, &c->hdb_entry.entry.keys.val[c->key_idx].key, &entry->keyblock); if (ret) { krb5_free_principal(context, entry->principal); memset(entry, 0, sizeof(*entry)); return ret; } c->key_idx++; /* * Once we get to the end of the list, signal that we want the * next entry */ if (c->key_idx == c->hdb_entry.entry.keys.len) { hdb_free_entry(context, &c->hdb_entry); c->next = TRUE; c->key_idx = 0; } return 0; }
static krb5_error_code KRB5_CALLCONV hdb_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *entry) { hdb_entry_ex ent; krb5_error_code ret; struct hdb_data *d = id->data; const char *dbname = d->dbname; const char *mkey = d->mkey; char *fdbname = NULL, *fmkey = NULL; HDB *db; int i; memset(&ent, 0, sizeof(ent)); if (dbname == NULL) { ret = find_db(context, &fdbname, &fmkey, principal); if (ret) return ret; dbname = fdbname; mkey = fmkey; } ret = hdb_create (context, &db, dbname); if (ret) goto out2; ret = hdb_set_master_keyfile (context, db, mkey); if (ret) { (*db->hdb_destroy)(context, db); goto out2; } ret = (*db->hdb_open)(context, db, O_RDONLY, 0); if (ret) { (*db->hdb_destroy)(context, db); goto out2; } ret = (*db->hdb_fetch_kvno)(context, db, principal, HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED| HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, kvno, &ent); if(ret == HDB_ERR_NOENTRY) { ret = KRB5_KT_NOTFOUND; goto out; }else if(ret) goto out; if(kvno && ent.entry.kvno != kvno) { hdb_free_entry(context, &ent); ret = KRB5_KT_NOTFOUND; goto out; } if(enctype == 0) if(ent.entry.keys.len > 0) enctype = ent.entry.keys.val[0].key.keytype; ret = KRB5_KT_NOTFOUND; for(i = 0; i < ent.entry.keys.len; i++) { if(ent.entry.keys.val[i].key.keytype == enctype) { krb5_copy_principal(context, principal, &entry->principal); entry->vno = ent.entry.kvno; krb5_copy_keyblock_contents(context, &ent.entry.keys.val[i].key, &entry->keyblock); ret = 0; break; } } hdb_free_entry(context, &ent); out: (*db->hdb_close)(context, db); (*db->hdb_destroy)(context, db); out2: free(fdbname); free(fmkey); return ret; }
static krb5_error_code receive_everything (krb5_context context, int fd, kadm5_server_context *server_context, krb5_auth_context auth_context) { int ret; krb5_data data; int32_t vno = 0; int32_t opcode; krb5_storage *sp; char *dbname; HDB *mydb; krb5_warnx(context, "receive complete database"); asprintf(&dbname, "%s-NEW", server_context->db->hdb_name); ret = hdb_create(context, &mydb, dbname); if(ret) krb5_err(context,1, ret, "hdb_create"); free(dbname); ret = hdb_set_master_keyfile (context, mydb, server_context->config.stash_file); if(ret) krb5_err(context,1, ret, "hdb_set_master_keyfile"); /* I really want to use O_EXCL here, but given that I can't easily clean up on error, I won't */ ret = mydb->hdb_open(context, mydb, O_RDWR | O_CREAT | O_TRUNC, 0600); if (ret) krb5_err (context, 1, ret, "db->open"); sp = NULL; do { ret = krb5_read_priv_message(context, auth_context, &fd, &data); if (ret) { krb5_warn (context, ret, "krb5_read_priv_message"); goto cleanup; } sp = krb5_storage_from_data (&data); if (sp == NULL) krb5_errx (context, 1, "krb5_storage_from_data"); krb5_ret_int32 (sp, &opcode); if (opcode == ONE_PRINC) { krb5_data fake_data; hdb_entry_ex entry; krb5_storage_free(sp); fake_data.data = (char *)data.data + 4; fake_data.length = data.length - 4; memset(&entry, 0, sizeof(entry)); ret = hdb_value2entry (context, &fake_data, &entry.entry); if (ret) krb5_err (context, 1, ret, "hdb_value2entry"); ret = mydb->hdb_store(server_context->context, mydb, 0, &entry); if (ret) krb5_err (context, 1, ret, "hdb_store"); hdb_free_entry (context, &entry); krb5_data_free (&data); } else if (opcode == NOW_YOU_HAVE) ; else krb5_errx (context, 1, "strange opcode %d", opcode); } while (opcode == ONE_PRINC); if (opcode != NOW_YOU_HAVE) krb5_errx (context, 1, "receive_everything: strange %d", opcode); krb5_ret_int32 (sp, &vno); krb5_storage_free(sp); ret = kadm5_log_reinit (server_context); if (ret) krb5_err(context, 1, ret, "kadm5_log_reinit"); ret = kadm5_log_set_version (server_context, vno - 1); if (ret) krb5_err (context, 1, ret, "kadm5_log_set_version"); ret = kadm5_log_nop (server_context); if (ret) krb5_err (context, 1, ret, "kadm5_log_nop"); ret = mydb->hdb_rename (context, mydb, server_context->db->hdb_name); if (ret) krb5_err (context, 1, ret, "db->rename"); cleanup: krb5_data_free (&data); ret = mydb->hdb_close (context, mydb); if (ret) krb5_err (context, 1, ret, "db->close"); ret = mydb->hdb_destroy (context, mydb); if (ret) krb5_err (context, 1, ret, "db->destroy"); krb5_warnx(context, "receive complete database, version %ld", (long)vno); return ret; }
static int doit(const char *filename, int mergep) { krb5_error_code ret; FILE *f; char s[8192]; /* XXX should fix this properly */ char *p; int line; int flags = O_RDWR; struct entry e; hdb_entry_ex ent; HDB *db = _kadm5_s_get_db(kadm_handle); f = fopen(filename, "r"); if(f == NULL){ krb5_warn(context, errno, "fopen(%s)", filename); return 1; } ret = kadm5_log_truncate (kadm_handle); if (ret) { fclose (f); krb5_warn(context, ret, "kadm5_log_truncate"); return 1; } if(!mergep) flags |= O_CREAT | O_TRUNC; ret = db->hdb_open(context, db, flags, 0600); if(ret){ krb5_warn(context, ret, "hdb_open"); fclose(f); return 1; } line = 0; ret = 0; while(fgets(s, sizeof(s), f) != NULL) { ret = 0; line++; p = s; while (isspace((unsigned char)*p)) p++; e.principal = p; for(p = s; *p; p++){ if(*p == '\\') p++; else if(isspace((unsigned char)*p)) { *p = 0; break; } } p = skip_next(p); e.key = p; p = skip_next(p); e.created = p; p = skip_next(p); e.modified = p; p = skip_next(p); e.valid_start = p; p = skip_next(p); e.valid_end = p; p = skip_next(p); e.pw_end = p; p = skip_next(p); e.max_life = p; p = skip_next(p); e.max_renew = p; p = skip_next(p); e.flags = p; p = skip_next(p); e.generation = p; p = skip_next(p); e.extensions = p; p = skip_next(p); memset(&ent, 0, sizeof(ent)); ret = krb5_parse_name(context, e.principal, &ent.entry.principal); if(ret) { fprintf(stderr, "%s:%d:%s (%s)\n", filename, line, krb5_get_err_text(context, ret), e.principal); continue; } if (parse_keys(&ent.entry, e.key)) { fprintf (stderr, "%s:%d:error parsing keys (%s)\n", filename, line, e.key); hdb_free_entry (context, &ent); continue; } if (parse_event(&ent.entry.created_by, e.created) == -1) { fprintf (stderr, "%s:%d:error parsing created event (%s)\n", filename, line, e.created); hdb_free_entry (context, &ent); continue; } if (parse_event_alloc (&ent.entry.modified_by, e.modified) == -1) { fprintf (stderr, "%s:%d:error parsing event (%s)\n", filename, line, e.modified); hdb_free_entry (context, &ent); continue; } if (parse_time_string_alloc (&ent.entry.valid_start, e.valid_start) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", filename, line, e.valid_start); hdb_free_entry (context, &ent); continue; } if (parse_time_string_alloc (&ent.entry.valid_end, e.valid_end) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", filename, line, e.valid_end); hdb_free_entry (context, &ent); continue; } if (parse_time_string_alloc (&ent.entry.pw_end, e.pw_end) == -1) { fprintf (stderr, "%s:%d:error parsing time (%s)\n", filename, line, e.pw_end); hdb_free_entry (context, &ent); continue; } if (parse_integer_alloc (&ent.entry.max_life, e.max_life) == -1) { fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", filename, line, e.max_life); hdb_free_entry (context, &ent); continue; } if (parse_integer_alloc (&ent.entry.max_renew, e.max_renew) == -1) { fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n", filename, line, e.max_renew); hdb_free_entry (context, &ent); continue; } if (parse_hdbflags2int (&ent.entry.flags, e.flags) != 1) { fprintf (stderr, "%s:%d:error parsing flags (%s)\n", filename, line, e.flags); hdb_free_entry (context, &ent); continue; } if(parse_generation(e.generation, &ent.entry.generation) == -1) { fprintf (stderr, "%s:%d:error parsing generation (%s)\n", filename, line, e.generation); hdb_free_entry (context, &ent); continue; } if(parse_extensions(e.extensions, &ent.entry.extensions) == -1) { fprintf (stderr, "%s:%d:error parsing extension (%s)\n", filename, line, e.extensions); hdb_free_entry (context, &ent); continue; } ret = db->hdb_store(context, db, HDB_F_REPLACE, &ent); hdb_free_entry (context, &ent); if (ret) { krb5_warn(context, ret, "db_store"); break; } } db->hdb_close(context, db); fclose(f); return ret != 0; }
static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, struct kdc_check_generic_kerberos *r) { struct PAC_Validate pac_validate; DATA_BLOB srv_sig; struct PAC_SIGNATURE_DATA kdc_sig; struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server); krb5_kdc_configuration *kdc_config = (krb5_kdc_configuration *)kdc->private_data; enum ndr_err_code ndr_err; int ret; hdb_entry_ex ent; krb5_principal principal; /* There is no reply to this request */ r->out.generic_reply = data_blob(NULL, 0); ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, &pac_validate, (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return NT_STATUS_INVALID_PARAMETER; } if (pac_validate.MessageType != NETLOGON_GENERIC_KRB5_PAC_VALIDATE) { /* We don't implement any other message types - such as certificate validation - yet */ return NT_STATUS_INVALID_PARAMETER; } if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength) || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) { return NT_STATUS_INVALID_PARAMETER; } srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, pac_validate.ChecksumLength); ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal, lpcfg_realm(kdc->task->lp_ctx), "krbtgt", lpcfg_realm(kdc->task->lp_ctx), NULL); if (ret != 0) { return NT_STATUS_NO_MEMORY; } ret = kdc_config->db[0]->hdb_fetch_kvno(kdc->smb_krb5_context->krb5_context, kdc_config->db[0], principal, HDB_F_GET_KRBTGT | HDB_F_DECRYPT, 0, &ent); if (ret != 0) { hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal); return NT_STATUS_LOGON_FAILURE; } kdc_sig.type = pac_validate.SignatureType; kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength], pac_validate.SignatureLength); ret = kdc_check_pac(kdc->smb_krb5_context->krb5_context, srv_sig, &kdc_sig, &ent); hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal); if (ret != 0) { return NT_STATUS_LOGON_FAILURE; } return NT_STATUS_OK; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_auth_context ac = NULL; krb5_principal c1, c2; krb5_authenticator authent; krb5_keytab keytab; krb5_socket_t sock = rk_INVALID_SOCKET; HDB *db = NULL; int optidx = 0; char *tmp_db; krb5_log_facility *fac; int nprincs; setprogname(argv[0]); ret = krb5_init_context(&context); if(ret) exit(1); ret = krb5_openlog(context, "hpropd", &fac); if(ret) errx(1, "krb5_openlog"); krb5_set_warn_dest(context, fac); if(getarg(args, num_args, argc, argv, &optidx)) usage(1); if(local_realm != NULL) krb5_set_default_realm(context, local_realm); if(help_flag) usage(0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (argc != 0) usage(1); if (database == NULL) database = hdb_default_db(context); if(from_stdin) { sock = STDIN_FILENO; } else { struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; socklen_t sin_len = sizeof(ss); char addr_name[256]; krb5_ticket *ticket; char *server; sock = STDIN_FILENO; #ifdef SUPPORT_INETD if (inetd_flag == -1) { if (getpeername (sock, sa, &sin_len) < 0) { inetd_flag = 0; } else { inetd_flag = 1; } } #else inetd_flag = 0; #endif if (!inetd_flag) { mini_inetd (krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT), &sock); } sin_len = sizeof(ss); if(getpeername(sock, sa, &sin_len) < 0) krb5_err(context, 1, errno, "getpeername"); if (inet_ntop(sa->sa_family, socket_get_address (sa), addr_name, sizeof(addr_name)) == NULL) strlcpy (addr_name, "unknown address", sizeof(addr_name)); krb5_log(context, fac, 0, "Connection from %s", addr_name); ret = krb5_kt_register(context, &hdb_kt_ops); if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); if (ktname != NULL) { ret = krb5_kt_resolve(context, ktname, &keytab); if (ret) krb5_err (context, 1, ret, "krb5_kt_resolve %s", ktname); } else { ret = krb5_kt_default (context, &keytab); if (ret) krb5_err (context, 1, ret, "krb5_kt_default"); } ret = krb5_recvauth(context, &ac, &sock, HPROP_VERSION, NULL, 0, keytab, &ticket); if(ret) krb5_err(context, 1, ret, "krb5_recvauth"); ret = krb5_unparse_name(context, ticket->server, &server); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name"); if (strncmp(server, "hprop/", 5) != 0) krb5_errx(context, 1, "ticket not for hprop (%s)", server); free(server); krb5_free_ticket (context, ticket); ret = krb5_auth_con_getauthenticator(context, ac, &authent); if(ret) krb5_err(context, 1, ret, "krb5_auth_con_getauthenticator"); ret = krb5_make_principal(context, &c1, NULL, "kadmin", "hprop", NULL); if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); _krb5_principalname2krb5_principal(context, &c2, authent->cname, authent->crealm); if(!krb5_principal_compare(context, c1, c2)) { char *s; ret = krb5_unparse_name(context, c2, &s); if (ret) s = unparseable_name; krb5_errx(context, 1, "Unauthorized connection from %s", s); } krb5_free_principal(context, c1); krb5_free_principal(context, c2); ret = krb5_kt_close(context, keytab); if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); } if(!print_dump) { asprintf(&tmp_db, "%s~", database); ret = hdb_create(context, &db, tmp_db); if(ret) krb5_err(context, 1, ret, "hdb_create(%s)", tmp_db); ret = db->hdb_open(context, db, O_RDWR | O_CREAT | O_TRUNC, 0600); if(ret) krb5_err(context, 1, ret, "hdb_open(%s)", tmp_db); } nprincs = 0; while(1){ krb5_data data; hdb_entry_ex entry; if(from_stdin) { ret = krb5_read_message(context, &sock, &data); if(ret != 0 && ret != HEIM_ERR_EOF) krb5_err(context, 1, ret, "krb5_read_message"); } else { ret = krb5_read_priv_message(context, ac, &sock, &data); if(ret) krb5_err(context, 1, ret, "krb5_read_priv_message"); } if(ret == HEIM_ERR_EOF || data.length == 0) { if(!from_stdin) { data.data = NULL; data.length = 0; krb5_write_priv_message(context, ac, &sock, &data); } if(!print_dump) { ret = db->hdb_close(context, db); if(ret) krb5_err(context, 1, ret, "db_close"); ret = db->hdb_rename(context, db, database); if(ret) krb5_err(context, 1, ret, "db_rename"); } break; } memset(&entry, 0, sizeof(entry)); ret = hdb_value2entry(context, &data, &entry.entry); krb5_data_free(&data); if(ret) krb5_err(context, 1, ret, "hdb_value2entry"); if(print_dump) hdb_print_entry(context, db, &entry, stdout); else { ret = db->hdb_store(context, db, 0, &entry); if(ret == HDB_ERR_EXISTS) { char *s; ret = krb5_unparse_name(context, entry.entry.principal, &s); if (ret) s = strdup(unparseable_name); krb5_warnx(context, "Entry exists: %s", s); free(s); } else if(ret) krb5_err(context, 1, ret, "db_store"); else nprincs++; } hdb_free_entry(context, &entry); } if (!print_dump) krb5_log(context, fac, 0, "Received %d principals", nprincs); if (inetd_flag == 0) rk_closesocket(sock); exit(0); }
/** * Retrieves an entry by searching for the given * principal in the Principal database table, both * for canonical principals and aliases. * * @param context The current krb5_context * @param db Heimdal database handle * @param principal The principal whose entry to search for * @param flags Currently only for HDB_F_DECRYPT * @param kvno kvno to fetch is HDB_F_KVNO_SPECIFIED use used * * @return 0 if everything worked, an error code if not */ static krb5_error_code hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) { int sqlite_error; krb5_error_code ret; hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); sqlite3_stmt *fetch = hsdb->fetch; krb5_data value; krb5_principal enterprise_principal = NULL; if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { if (principal->name.name_string.len != 1) { ret = KRB5_PARSE_MALFORMED; krb5_set_error_message(context, ret, "malformed principal: " "enterprise name with %d name components", principal->name.name_string.len); return ret; } ret = krb5_parse_name(context, principal->name.name_string.val[0], &enterprise_principal); if (ret) return ret; principal = enterprise_principal; } ret = bind_principal(context, principal, fetch, 1); if (ret) return ret; krb5_free_principal(context, enterprise_principal); sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch); if (sqlite_error != SQLITE_ROW) { if(sqlite_error == SQLITE_DONE) { ret = HDB_ERR_NOENTRY; goto out; } else { ret = HDB_ERR_UK_RERROR; krb5_set_error_message(context, ret, "sqlite fetch failed: %d", sqlite_error); goto out; } } value.length = sqlite3_column_bytes(fetch, 0); value.data = (void *) sqlite3_column_blob(fetch, 0); ret = hdb_value2entry(context, &value, &entry->entry); if(ret) goto out; if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { ret = hdb_unseal_keys(context, db, &entry->entry); if(ret) { hdb_free_entry(context, entry); goto out; } } ret = 0; out: sqlite3_clear_bindings(fetch); sqlite3_reset(fetch); return ret; }
kadm5_ret_t kadm5_s_get_principal(void *server_handle, krb5_principal princ, kadm5_principal_ent_t out, uint32_t mask) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); if(ret) return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_ALL_KVNOS| HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if (!context->keep_open) context->db->hdb_close(context->context, context->db); if(ret) return _kadm5_error_code(ret); memset(out, 0, sizeof(*out)); if(mask & KADM5_PRINCIPAL) ret = krb5_copy_principal(context->context, ent.entry.principal, &out->principal); if(ret) goto out; if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end) out->princ_expire_time = *ent.entry.valid_end; if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end) out->pw_expiration = *ent.entry.pw_end; if(mask & KADM5_LAST_PWD_CHANGE) hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change); if(mask & KADM5_ATTRIBUTES){ out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; } if(mask & KADM5_MAX_LIFE) { if(ent.entry.max_life) out->max_life = *ent.entry.max_life; else out->max_life = INT_MAX; } if(mask & KADM5_MOD_TIME) { if(ent.entry.modified_by) out->mod_date = ent.entry.modified_by->time; else out->mod_date = ent.entry.created_by.time; } if(mask & KADM5_MOD_NAME) { if(ent.entry.modified_by) { if (ent.entry.modified_by->principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.modified_by->principal, &out->mod_name); } else if(ent.entry.created_by.principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.created_by.principal, &out->mod_name); else out->mod_name = NULL; } if(ret) goto out; if(mask & KADM5_KVNO) out->kvno = ent.entry.kvno; if(mask & KADM5_MKVNO) { size_t n; out->mkvno = 0; /* XXX */ for(n = 0; n < ent.entry.keys.len; n++) if(ent.entry.keys.val[n].mkvno) { out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */ break; } } #if 0 /* XXX implement */ if(mask & KADM5_AUX_ATTRIBUTES) ; if(mask & KADM5_LAST_SUCCESS) ; if(mask & KADM5_LAST_FAILED) ; if(mask & KADM5_FAIL_AUTH_COUNT) ; #endif if(mask & KADM5_POLICY) { HDB_extension *ext; ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_policy); if (ext == NULL) { out->policy = strdup("default"); /* It's OK if we retun NULL instead of "default" */ } else { out->policy = strdup(ext->data.u.policy); if (out->policy == NULL) { ret = ENOMEM; goto out; } } } if(mask & KADM5_MAX_RLIFE) { if(ent.entry.max_renew) out->max_renewable_life = *ent.entry.max_renew; else out->max_renewable_life = INT_MAX; } if(mask & KADM5_KEY_DATA){ size_t i; size_t n_keys = ent.entry.keys.len; krb5_salt salt; HDB_extension *ext; HDB_Ext_KeySet *hist_keys = NULL; ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys); if (ext != NULL) hist_keys = &ext->data.u.hist_keys; krb5_get_pw_salt(context->context, ent.entry.principal, &salt); for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) n_keys += hist_keys->val[i].keys.len; out->key_data = malloc(n_keys * sizeof(*out->key_data)); if (out->key_data == NULL && n_keys != 0) { ret = ENOMEM; goto out; } out->n_key_data = 0; ret = copy_keyset_to_kadm5(context, ent.entry.kvno, ent.entry.keys.len, ent.entry.keys.val, &salt, out); if (ret) goto out; for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) { ret = copy_keyset_to_kadm5(context, hist_keys->val[i].kvno, hist_keys->val[i].keys.len, hist_keys->val[i].keys.val, &salt, out); if (ret) goto out; } krb5_free_salt(context->context, salt); assert( out->n_key_data == n_keys ); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } if(mask & KADM5_TL_DATA) { time_t last_pw_expire; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_Aliases *aliases; ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire); if (ret == 0 && last_pw_expire) { unsigned char buf[4]; _krb5_put_int(buf, last_pw_expire, sizeof(buf)); ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } /* * If the client was allowed to get key data, let it have the * password too. */ if(mask & KADM5_KEY_DATA) { heim_utf8_string pw; ret = hdb_entry_get_password(context->context, context->db, &ent.entry, &pw); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); free(pw); } krb5_clear_error_message(context->context); } ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl); if (ret == 0 && acl) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length, acl, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } ret = hdb_entry_get_aliases(&ent.entry, &aliases); if (ret == 0 && aliases) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length, aliases, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } } out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
static kadm5_ret_t kadm5_log_replay_modify (kadm5_server_context *context, uint32_t ver, uint32_t len, krb5_storage *sp) { krb5_error_code ret; int32_t mask; krb5_data value; hdb_entry_ex ent, log_ent; memset(&log_ent, 0, sizeof(log_ent)); krb5_ret_int32 (sp, &mask); len -= 4; ret = krb5_data_alloc (&value, len); if (ret) { krb5_set_error_message(context->context, ret, "out of memory"); return ret; } krb5_storage_read (sp, value.data, len); ret = hdb_value2entry (context->context, &value, &log_ent.entry); krb5_data_free(&value); if (ret) return ret; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_fetch_kvno(context->context, context->db, log_ent.entry.principal, HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if (ret) goto out; if (mask & KADM5_PRINC_EXPIRE_TIME) { if (log_ent.entry.valid_end == NULL) { ent.entry.valid_end = NULL; } else { if (ent.entry.valid_end == NULL) { ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end)); if (ent.entry.valid_end == NULL) { ret = ENOMEM; krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } *ent.entry.valid_end = *log_ent.entry.valid_end; } } if (mask & KADM5_PW_EXPIRATION) { if (log_ent.entry.pw_end == NULL) { ent.entry.pw_end = NULL; } else { if (ent.entry.pw_end == NULL) { ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end)); if (ent.entry.pw_end == NULL) { ret = ENOMEM; krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } *ent.entry.pw_end = *log_ent.entry.pw_end; } } if (mask & KADM5_LAST_PWD_CHANGE) { abort (); /* XXX */ } if (mask & KADM5_ATTRIBUTES) { ent.entry.flags = log_ent.entry.flags; } if (mask & KADM5_MAX_LIFE) { if (log_ent.entry.max_life == NULL) { ent.entry.max_life = NULL; } else { if (ent.entry.max_life == NULL) { ent.entry.max_life = malloc (sizeof(*ent.entry.max_life)); if (ent.entry.max_life == NULL) { ret = ENOMEM; krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } *ent.entry.max_life = *log_ent.entry.max_life; } } if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) { if (ent.entry.modified_by == NULL) { ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by)); if (ent.entry.modified_by == NULL) { ret = ENOMEM; krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } else free_Event(ent.entry.modified_by); ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by); if (ret) { krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } if (mask & KADM5_KVNO) { ent.entry.kvno = log_ent.entry.kvno; } if (mask & KADM5_MKVNO) { abort (); /* XXX */ } if (mask & KADM5_AUX_ATTRIBUTES) { abort (); /* XXX */ } if (mask & KADM5_POLICY) { abort (); /* XXX */ } if (mask & KADM5_POLICY_CLR) { abort (); /* XXX */ } if (mask & KADM5_MAX_RLIFE) { if (log_ent.entry.max_renew == NULL) { ent.entry.max_renew = NULL; } else { if (ent.entry.max_renew == NULL) { ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew)); if (ent.entry.max_renew == NULL) { ret = ENOMEM; krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } *ent.entry.max_renew = *log_ent.entry.max_renew; } } if (mask & KADM5_LAST_SUCCESS) { abort (); /* XXX */ } if (mask & KADM5_LAST_FAILED) { abort (); /* XXX */ } if (mask & KADM5_FAIL_AUTH_COUNT) { abort (); /* XXX */ } if (mask & KADM5_KEY_DATA) { size_t num; int i; for (i = 0; i < ent.entry.keys.len; ++i) free_Key(&ent.entry.keys.val[i]); free (ent.entry.keys.val); num = log_ent.entry.keys.len; ent.entry.keys.len = num; ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val)); if (ent.entry.keys.val == NULL) { krb5_set_error_message(context->context, ENOMEM, "out of memory"); return ENOMEM; } for (i = 0; i < ent.entry.keys.len; ++i) { ret = copy_Key(&log_ent.entry.keys.val[i], &ent.entry.keys.val[i]); if (ret) { krb5_set_error_message(context->context, ret, "out of memory"); goto out; } } } if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) { HDB_extensions *es = ent.entry.extensions; ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions)); if (ent.entry.extensions == NULL) goto out; ret = copy_HDB_extensions(log_ent.entry.extensions, ent.entry.extensions); if (ret) { krb5_set_error_message(context->context, ret, "out of memory"); free(ent.entry.extensions); ent.entry.extensions = es; goto out; } if (es) { free_HDB_extensions(es); free(es); } } ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); out: hdb_free_entry (context->context, &ent); hdb_free_entry (context->context, &log_ent); return ret; }
kadm5_ret_t kadm5_s_rename_principal(void *server_handle, krb5_principal source, krb5_principal target) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; krb5_principal oldname; memset(&ent, 0, sizeof(ent)); if(krb5_principal_compare(context->context, source, target)) return KADM5_DUP; /* XXX is this right? */ ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, source, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret){ context->db->hdb_close(context->context, context->db); goto out; } ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; { /* fix salt */ size_t i; Salt salt; krb5_salt salt2; memset(&salt, 0, sizeof(salt)); krb5_get_pw_salt(context->context, source, &salt2); salt.type = hdb_pw_salt; salt.salt = salt2.saltvalue; for(i = 0; i < ent.entry.keys.len; i++){ if(ent.entry.keys.val[i].salt == NULL){ ent.entry.keys.val[i].salt = malloc(sizeof(*ent.entry.keys.val[i].salt)); if(ent.entry.keys.val[i].salt == NULL) return ENOMEM; ret = copy_Salt(&salt, ent.entry.keys.val[i].salt); if(ret) break; } } krb5_free_salt(context->context, salt2); } if(ret) goto out2; oldname = ent.entry.principal; ent.entry.principal = target; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) { ent.entry.principal = oldname; goto out2; } kadm5_log_rename (context, source, &ent.entry); ret = context->db->hdb_store(context->context, context->db, 0, &ent); if(ret){ ent.entry.principal = oldname; goto out2; } ret = context->db->hdb_remove(context->context, context->db, oldname); ent.entry.principal = oldname; out2: context->db->hdb_close(context->context, context->db); hdb_free_entry(context->context, &ent); out: return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_log_replay_modify (kadm5_server_context *context, u_int32_t ver, u_int32_t len, krb5_storage *sp) { krb5_error_code ret; int32_t mask; krb5_data value; hdb_entry ent, log_ent; krb5_ret_int32 (sp, &mask); len -= 4; ret = krb5_data_alloc (&value, len); if (ret) return ret; krb5_storage_read (sp, value.data, len); ret = hdb_value2entry (context->context, &value, &log_ent); krb5_data_free(&value); if (ret) return ret; ent.principal = log_ent.principal; log_ent.principal = NULL; ret = context->db->hdb_fetch(context->context, context->db, HDB_F_DECRYPT, &ent); if (ret) return ret; if (mask & KADM5_PRINC_EXPIRE_TIME) { if (log_ent.valid_end == NULL) { ent.valid_end = NULL; } else { if (ent.valid_end == NULL) ent.valid_end = malloc(sizeof(*ent.valid_end)); *ent.valid_end = *log_ent.valid_end; } } if (mask & KADM5_PW_EXPIRATION) { if (log_ent.pw_end == NULL) { ent.pw_end = NULL; } else { if (ent.pw_end == NULL) ent.pw_end = malloc(sizeof(*ent.pw_end)); *ent.pw_end = *log_ent.pw_end; } } if (mask & KADM5_LAST_PWD_CHANGE) { abort (); /* XXX */ } if (mask & KADM5_ATTRIBUTES) { ent.flags = log_ent.flags; } if (mask & KADM5_MAX_LIFE) { if (log_ent.max_life == NULL) { ent.max_life = NULL; } else { if (ent.max_life == NULL) ent.max_life = malloc (sizeof(*ent.max_life)); *ent.max_life = *log_ent.max_life; } } if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) { if (ent.modified_by == NULL) { ent.modified_by = malloc(sizeof(*ent.modified_by)); } else free_Event(ent.modified_by); copy_Event(log_ent.modified_by, ent.modified_by); } if (mask & KADM5_KVNO) { ent.kvno = log_ent.kvno; } if (mask & KADM5_MKVNO) { abort (); /* XXX */ } if (mask & KADM5_AUX_ATTRIBUTES) { abort (); /* XXX */ } if (mask & KADM5_POLICY) { abort (); /* XXX */ } if (mask & KADM5_POLICY_CLR) { abort (); /* XXX */ } if (mask & KADM5_MAX_RLIFE) { if (log_ent.max_renew == NULL) { ent.max_renew = NULL; } else { if (ent.max_renew == NULL) ent.max_renew = malloc (sizeof(*ent.max_renew)); *ent.max_renew = *log_ent.max_renew; } } if (mask & KADM5_LAST_SUCCESS) { abort (); /* XXX */ } if (mask & KADM5_LAST_FAILED) { abort (); /* XXX */ } if (mask & KADM5_FAIL_AUTH_COUNT) { abort (); /* XXX */ } if (mask & KADM5_KEY_DATA) { size_t len; int i; for (i = 0; i < ent.keys.len; ++i) free_Key(&ent.keys.val[i]); free (ent.keys.val); len = log_ent.keys.len; ent.keys.len = len; ent.keys.val = malloc(len * sizeof(*ent.keys.val)); for (i = 0; i < ent.keys.len; ++i) copy_Key(&log_ent.keys.val[i], &ent.keys.val[i]); } ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); hdb_free_entry (context->context, &ent); hdb_free_entry (context->context, &log_ent); return ret; }
void _kdc_free_ent(krb5_context context, hdb_entry_ex *ent) { hdb_free_entry (context, ent); free (ent); }