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; }
/* * Should get the next entry, to allow iteration over all entries. */ static krb5_error_code hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) { krb5_error_code ret = 0; int sqlite_error; krb5_data value; hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries); if(sqlite_error == SQLITE_ROW) { /* Found an entry */ value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0); value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0); memset(entry, 0, sizeof(*entry)); ret = hdb_value2entry(context, &value, &entry->entry); } else if(sqlite_error == SQLITE_DONE) { /* No more entries */ ret = HDB_ERR_NOENTRY; sqlite3_reset(hsdb->get_all_entries); } else { ret = HDB_ERR_UK_RERROR; krb5_set_error_message(context, HDB_ERR_UK_RERROR, "SELECT failed after returning one or " "more rows: %s", sqlite3_errmsg(hsdb->db)); } return ret; }
/* * Should get the next entry, to allow iteration over all entries. */ static krb5_error_code hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) { krb5_error_code ret = 0; int sqlite_error; krb5_data value; hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries); if(sqlite_error == SQLITE_ROW) { /* Found an entry */ value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0); value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0); memset(entry, 0, sizeof(*entry)); ret = hdb_value2entry(context, &value, &entry->entry); } else if(sqlite_error == SQLITE_DONE) { /* No more entries */ ret = HDB_ERR_NOENTRY; sqlite3_reset(hsdb->get_all_entries); } else { /* XXX SQLite error. Should be handled in some way. */ ret = EINVAL; } 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 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 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; }
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_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; }
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); }
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_ALL_KVNOS| 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; size_t i; /* * We don't need to do anything about key history here because * we always log KADM5_TL_DATA when we change keys/passwords, so * the code below this will handle key history implicitly. * However, if we had to, the code to handle key history here * would look like this: * * HDB_extension *ext; * ... * ext = hdb_find_extension(&log_ent.entry, * choice_HDB_extension_data_hist_keys); * if (ext); * ret = hdb_replace_extension(context->context, &ent.entry, ext); * else * ret = hdb_clear_extension(context->context, &ent.entry, * choice_HDB_extension_data_hist_keys); * * Maybe we should do this here anyways, wasteful as it would * be, as a defensive programming measure? For now we heim_assert(). */ heim_assert((mask & KADM5_TL_DATA), "Wouldn't log and replay key history"); 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; }
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); }
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; }
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; }
/** * 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; }
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; }