diff options
Diffstat (limited to 'lib/kadm5/log.c')
-rw-r--r-- | lib/kadm5/log.c | 982 |
1 files changed, 982 insertions, 0 deletions
diff --git a/lib/kadm5/log.c b/lib/kadm5/log.c new file mode 100644 index 0000000..5c4aaef --- /dev/null +++ b/lib/kadm5/log.c @@ -0,0 +1,982 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kadm5_locl.h" +#include "heim_threads.h" + +RCSID("$Id: log.c 22211 2007-12-07 19:27:27Z lha $"); + +/* + * A log record consists of: + * + * version number 4 bytes + * time in seconds 4 bytes + * operation (enum kadm_ops) 4 bytes + * length of record 4 bytes + * data... n bytes + * length of record 4 bytes + * version number 4 bytes + * + */ + +kadm5_ret_t +kadm5_log_get_version_fd (int fd, + uint32_t *ver) +{ + int ret; + krb5_storage *sp; + int32_t old_version; + + ret = lseek (fd, 0, SEEK_END); + if(ret < 0) + return errno; + if(ret == 0) { + *ver = 0; + return 0; + } + sp = krb5_storage_from_fd (fd); + krb5_storage_seek(sp, -4, SEEK_CUR); + krb5_ret_int32 (sp, &old_version); + *ver = old_version; + krb5_storage_free(sp); + lseek (fd, 0, SEEK_END); + return 0; +} + +kadm5_ret_t +kadm5_log_get_version (kadm5_server_context *context, uint32_t *ver) +{ + return kadm5_log_get_version_fd (context->log_context.log_fd, ver); +} + +kadm5_ret_t +kadm5_log_set_version (kadm5_server_context *context, uint32_t vno) +{ + kadm5_log_context *log_context = &context->log_context; + + log_context->version = vno; + return 0; +} + +kadm5_ret_t +kadm5_log_init (kadm5_server_context *context) +{ + int fd; + kadm5_ret_t ret; + kadm5_log_context *log_context = &context->log_context; + + if (log_context->log_fd != -1) + return 0; + fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600); + if (fd < 0) { + krb5_set_error_string(context->context, "kadm5_log_init: open %s", + log_context->log_file); + return errno; + } + if (flock (fd, LOCK_EX) < 0) { + krb5_set_error_string(context->context, "kadm5_log_init: flock %s", + log_context->log_file); + close (fd); + return errno; + } + + ret = kadm5_log_get_version_fd (fd, &log_context->version); + if (ret) + return ret; + + log_context->log_fd = fd; + return 0; +} + +kadm5_ret_t +kadm5_log_reinit (kadm5_server_context *context) +{ + int fd; + kadm5_log_context *log_context = &context->log_context; + + if (log_context->log_fd != -1) { + flock (log_context->log_fd, LOCK_UN); + close (log_context->log_fd); + log_context->log_fd = -1; + } + fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd < 0) + return errno; + if (flock (fd, LOCK_EX) < 0) { + close (fd); + return errno; + } + + log_context->version = 0; + log_context->log_fd = fd; + return 0; +} + + +kadm5_ret_t +kadm5_log_end (kadm5_server_context *context) +{ + kadm5_log_context *log_context = &context->log_context; + int fd = log_context->log_fd; + + flock (fd, LOCK_UN); + close(fd); + log_context->log_fd = -1; + return 0; +} + +static kadm5_ret_t +kadm5_log_preamble (kadm5_server_context *context, + krb5_storage *sp, + enum kadm_ops op) +{ + kadm5_log_context *log_context = &context->log_context; + kadm5_ret_t kadm_ret; + + kadm_ret = kadm5_log_init (context); + if (kadm_ret) + return kadm_ret; + + krb5_store_int32 (sp, ++log_context->version); + krb5_store_int32 (sp, time(NULL)); + krb5_store_int32 (sp, op); + return 0; +} + +static kadm5_ret_t +kadm5_log_postamble (kadm5_log_context *context, + krb5_storage *sp) +{ + krb5_store_int32 (sp, context->version); + return 0; +} + +/* + * flush the log record in `sp'. + */ + +static kadm5_ret_t +kadm5_log_flush (kadm5_log_context *log_context, + krb5_storage *sp) +{ + krb5_data data; + size_t len; + int ret; + + krb5_storage_to_data(sp, &data); + len = data.length; + ret = write (log_context->log_fd, data.data, len); + if (ret != len) { + krb5_data_free(&data); + return errno; + } + if (fsync (log_context->log_fd) < 0) { + krb5_data_free(&data); + return errno; + } + /* + * Try to send a signal to any running `ipropd-master' + */ + sendto (log_context->socket_fd, + (void *)&log_context->version, + sizeof(log_context->version), + 0, + (struct sockaddr *)&log_context->socket_name, + sizeof(log_context->socket_name)); + + krb5_data_free(&data); + return 0; +} + +/* + * Add a `create' operation to the log. + */ + +kadm5_ret_t +kadm5_log_create (kadm5_server_context *context, + hdb_entry *ent) +{ + krb5_storage *sp; + kadm5_ret_t ret; + krb5_data value; + kadm5_log_context *log_context = &context->log_context; + + sp = krb5_storage_emem(); + ret = hdb_entry2value (context->context, ent, &value); + if (ret) { + krb5_storage_free(sp); + return ret; + } + ret = kadm5_log_preamble (context, sp, kadm_create); + if (ret) { + krb5_data_free (&value); + krb5_storage_free(sp); + return ret; + } + krb5_store_int32 (sp, value.length); + krb5_storage_write(sp, value.data, value.length); + krb5_store_int32 (sp, value.length); + krb5_data_free (&value); + ret = kadm5_log_postamble (log_context, sp); + if (ret) { + krb5_storage_free (sp); + return ret; + } + ret = kadm5_log_flush (log_context, sp); + krb5_storage_free (sp); + if (ret) + return ret; + ret = kadm5_log_end (context); + return ret; +} + +/* + * Read the data of a create log record from `sp' and change the + * database. + */ + +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_string(context->context, "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_string(context->context, + "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; +} + +/* + * Add a `delete' operation to the log. + */ + +kadm5_ret_t +kadm5_log_delete (kadm5_server_context *context, + krb5_principal princ) +{ + krb5_storage *sp; + kadm5_ret_t ret; + off_t off; + off_t len; + kadm5_log_context *log_context = &context->log_context; + + sp = krb5_storage_emem(); + if (sp == NULL) + return ENOMEM; + ret = kadm5_log_preamble (context, sp, kadm_delete); + if (ret) + goto out; + ret = krb5_store_int32 (sp, 0); + if (ret) + goto out; + off = krb5_storage_seek (sp, 0, SEEK_CUR); + ret = krb5_store_principal (sp, princ); + if (ret) + goto out; + len = krb5_storage_seek (sp, 0, SEEK_CUR) - off; + krb5_storage_seek(sp, -(len + 4), SEEK_CUR); + ret = krb5_store_int32 (sp, len); + if (ret) + goto out; + krb5_storage_seek(sp, len, SEEK_CUR); + ret = krb5_store_int32 (sp, len); + if (ret) + goto out; + ret = kadm5_log_postamble (log_context, sp); + if (ret) + goto out; + ret = kadm5_log_flush (log_context, sp); + if (ret) + goto out; + ret = kadm5_log_end (context); +out: + krb5_storage_free (sp); + return ret; +} + +/* + * Read a `delete' log operation from `sp' and apply it. + */ + +static kadm5_ret_t +kadm5_log_replay_delete (kadm5_server_context *context, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + krb5_error_code ret; + krb5_principal principal; + + ret = krb5_ret_principal (sp, &principal); + if (ret) { + krb5_set_error_string(context->context, "Failed to read deleted " + "principal from log version: %ld", (long)ver); + return ret; + } + + ret = context->db->hdb_remove(context->context, context->db, principal); + krb5_free_principal (context->context, principal); + return ret; +} + +/* + * Add a `rename' operation to the log. + */ + +kadm5_ret_t +kadm5_log_rename (kadm5_server_context *context, + krb5_principal source, + hdb_entry *ent) +{ + krb5_storage *sp; + kadm5_ret_t ret; + off_t off; + off_t len; + krb5_data value; + kadm5_log_context *log_context = &context->log_context; + + krb5_data_zero(&value); + + sp = krb5_storage_emem(); + ret = hdb_entry2value (context->context, ent, &value); + if (ret) + goto failed; + + ret = kadm5_log_preamble (context, sp, kadm_rename); + if (ret) + goto failed; + + ret = krb5_store_int32 (sp, 0); + if (ret) + goto failed; + off = krb5_storage_seek (sp, 0, SEEK_CUR); + ret = krb5_store_principal (sp, source); + if (ret) + goto failed; + + krb5_storage_write(sp, value.data, value.length); + len = krb5_storage_seek (sp, 0, SEEK_CUR) - off; + + krb5_storage_seek(sp, -(len + 4), SEEK_CUR); + ret = krb5_store_int32 (sp, len); + if (ret) + goto failed; + + krb5_storage_seek(sp, len, SEEK_CUR); + ret = krb5_store_int32 (sp, len); + if (ret) + goto failed; + + ret = kadm5_log_postamble (log_context, sp); + if (ret) + goto failed; + + ret = kadm5_log_flush (log_context, sp); + if (ret) + goto failed; + krb5_storage_free (sp); + krb5_data_free (&value); + + return kadm5_log_end (context); + +failed: + krb5_data_free(&value); + krb5_storage_free(sp); + return ret; +} + +/* + * Read a `rename' log operation from `sp' and apply it. + */ + +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_string(context->context, "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; +} + + +/* + * Add a `modify' operation to the log. + */ + +kadm5_ret_t +kadm5_log_modify (kadm5_server_context *context, + hdb_entry *ent, + uint32_t mask) +{ + krb5_storage *sp; + kadm5_ret_t ret; + krb5_data value; + uint32_t len; + kadm5_log_context *log_context = &context->log_context; + + krb5_data_zero(&value); + + sp = krb5_storage_emem(); + ret = hdb_entry2value (context->context, ent, &value); + if (ret) + goto failed; + + ret = kadm5_log_preamble (context, sp, kadm_modify); + if (ret) + goto failed; + + len = value.length + 4; + ret = krb5_store_int32 (sp, len); + if (ret) + goto failed; + ret = krb5_store_int32 (sp, mask); + if (ret) + goto failed; + krb5_storage_write (sp, value.data, value.length); + + ret = krb5_store_int32 (sp, len); + if (ret) + goto failed; + ret = kadm5_log_postamble (log_context, sp); + if (ret) + goto failed; + ret = kadm5_log_flush (log_context, sp); + if (ret) + goto failed; + krb5_data_free(&value); + krb5_storage_free (sp); + return kadm5_log_end (context); +failed: + krb5_data_free(&value); + krb5_storage_free(sp); + return ret; +} + +/* + * Read a `modify' log operation from `sp' and apply it. + */ + +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_string(context->context, "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(context->context, context->db, + log_ent.entry.principal, + HDB_F_DECRYPT|HDB_F_GET_ANY, &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) { + krb5_set_error_string(context->context, "out of memory"); + ret = ENOMEM; + 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) { + krb5_set_error_string(context->context, "out of memory"); + ret = ENOMEM; + 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) { + krb5_set_error_string(context->context, "out of memory"); + ret = ENOMEM; + 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) { + krb5_set_error_string(context->context, "out of memory"); + ret = ENOMEM; + 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_string(context->context, "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) { + krb5_set_error_string(context->context, "out of memory"); + ret = ENOMEM; + 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_string(context->context, "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_string(context->context, "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_string(context->context, "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; +} + +/* + * Add a `nop' operation to the log. Does not close the log. + */ + +kadm5_ret_t +kadm5_log_nop (kadm5_server_context *context) +{ + krb5_storage *sp; + kadm5_ret_t ret; + kadm5_log_context *log_context = &context->log_context; + + sp = krb5_storage_emem(); + ret = kadm5_log_preamble (context, sp, kadm_nop); + if (ret) { + krb5_storage_free (sp); + return ret; + } + krb5_store_int32 (sp, 0); + krb5_store_int32 (sp, 0); + ret = kadm5_log_postamble (log_context, sp); + if (ret) { + krb5_storage_free (sp); + return ret; + } + ret = kadm5_log_flush (log_context, sp); + krb5_storage_free (sp); + + return ret; +} + +/* + * Read a `nop' log operation from `sp' and apply it. + */ + +static kadm5_ret_t +kadm5_log_replay_nop (kadm5_server_context *context, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + return 0; +} + +/* + * Call `func' for each log record in the log in `context' + */ + +kadm5_ret_t +kadm5_log_foreach (kadm5_server_context *context, + void (*func)(kadm5_server_context *server_context, + uint32_t ver, + time_t timestamp, + enum kadm_ops op, + uint32_t len, + krb5_storage *, + void *), + void *ctx) +{ + int fd = context->log_context.log_fd; + krb5_storage *sp; + + lseek (fd, 0, SEEK_SET); + sp = krb5_storage_from_fd (fd); + for (;;) { + int32_t ver, timestamp, op, len, len2, ver2; + + if(krb5_ret_int32 (sp, &ver) != 0) + break; + krb5_ret_int32 (sp, ×tamp); + krb5_ret_int32 (sp, &op); + krb5_ret_int32 (sp, &len); + (*func)(context, ver, timestamp, op, len, sp, ctx); + krb5_ret_int32 (sp, &len2); + krb5_ret_int32 (sp, &ver2); + if (len != len2) + abort(); + if (ver != ver2) + abort(); + } + krb5_storage_free(sp); + return 0; +} + +/* + * Go to end of log. + */ + +krb5_storage * +kadm5_log_goto_end (int fd) +{ + krb5_storage *sp; + + sp = krb5_storage_from_fd (fd); + krb5_storage_seek(sp, 0, SEEK_END); + return sp; +} + +/* + * Return previous log entry. + * + * The pointer in `sp´ is assumed to be at the top of the entry before + * previous entry. On success, the `sp´ pointer is set to data portion + * of previous entry. In case of error, it's not changed at all. + */ + +kadm5_ret_t +kadm5_log_previous (krb5_context context, + krb5_storage *sp, + uint32_t *ver, + time_t *timestamp, + enum kadm_ops *op, + uint32_t *len) +{ + krb5_error_code ret; + off_t off, oldoff; + int32_t tmp; + + oldoff = krb5_storage_seek(sp, 0, SEEK_CUR); + + krb5_storage_seek(sp, -8, SEEK_CUR); + ret = krb5_ret_int32 (sp, &tmp); + if (ret) + goto end_of_storage; + *len = tmp; + ret = krb5_ret_int32 (sp, &tmp); + *ver = tmp; + off = 24 + *len; + krb5_storage_seek(sp, -off, SEEK_CUR); + ret = krb5_ret_int32 (sp, &tmp); + if (ret) + goto end_of_storage; + if (tmp != *ver) { + krb5_storage_seek(sp, oldoff, SEEK_SET); + krb5_set_error_string(context, "kadm5_log_previous: log entry " + "have consistency failure, version number wrong"); + return KADM5_BAD_DB; + } + ret = krb5_ret_int32 (sp, &tmp); + if (ret) + goto end_of_storage; + *timestamp = tmp; + ret = krb5_ret_int32 (sp, &tmp); + *op = tmp; + ret = krb5_ret_int32 (sp, &tmp); + if (ret) + goto end_of_storage; + if (tmp != *len) { + krb5_storage_seek(sp, oldoff, SEEK_SET); + krb5_set_error_string(context, "kadm5_log_previous: log entry " + "have consistency failure, length wrong"); + return KADM5_BAD_DB; + } + return 0; + + end_of_storage: + krb5_storage_seek(sp, oldoff, SEEK_SET); + krb5_set_error_string(context, "kadm5_log_previous: end of storage " + "reached before end"); + return ret; +} + +/* + * Replay a record from the log + */ + +kadm5_ret_t +kadm5_log_replay (kadm5_server_context *context, + enum kadm_ops op, + uint32_t ver, + uint32_t len, + krb5_storage *sp) +{ + switch (op) { + case kadm_create : + return kadm5_log_replay_create (context, ver, len, sp); + case kadm_delete : + return kadm5_log_replay_delete (context, ver, len, sp); + case kadm_rename : + return kadm5_log_replay_rename (context, ver, len, sp); + case kadm_modify : + return kadm5_log_replay_modify (context, ver, len, sp); + case kadm_nop : + return kadm5_log_replay_nop (context, ver, len, sp); + default : + krb5_set_error_string(context->context, + "Unsupported replay op %d", (int)op); + return KADM5_FAILURE; + } +} + +/* + * truncate the log - i.e. create an empty file with just (nop vno + 2) + */ + +kadm5_ret_t +kadm5_log_truncate (kadm5_server_context *server_context) +{ + kadm5_ret_t ret; + uint32_t vno; + + ret = kadm5_log_init (server_context); + if (ret) + return ret; + + ret = kadm5_log_get_version (server_context, &vno); + if (ret) + return ret; + + ret = kadm5_log_reinit (server_context); + if (ret) + return ret; + + ret = kadm5_log_set_version (server_context, vno); + if (ret) + return ret; + + ret = kadm5_log_nop (server_context); + if (ret) + return ret; + + ret = kadm5_log_end (server_context); + if (ret) + return ret; + return 0; + +} + +static char *default_signal = NULL; +static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER; + +const char * +kadm5_log_signal_socket(krb5_context context) +{ + HEIMDAL_MUTEX_lock(&signal_mutex); + if (!default_signal) + asprintf(&default_signal, "%s/signal", hdb_db_dir(context)); + HEIMDAL_MUTEX_unlock(&signal_mutex); + + return krb5_config_get_string_default(context, + NULL, + default_signal, + "kdc", + "signal_socket", + NULL); +} |