155682Smarkm/* 2178825Sdfr * Copyright (c) 1997 - 2007 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "kadm5_locl.h" 35178825Sdfr#include "heim_threads.h" 3655682Smarkm 37178825SdfrRCSID("$Id: log.c 22211 2007-12-07 19:27:27Z lha $"); 3855682Smarkm 3955682Smarkm/* 4055682Smarkm * A log record consists of: 4155682Smarkm * 4255682Smarkm * version number 4 bytes 4355682Smarkm * time in seconds 4 bytes 4455682Smarkm * operation (enum kadm_ops) 4 bytes 4555682Smarkm * length of record 4 bytes 4655682Smarkm * data... n bytes 4755682Smarkm * length of record 4 bytes 4855682Smarkm * version number 4 bytes 4955682Smarkm * 5055682Smarkm */ 5155682Smarkm 5255682Smarkmkadm5_ret_t 5372445Sassarkadm5_log_get_version_fd (int fd, 54178825Sdfr uint32_t *ver) 5555682Smarkm{ 5655682Smarkm int ret; 5755682Smarkm krb5_storage *sp; 5855682Smarkm int32_t old_version; 5955682Smarkm 6055682Smarkm ret = lseek (fd, 0, SEEK_END); 6155682Smarkm if(ret < 0) 6255682Smarkm return errno; 6355682Smarkm if(ret == 0) { 6455682Smarkm *ver = 0; 6555682Smarkm return 0; 6655682Smarkm } 6755682Smarkm sp = krb5_storage_from_fd (fd); 68102644Snectar krb5_storage_seek(sp, -4, SEEK_CUR); 6955682Smarkm krb5_ret_int32 (sp, &old_version); 7055682Smarkm *ver = old_version; 7155682Smarkm krb5_storage_free(sp); 7255682Smarkm lseek (fd, 0, SEEK_END); 7355682Smarkm return 0; 7455682Smarkm} 7555682Smarkm 7655682Smarkmkadm5_ret_t 77178825Sdfrkadm5_log_get_version (kadm5_server_context *context, uint32_t *ver) 7872445Sassar{ 7972445Sassar return kadm5_log_get_version_fd (context->log_context.log_fd, ver); 8072445Sassar} 8172445Sassar 8272445Sassarkadm5_ret_t 83178825Sdfrkadm5_log_set_version (kadm5_server_context *context, uint32_t vno) 8472445Sassar{ 8572445Sassar kadm5_log_context *log_context = &context->log_context; 8672445Sassar 8772445Sassar log_context->version = vno; 8872445Sassar return 0; 8972445Sassar} 9072445Sassar 9172445Sassarkadm5_ret_t 9255682Smarkmkadm5_log_init (kadm5_server_context *context) 9355682Smarkm{ 9455682Smarkm int fd; 9555682Smarkm kadm5_ret_t ret; 9655682Smarkm kadm5_log_context *log_context = &context->log_context; 9755682Smarkm 9855682Smarkm if (log_context->log_fd != -1) 9955682Smarkm return 0; 10055682Smarkm fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600); 101178825Sdfr if (fd < 0) { 102178825Sdfr krb5_set_error_string(context->context, "kadm5_log_init: open %s", 103178825Sdfr log_context->log_file); 10455682Smarkm return errno; 105178825Sdfr } 10655682Smarkm if (flock (fd, LOCK_EX) < 0) { 107178825Sdfr krb5_set_error_string(context->context, "kadm5_log_init: flock %s", 108178825Sdfr log_context->log_file); 10955682Smarkm close (fd); 11055682Smarkm return errno; 11155682Smarkm } 11255682Smarkm 11372445Sassar ret = kadm5_log_get_version_fd (fd, &log_context->version); 11455682Smarkm if (ret) 11555682Smarkm return ret; 11655682Smarkm 11755682Smarkm log_context->log_fd = fd; 11855682Smarkm return 0; 11955682Smarkm} 12055682Smarkm 12155682Smarkmkadm5_ret_t 12272445Sassarkadm5_log_reinit (kadm5_server_context *context) 12372445Sassar{ 12472445Sassar int fd; 12572445Sassar kadm5_log_context *log_context = &context->log_context; 12672445Sassar 12772445Sassar if (log_context->log_fd != -1) { 128178825Sdfr flock (log_context->log_fd, LOCK_UN); 12972445Sassar close (log_context->log_fd); 13072445Sassar log_context->log_fd = -1; 13172445Sassar } 13272445Sassar fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600); 13372445Sassar if (fd < 0) 13472445Sassar return errno; 13572445Sassar if (flock (fd, LOCK_EX) < 0) { 13672445Sassar close (fd); 13772445Sassar return errno; 13872445Sassar } 13972445Sassar 14072445Sassar log_context->version = 0; 14172445Sassar log_context->log_fd = fd; 14272445Sassar return 0; 14372445Sassar} 14472445Sassar 14572445Sassar 14672445Sassarkadm5_ret_t 14755682Smarkmkadm5_log_end (kadm5_server_context *context) 14855682Smarkm{ 14955682Smarkm kadm5_log_context *log_context = &context->log_context; 15055682Smarkm int fd = log_context->log_fd; 15155682Smarkm 15255682Smarkm flock (fd, LOCK_UN); 15355682Smarkm close(fd); 15455682Smarkm log_context->log_fd = -1; 15555682Smarkm return 0; 15655682Smarkm} 15755682Smarkm 15855682Smarkmstatic kadm5_ret_t 15955682Smarkmkadm5_log_preamble (kadm5_server_context *context, 16055682Smarkm krb5_storage *sp, 16155682Smarkm enum kadm_ops op) 16255682Smarkm{ 16355682Smarkm kadm5_log_context *log_context = &context->log_context; 16455682Smarkm kadm5_ret_t kadm_ret; 16555682Smarkm 16655682Smarkm kadm_ret = kadm5_log_init (context); 16755682Smarkm if (kadm_ret) 16855682Smarkm return kadm_ret; 16955682Smarkm 17055682Smarkm krb5_store_int32 (sp, ++log_context->version); 17155682Smarkm krb5_store_int32 (sp, time(NULL)); 17255682Smarkm krb5_store_int32 (sp, op); 17355682Smarkm return 0; 17455682Smarkm} 17555682Smarkm 17655682Smarkmstatic kadm5_ret_t 17755682Smarkmkadm5_log_postamble (kadm5_log_context *context, 17855682Smarkm krb5_storage *sp) 17955682Smarkm{ 18055682Smarkm krb5_store_int32 (sp, context->version); 18155682Smarkm return 0; 18255682Smarkm} 18355682Smarkm 18455682Smarkm/* 18555682Smarkm * flush the log record in `sp'. 18655682Smarkm */ 18755682Smarkm 18855682Smarkmstatic kadm5_ret_t 18955682Smarkmkadm5_log_flush (kadm5_log_context *log_context, 19055682Smarkm krb5_storage *sp) 19155682Smarkm{ 19255682Smarkm krb5_data data; 19355682Smarkm size_t len; 19455682Smarkm int ret; 19555682Smarkm 19655682Smarkm krb5_storage_to_data(sp, &data); 19755682Smarkm len = data.length; 19855682Smarkm ret = write (log_context->log_fd, data.data, len); 19955682Smarkm if (ret != len) { 20055682Smarkm krb5_data_free(&data); 20155682Smarkm return errno; 20255682Smarkm } 20355682Smarkm if (fsync (log_context->log_fd) < 0) { 20455682Smarkm krb5_data_free(&data); 20555682Smarkm return errno; 20655682Smarkm } 20755682Smarkm /* 20855682Smarkm * Try to send a signal to any running `ipropd-master' 20955682Smarkm */ 21055682Smarkm sendto (log_context->socket_fd, 21155682Smarkm (void *)&log_context->version, 21255682Smarkm sizeof(log_context->version), 21355682Smarkm 0, 21455682Smarkm (struct sockaddr *)&log_context->socket_name, 21555682Smarkm sizeof(log_context->socket_name)); 21655682Smarkm 21755682Smarkm krb5_data_free(&data); 21855682Smarkm return 0; 21955682Smarkm} 22055682Smarkm 22155682Smarkm/* 22255682Smarkm * Add a `create' operation to the log. 22355682Smarkm */ 22455682Smarkm 22555682Smarkmkadm5_ret_t 22655682Smarkmkadm5_log_create (kadm5_server_context *context, 22755682Smarkm hdb_entry *ent) 22855682Smarkm{ 22955682Smarkm krb5_storage *sp; 23055682Smarkm kadm5_ret_t ret; 23155682Smarkm krb5_data value; 23255682Smarkm kadm5_log_context *log_context = &context->log_context; 23355682Smarkm 23455682Smarkm sp = krb5_storage_emem(); 23555682Smarkm ret = hdb_entry2value (context->context, ent, &value); 23655682Smarkm if (ret) { 23755682Smarkm krb5_storage_free(sp); 23855682Smarkm return ret; 23955682Smarkm } 24055682Smarkm ret = kadm5_log_preamble (context, sp, kadm_create); 24155682Smarkm if (ret) { 24255682Smarkm krb5_data_free (&value); 24355682Smarkm krb5_storage_free(sp); 24455682Smarkm return ret; 24555682Smarkm } 24655682Smarkm krb5_store_int32 (sp, value.length); 247102644Snectar krb5_storage_write(sp, value.data, value.length); 24855682Smarkm krb5_store_int32 (sp, value.length); 24955682Smarkm krb5_data_free (&value); 25055682Smarkm ret = kadm5_log_postamble (log_context, sp); 25155682Smarkm if (ret) { 25255682Smarkm krb5_storage_free (sp); 25355682Smarkm return ret; 25455682Smarkm } 25555682Smarkm ret = kadm5_log_flush (log_context, sp); 25655682Smarkm krb5_storage_free (sp); 25755682Smarkm if (ret) 25855682Smarkm return ret; 25955682Smarkm ret = kadm5_log_end (context); 26055682Smarkm return ret; 26155682Smarkm} 26255682Smarkm 26355682Smarkm/* 26455682Smarkm * Read the data of a create log record from `sp' and change the 26555682Smarkm * database. 26655682Smarkm */ 26755682Smarkm 268178825Sdfrstatic kadm5_ret_t 26955682Smarkmkadm5_log_replay_create (kadm5_server_context *context, 270178825Sdfr uint32_t ver, 271178825Sdfr uint32_t len, 27255682Smarkm krb5_storage *sp) 27355682Smarkm{ 27455682Smarkm krb5_error_code ret; 27555682Smarkm krb5_data data; 276178825Sdfr hdb_entry_ex ent; 27755682Smarkm 278178825Sdfr memset(&ent, 0, sizeof(ent)); 279178825Sdfr 280120945Snectar ret = krb5_data_alloc (&data, len); 281178825Sdfr if (ret) { 282178825Sdfr krb5_set_error_string(context->context, "out of memory"); 283120945Snectar return ret; 284178825Sdfr } 285102644Snectar krb5_storage_read (sp, data.data, len); 286178825Sdfr ret = hdb_value2entry (context->context, &data, &ent.entry); 28755682Smarkm krb5_data_free(&data); 288178825Sdfr if (ret) { 289178825Sdfr krb5_set_error_string(context->context, 290178825Sdfr "Unmarshaling hdb entry failed"); 29155682Smarkm return ret; 292178825Sdfr } 293178825Sdfr ret = context->db->hdb_store(context->context, context->db, 0, &ent); 29455682Smarkm hdb_free_entry (context->context, &ent); 29555682Smarkm return ret; 29655682Smarkm} 29755682Smarkm 29855682Smarkm/* 29955682Smarkm * Add a `delete' operation to the log. 30055682Smarkm */ 30155682Smarkm 30255682Smarkmkadm5_ret_t 30355682Smarkmkadm5_log_delete (kadm5_server_context *context, 30455682Smarkm krb5_principal princ) 30555682Smarkm{ 30655682Smarkm krb5_storage *sp; 30755682Smarkm kadm5_ret_t ret; 30855682Smarkm off_t off; 30955682Smarkm off_t len; 31055682Smarkm kadm5_log_context *log_context = &context->log_context; 31155682Smarkm 31255682Smarkm sp = krb5_storage_emem(); 313178825Sdfr if (sp == NULL) 314178825Sdfr return ENOMEM; 31555682Smarkm ret = kadm5_log_preamble (context, sp, kadm_delete); 316178825Sdfr if (ret) 317178825Sdfr goto out; 318178825Sdfr ret = krb5_store_int32 (sp, 0); 319178825Sdfr if (ret) 320178825Sdfr goto out; 321102644Snectar off = krb5_storage_seek (sp, 0, SEEK_CUR); 322178825Sdfr ret = krb5_store_principal (sp, princ); 323178825Sdfr if (ret) 324178825Sdfr goto out; 325102644Snectar len = krb5_storage_seek (sp, 0, SEEK_CUR) - off; 326102644Snectar krb5_storage_seek(sp, -(len + 4), SEEK_CUR); 327178825Sdfr ret = krb5_store_int32 (sp, len); 328178825Sdfr if (ret) 329178825Sdfr goto out; 330102644Snectar krb5_storage_seek(sp, len, SEEK_CUR); 331178825Sdfr ret = krb5_store_int32 (sp, len); 332178825Sdfr if (ret) 333178825Sdfr goto out; 33455682Smarkm ret = kadm5_log_postamble (log_context, sp); 335178825Sdfr if (ret) 336178825Sdfr goto out; 33755682Smarkm ret = kadm5_log_flush (log_context, sp); 33855682Smarkm if (ret) 339178825Sdfr goto out; 34055682Smarkm ret = kadm5_log_end (context); 341178825Sdfrout: 342178825Sdfr krb5_storage_free (sp); 34355682Smarkm return ret; 34455682Smarkm} 34555682Smarkm 34655682Smarkm/* 34755682Smarkm * Read a `delete' log operation from `sp' and apply it. 34855682Smarkm */ 34955682Smarkm 350178825Sdfrstatic kadm5_ret_t 35155682Smarkmkadm5_log_replay_delete (kadm5_server_context *context, 352178825Sdfr uint32_t ver, 353178825Sdfr uint32_t len, 35455682Smarkm krb5_storage *sp) 35555682Smarkm{ 35655682Smarkm krb5_error_code ret; 357178825Sdfr krb5_principal principal; 35855682Smarkm 359178825Sdfr ret = krb5_ret_principal (sp, &principal); 360178825Sdfr if (ret) { 361178825Sdfr krb5_set_error_string(context->context, "Failed to read deleted " 362178825Sdfr "principal from log version: %ld", (long)ver); 363178825Sdfr return ret; 364178825Sdfr } 36555682Smarkm 366178825Sdfr ret = context->db->hdb_remove(context->context, context->db, principal); 367178825Sdfr krb5_free_principal (context->context, principal); 36855682Smarkm return ret; 36955682Smarkm} 37055682Smarkm 37155682Smarkm/* 37255682Smarkm * Add a `rename' operation to the log. 37355682Smarkm */ 37455682Smarkm 37555682Smarkmkadm5_ret_t 37655682Smarkmkadm5_log_rename (kadm5_server_context *context, 37755682Smarkm krb5_principal source, 37855682Smarkm hdb_entry *ent) 37955682Smarkm{ 38055682Smarkm krb5_storage *sp; 38155682Smarkm kadm5_ret_t ret; 38255682Smarkm off_t off; 38355682Smarkm off_t len; 38455682Smarkm krb5_data value; 38555682Smarkm kadm5_log_context *log_context = &context->log_context; 38655682Smarkm 387178825Sdfr krb5_data_zero(&value); 388178825Sdfr 38955682Smarkm sp = krb5_storage_emem(); 39055682Smarkm ret = hdb_entry2value (context->context, ent, &value); 391178825Sdfr if (ret) 392178825Sdfr goto failed; 393178825Sdfr 39455682Smarkm ret = kadm5_log_preamble (context, sp, kadm_rename); 395178825Sdfr if (ret) 396178825Sdfr goto failed; 397178825Sdfr 398178825Sdfr ret = krb5_store_int32 (sp, 0); 399178825Sdfr if (ret) 400178825Sdfr goto failed; 401102644Snectar off = krb5_storage_seek (sp, 0, SEEK_CUR); 402178825Sdfr ret = krb5_store_principal (sp, source); 403178825Sdfr if (ret) 404178825Sdfr goto failed; 405178825Sdfr 406102644Snectar krb5_storage_write(sp, value.data, value.length); 407102644Snectar len = krb5_storage_seek (sp, 0, SEEK_CUR) - off; 40855682Smarkm 409102644Snectar krb5_storage_seek(sp, -(len + 4), SEEK_CUR); 410178825Sdfr ret = krb5_store_int32 (sp, len); 411178825Sdfr if (ret) 412178825Sdfr goto failed; 413178825Sdfr 414102644Snectar krb5_storage_seek(sp, len, SEEK_CUR); 415178825Sdfr ret = krb5_store_int32 (sp, len); 416178825Sdfr if (ret) 417178825Sdfr goto failed; 418178825Sdfr 41955682Smarkm ret = kadm5_log_postamble (log_context, sp); 420178825Sdfr if (ret) 421178825Sdfr goto failed; 422178825Sdfr 42355682Smarkm ret = kadm5_log_flush (log_context, sp); 424178825Sdfr if (ret) 425178825Sdfr goto failed; 42655682Smarkm krb5_storage_free (sp); 427178825Sdfr krb5_data_free (&value); 428178825Sdfr 429178825Sdfr return kadm5_log_end (context); 430178825Sdfr 431178825Sdfrfailed: 432178825Sdfr krb5_data_free(&value); 433178825Sdfr krb5_storage_free(sp); 43455682Smarkm return ret; 43555682Smarkm} 43655682Smarkm 43755682Smarkm/* 43855682Smarkm * Read a `rename' log operation from `sp' and apply it. 43955682Smarkm */ 44055682Smarkm 441178825Sdfrstatic kadm5_ret_t 44255682Smarkmkadm5_log_replay_rename (kadm5_server_context *context, 443178825Sdfr uint32_t ver, 444178825Sdfr uint32_t len, 44555682Smarkm krb5_storage *sp) 44655682Smarkm{ 44755682Smarkm krb5_error_code ret; 44855682Smarkm krb5_principal source; 449178825Sdfr hdb_entry_ex target_ent; 45055682Smarkm krb5_data value; 45155682Smarkm off_t off; 45255682Smarkm size_t princ_len, data_len; 45355682Smarkm 454178825Sdfr memset(&target_ent, 0, sizeof(target_ent)); 455178825Sdfr 456102644Snectar off = krb5_storage_seek(sp, 0, SEEK_CUR); 457178825Sdfr ret = krb5_ret_principal (sp, &source); 458178825Sdfr if (ret) { 459178825Sdfr krb5_set_error_string(context->context, "Failed to read renamed " 460178825Sdfr "principal in log, version: %ld", (long)ver); 461178825Sdfr return ret; 462178825Sdfr } 463102644Snectar princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off; 46455682Smarkm data_len = len - princ_len; 465120945Snectar ret = krb5_data_alloc (&value, data_len); 466120945Snectar if (ret) { 467120945Snectar krb5_free_principal (context->context, source); 468120945Snectar return ret; 469120945Snectar } 470102644Snectar krb5_storage_read (sp, value.data, data_len); 471178825Sdfr ret = hdb_value2entry (context->context, &value, &target_ent.entry); 47255682Smarkm krb5_data_free(&value); 47355682Smarkm if (ret) { 47455682Smarkm krb5_free_principal (context->context, source); 47555682Smarkm return ret; 47655682Smarkm } 477178825Sdfr ret = context->db->hdb_store (context->context, context->db, 478178825Sdfr 0, &target_ent); 47955682Smarkm hdb_free_entry (context->context, &target_ent); 48055682Smarkm if (ret) { 48155682Smarkm krb5_free_principal (context->context, source); 48255682Smarkm return ret; 48355682Smarkm } 484178825Sdfr ret = context->db->hdb_remove (context->context, context->db, source); 48555682Smarkm krb5_free_principal (context->context, source); 48655682Smarkm return ret; 48755682Smarkm} 48855682Smarkm 48955682Smarkm 49055682Smarkm/* 49155682Smarkm * Add a `modify' operation to the log. 49255682Smarkm */ 49355682Smarkm 49455682Smarkmkadm5_ret_t 49555682Smarkmkadm5_log_modify (kadm5_server_context *context, 49655682Smarkm hdb_entry *ent, 497178825Sdfr uint32_t mask) 49855682Smarkm{ 49955682Smarkm krb5_storage *sp; 50055682Smarkm kadm5_ret_t ret; 50155682Smarkm krb5_data value; 502178825Sdfr uint32_t len; 50355682Smarkm kadm5_log_context *log_context = &context->log_context; 50455682Smarkm 505178825Sdfr krb5_data_zero(&value); 506178825Sdfr 50755682Smarkm sp = krb5_storage_emem(); 50855682Smarkm ret = hdb_entry2value (context->context, ent, &value); 509178825Sdfr if (ret) 510178825Sdfr goto failed; 511178825Sdfr 51255682Smarkm ret = kadm5_log_preamble (context, sp, kadm_modify); 513178825Sdfr if (ret) 514178825Sdfr goto failed; 515178825Sdfr 51655682Smarkm len = value.length + 4; 517178825Sdfr ret = krb5_store_int32 (sp, len); 518178825Sdfr if (ret) 519178825Sdfr goto failed; 520178825Sdfr ret = krb5_store_int32 (sp, mask); 521178825Sdfr if (ret) 522178825Sdfr goto failed; 523102644Snectar krb5_storage_write (sp, value.data, value.length); 524178825Sdfr 525178825Sdfr ret = krb5_store_int32 (sp, len); 526178825Sdfr if (ret) 527178825Sdfr goto failed; 52855682Smarkm ret = kadm5_log_postamble (log_context, sp); 529178825Sdfr if (ret) 530178825Sdfr goto failed; 53155682Smarkm ret = kadm5_log_flush (log_context, sp); 532178825Sdfr if (ret) 533178825Sdfr goto failed; 534178825Sdfr krb5_data_free(&value); 53555682Smarkm krb5_storage_free (sp); 536178825Sdfr return kadm5_log_end (context); 537178825Sdfrfailed: 538178825Sdfr krb5_data_free(&value); 539178825Sdfr krb5_storage_free(sp); 54055682Smarkm return ret; 54155682Smarkm} 54255682Smarkm 54355682Smarkm/* 54455682Smarkm * Read a `modify' log operation from `sp' and apply it. 54555682Smarkm */ 54655682Smarkm 547178825Sdfrstatic kadm5_ret_t 54855682Smarkmkadm5_log_replay_modify (kadm5_server_context *context, 549178825Sdfr uint32_t ver, 550178825Sdfr uint32_t len, 55155682Smarkm krb5_storage *sp) 55255682Smarkm{ 55355682Smarkm krb5_error_code ret; 55455682Smarkm int32_t mask; 55555682Smarkm krb5_data value; 556178825Sdfr hdb_entry_ex ent, log_ent; 55755682Smarkm 558178825Sdfr memset(&log_ent, 0, sizeof(log_ent)); 559178825Sdfr 56055682Smarkm krb5_ret_int32 (sp, &mask); 56155682Smarkm len -= 4; 562120945Snectar ret = krb5_data_alloc (&value, len); 563178825Sdfr if (ret) { 564178825Sdfr krb5_set_error_string(context->context, "out of memory"); 565120945Snectar return ret; 566178825Sdfr } 567102644Snectar krb5_storage_read (sp, value.data, len); 568178825Sdfr ret = hdb_value2entry (context->context, &value, &log_ent.entry); 56955682Smarkm krb5_data_free(&value); 57055682Smarkm if (ret) 57155682Smarkm return ret; 572178825Sdfr 573178825Sdfr memset(&ent, 0, sizeof(ent)); 574178825Sdfr ret = context->db->hdb_fetch(context->context, context->db, 575178825Sdfr log_ent.entry.principal, 576178825Sdfr HDB_F_DECRYPT|HDB_F_GET_ANY, &ent); 57755682Smarkm if (ret) 578178825Sdfr goto out; 57955682Smarkm if (mask & KADM5_PRINC_EXPIRE_TIME) { 580178825Sdfr if (log_ent.entry.valid_end == NULL) { 581178825Sdfr ent.entry.valid_end = NULL; 58272445Sassar } else { 583178825Sdfr if (ent.entry.valid_end == NULL) { 584178825Sdfr ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end)); 585178825Sdfr if (ent.entry.valid_end == NULL) { 586178825Sdfr krb5_set_error_string(context->context, "out of memory"); 587178825Sdfr ret = ENOMEM; 588178825Sdfr goto out; 589178825Sdfr } 590178825Sdfr } 591178825Sdfr *ent.entry.valid_end = *log_ent.entry.valid_end; 59272445Sassar } 59355682Smarkm } 59455682Smarkm if (mask & KADM5_PW_EXPIRATION) { 595178825Sdfr if (log_ent.entry.pw_end == NULL) { 596178825Sdfr ent.entry.pw_end = NULL; 59772445Sassar } else { 598178825Sdfr if (ent.entry.pw_end == NULL) { 599178825Sdfr ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end)); 600178825Sdfr if (ent.entry.pw_end == NULL) { 601178825Sdfr krb5_set_error_string(context->context, "out of memory"); 602178825Sdfr ret = ENOMEM; 603178825Sdfr goto out; 604178825Sdfr } 605178825Sdfr } 606178825Sdfr *ent.entry.pw_end = *log_ent.entry.pw_end; 60772445Sassar } 60855682Smarkm } 60955682Smarkm if (mask & KADM5_LAST_PWD_CHANGE) { 61055682Smarkm abort (); /* XXX */ 61155682Smarkm } 61255682Smarkm if (mask & KADM5_ATTRIBUTES) { 613178825Sdfr ent.entry.flags = log_ent.entry.flags; 61455682Smarkm } 61555682Smarkm if (mask & KADM5_MAX_LIFE) { 616178825Sdfr if (log_ent.entry.max_life == NULL) { 617178825Sdfr ent.entry.max_life = NULL; 61872445Sassar } else { 619178825Sdfr if (ent.entry.max_life == NULL) { 620178825Sdfr ent.entry.max_life = malloc (sizeof(*ent.entry.max_life)); 621178825Sdfr if (ent.entry.max_life == NULL) { 622178825Sdfr krb5_set_error_string(context->context, "out of memory"); 623178825Sdfr ret = ENOMEM; 624178825Sdfr goto out; 625178825Sdfr } 626178825Sdfr } 627178825Sdfr *ent.entry.max_life = *log_ent.entry.max_life; 62872445Sassar } 62955682Smarkm } 63055682Smarkm if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) { 631178825Sdfr if (ent.entry.modified_by == NULL) { 632178825Sdfr ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by)); 633178825Sdfr if (ent.entry.modified_by == NULL) { 634178825Sdfr krb5_set_error_string(context->context, "out of memory"); 635178825Sdfr ret = ENOMEM; 636178825Sdfr goto out; 637178825Sdfr } 63855682Smarkm } else 639178825Sdfr free_Event(ent.entry.modified_by); 640178825Sdfr ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by); 641178825Sdfr if (ret) { 642178825Sdfr krb5_set_error_string(context->context, "out of memory"); 643178825Sdfr goto out; 644178825Sdfr } 64555682Smarkm } 64655682Smarkm if (mask & KADM5_KVNO) { 647178825Sdfr ent.entry.kvno = log_ent.entry.kvno; 64855682Smarkm } 64955682Smarkm if (mask & KADM5_MKVNO) { 65055682Smarkm abort (); /* XXX */ 65155682Smarkm } 65255682Smarkm if (mask & KADM5_AUX_ATTRIBUTES) { 65355682Smarkm abort (); /* XXX */ 65455682Smarkm } 65555682Smarkm if (mask & KADM5_POLICY) { 65655682Smarkm abort (); /* XXX */ 65755682Smarkm } 65855682Smarkm if (mask & KADM5_POLICY_CLR) { 65955682Smarkm abort (); /* XXX */ 66055682Smarkm } 66155682Smarkm if (mask & KADM5_MAX_RLIFE) { 662178825Sdfr if (log_ent.entry.max_renew == NULL) { 663178825Sdfr ent.entry.max_renew = NULL; 66472445Sassar } else { 665178825Sdfr if (ent.entry.max_renew == NULL) { 666178825Sdfr ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew)); 667178825Sdfr if (ent.entry.max_renew == NULL) { 668178825Sdfr krb5_set_error_string(context->context, "out of memory"); 669178825Sdfr ret = ENOMEM; 670178825Sdfr goto out; 671178825Sdfr } 672178825Sdfr } 673178825Sdfr *ent.entry.max_renew = *log_ent.entry.max_renew; 67472445Sassar } 67555682Smarkm } 67655682Smarkm if (mask & KADM5_LAST_SUCCESS) { 67755682Smarkm abort (); /* XXX */ 67855682Smarkm } 67955682Smarkm if (mask & KADM5_LAST_FAILED) { 68055682Smarkm abort (); /* XXX */ 68155682Smarkm } 68255682Smarkm if (mask & KADM5_FAIL_AUTH_COUNT) { 68355682Smarkm abort (); /* XXX */ 68455682Smarkm } 68555682Smarkm if (mask & KADM5_KEY_DATA) { 686178825Sdfr size_t num; 68755682Smarkm int i; 68855682Smarkm 689178825Sdfr for (i = 0; i < ent.entry.keys.len; ++i) 690178825Sdfr free_Key(&ent.entry.keys.val[i]); 691178825Sdfr free (ent.entry.keys.val); 69255682Smarkm 693178825Sdfr num = log_ent.entry.keys.len; 69455682Smarkm 695178825Sdfr ent.entry.keys.len = num; 696178825Sdfr ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val)); 697178825Sdfr if (ent.entry.keys.val == NULL) { 698178825Sdfr krb5_set_error_string(context->context, "out of memory"); 699178825Sdfr return ENOMEM; 700178825Sdfr } 701178825Sdfr for (i = 0; i < ent.entry.keys.len; ++i) { 702178825Sdfr ret = copy_Key(&log_ent.entry.keys.val[i], 703178825Sdfr &ent.entry.keys.val[i]); 704178825Sdfr if (ret) { 705178825Sdfr krb5_set_error_string(context->context, "out of memory"); 706178825Sdfr goto out; 707178825Sdfr } 708178825Sdfr } 70955682Smarkm } 710178825Sdfr if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) { 711178825Sdfr HDB_extensions *es = ent.entry.extensions; 712178825Sdfr 713178825Sdfr ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions)); 714178825Sdfr if (ent.entry.extensions == NULL) 715178825Sdfr goto out; 716178825Sdfr 717178825Sdfr ret = copy_HDB_extensions(log_ent.entry.extensions, 718178825Sdfr ent.entry.extensions); 719178825Sdfr if (ret) { 720178825Sdfr krb5_set_error_string(context->context, "out of memory"); 721178825Sdfr free(ent.entry.extensions); 722178825Sdfr ent.entry.extensions = es; 723178825Sdfr goto out; 724178825Sdfr } 725178825Sdfr if (es) { 726178825Sdfr free_HDB_extensions(es); 727178825Sdfr free(es); 728178825Sdfr } 729178825Sdfr } 730178825Sdfr ret = context->db->hdb_store(context->context, context->db, 731178825Sdfr HDB_F_REPLACE, &ent); 732178825Sdfr out: 73355682Smarkm hdb_free_entry (context->context, &ent); 73455682Smarkm hdb_free_entry (context->context, &log_ent); 73555682Smarkm return ret; 73655682Smarkm} 73755682Smarkm 73855682Smarkm/* 739178825Sdfr * Add a `nop' operation to the log. Does not close the log. 74072445Sassar */ 74172445Sassar 74272445Sassarkadm5_ret_t 74372445Sassarkadm5_log_nop (kadm5_server_context *context) 74472445Sassar{ 74572445Sassar krb5_storage *sp; 74672445Sassar kadm5_ret_t ret; 74772445Sassar kadm5_log_context *log_context = &context->log_context; 74872445Sassar 74972445Sassar sp = krb5_storage_emem(); 75072445Sassar ret = kadm5_log_preamble (context, sp, kadm_nop); 75172445Sassar if (ret) { 75272445Sassar krb5_storage_free (sp); 75372445Sassar return ret; 75472445Sassar } 75572445Sassar krb5_store_int32 (sp, 0); 75672445Sassar krb5_store_int32 (sp, 0); 75772445Sassar ret = kadm5_log_postamble (log_context, sp); 75872445Sassar if (ret) { 75972445Sassar krb5_storage_free (sp); 76072445Sassar return ret; 76172445Sassar } 76272445Sassar ret = kadm5_log_flush (log_context, sp); 76372445Sassar krb5_storage_free (sp); 764178825Sdfr 76572445Sassar return ret; 76672445Sassar} 76772445Sassar 76872445Sassar/* 76972445Sassar * Read a `nop' log operation from `sp' and apply it. 77072445Sassar */ 77172445Sassar 772178825Sdfrstatic kadm5_ret_t 77372445Sassarkadm5_log_replay_nop (kadm5_server_context *context, 774178825Sdfr uint32_t ver, 775178825Sdfr uint32_t len, 77672445Sassar krb5_storage *sp) 77772445Sassar{ 77872445Sassar return 0; 77972445Sassar} 78072445Sassar 78172445Sassar/* 78255682Smarkm * Call `func' for each log record in the log in `context' 78355682Smarkm */ 78455682Smarkm 78555682Smarkmkadm5_ret_t 78655682Smarkmkadm5_log_foreach (kadm5_server_context *context, 78755682Smarkm void (*func)(kadm5_server_context *server_context, 788178825Sdfr uint32_t ver, 78955682Smarkm time_t timestamp, 79055682Smarkm enum kadm_ops op, 791178825Sdfr uint32_t len, 792178825Sdfr krb5_storage *, 793178825Sdfr void *), 794178825Sdfr void *ctx) 79555682Smarkm{ 79655682Smarkm int fd = context->log_context.log_fd; 79755682Smarkm krb5_storage *sp; 79855682Smarkm 79955682Smarkm lseek (fd, 0, SEEK_SET); 80055682Smarkm sp = krb5_storage_from_fd (fd); 80155682Smarkm for (;;) { 802178825Sdfr int32_t ver, timestamp, op, len, len2, ver2; 80355682Smarkm 80455682Smarkm if(krb5_ret_int32 (sp, &ver) != 0) 80555682Smarkm break; 80655682Smarkm krb5_ret_int32 (sp, ×tamp); 80755682Smarkm krb5_ret_int32 (sp, &op); 80855682Smarkm krb5_ret_int32 (sp, &len); 809178825Sdfr (*func)(context, ver, timestamp, op, len, sp, ctx); 810178825Sdfr krb5_ret_int32 (sp, &len2); 811178825Sdfr krb5_ret_int32 (sp, &ver2); 812178825Sdfr if (len != len2) 813178825Sdfr abort(); 814178825Sdfr if (ver != ver2) 815178825Sdfr abort(); 81655682Smarkm } 817178825Sdfr krb5_storage_free(sp); 81855682Smarkm return 0; 81955682Smarkm} 82055682Smarkm 82155682Smarkm/* 82255682Smarkm * Go to end of log. 82355682Smarkm */ 82455682Smarkm 82555682Smarkmkrb5_storage * 82655682Smarkmkadm5_log_goto_end (int fd) 82755682Smarkm{ 82855682Smarkm krb5_storage *sp; 82955682Smarkm 83055682Smarkm sp = krb5_storage_from_fd (fd); 831102644Snectar krb5_storage_seek(sp, 0, SEEK_END); 83255682Smarkm return sp; 83355682Smarkm} 83455682Smarkm 83555682Smarkm/* 83655682Smarkm * Return previous log entry. 837178825Sdfr * 838178825Sdfr * The pointer in `sp� is assumed to be at the top of the entry before 839178825Sdfr * previous entry. On success, the `sp� pointer is set to data portion 840178825Sdfr * of previous entry. In case of error, it's not changed at all. 84155682Smarkm */ 84255682Smarkm 84355682Smarkmkadm5_ret_t 844178825Sdfrkadm5_log_previous (krb5_context context, 845178825Sdfr krb5_storage *sp, 846178825Sdfr uint32_t *ver, 84755682Smarkm time_t *timestamp, 84855682Smarkm enum kadm_ops *op, 849178825Sdfr uint32_t *len) 85055682Smarkm{ 851178825Sdfr krb5_error_code ret; 852178825Sdfr off_t off, oldoff; 85355682Smarkm int32_t tmp; 85455682Smarkm 855178825Sdfr oldoff = krb5_storage_seek(sp, 0, SEEK_CUR); 856178825Sdfr 857102644Snectar krb5_storage_seek(sp, -8, SEEK_CUR); 858178825Sdfr ret = krb5_ret_int32 (sp, &tmp); 859178825Sdfr if (ret) 860178825Sdfr goto end_of_storage; 86155682Smarkm *len = tmp; 862178825Sdfr ret = krb5_ret_int32 (sp, &tmp); 86355682Smarkm *ver = tmp; 86455682Smarkm off = 24 + *len; 865102644Snectar krb5_storage_seek(sp, -off, SEEK_CUR); 866178825Sdfr ret = krb5_ret_int32 (sp, &tmp); 867178825Sdfr if (ret) 868178825Sdfr goto end_of_storage; 869178825Sdfr if (tmp != *ver) { 870178825Sdfr krb5_storage_seek(sp, oldoff, SEEK_SET); 871178825Sdfr krb5_set_error_string(context, "kadm5_log_previous: log entry " 872178825Sdfr "have consistency failure, version number wrong"); 873178825Sdfr return KADM5_BAD_DB; 874178825Sdfr } 875178825Sdfr ret = krb5_ret_int32 (sp, &tmp); 876178825Sdfr if (ret) 877178825Sdfr goto end_of_storage; 87855682Smarkm *timestamp = tmp; 879178825Sdfr ret = krb5_ret_int32 (sp, &tmp); 88055682Smarkm *op = tmp; 881178825Sdfr ret = krb5_ret_int32 (sp, &tmp); 882178825Sdfr if (ret) 883178825Sdfr goto end_of_storage; 884178825Sdfr if (tmp != *len) { 885178825Sdfr krb5_storage_seek(sp, oldoff, SEEK_SET); 886178825Sdfr krb5_set_error_string(context, "kadm5_log_previous: log entry " 887178825Sdfr "have consistency failure, length wrong"); 888178825Sdfr return KADM5_BAD_DB; 889178825Sdfr } 89055682Smarkm return 0; 891178825Sdfr 892178825Sdfr end_of_storage: 893178825Sdfr krb5_storage_seek(sp, oldoff, SEEK_SET); 894178825Sdfr krb5_set_error_string(context, "kadm5_log_previous: end of storage " 895178825Sdfr "reached before end"); 896178825Sdfr return ret; 89755682Smarkm} 89855682Smarkm 89955682Smarkm/* 90055682Smarkm * Replay a record from the log 90155682Smarkm */ 90255682Smarkm 90355682Smarkmkadm5_ret_t 90455682Smarkmkadm5_log_replay (kadm5_server_context *context, 90555682Smarkm enum kadm_ops op, 906178825Sdfr uint32_t ver, 907178825Sdfr uint32_t len, 90855682Smarkm krb5_storage *sp) 90955682Smarkm{ 91055682Smarkm switch (op) { 91155682Smarkm case kadm_create : 91255682Smarkm return kadm5_log_replay_create (context, ver, len, sp); 91355682Smarkm case kadm_delete : 91455682Smarkm return kadm5_log_replay_delete (context, ver, len, sp); 91555682Smarkm case kadm_rename : 91655682Smarkm return kadm5_log_replay_rename (context, ver, len, sp); 91755682Smarkm case kadm_modify : 91855682Smarkm return kadm5_log_replay_modify (context, ver, len, sp); 91972445Sassar case kadm_nop : 92072445Sassar return kadm5_log_replay_nop (context, ver, len, sp); 92155682Smarkm default : 922178825Sdfr krb5_set_error_string(context->context, 923178825Sdfr "Unsupported replay op %d", (int)op); 92455682Smarkm return KADM5_FAILURE; 92555682Smarkm } 92655682Smarkm} 92772445Sassar 92872445Sassar/* 92972445Sassar * truncate the log - i.e. create an empty file with just (nop vno + 2) 93072445Sassar */ 93172445Sassar 93272445Sassarkadm5_ret_t 93372445Sassarkadm5_log_truncate (kadm5_server_context *server_context) 93472445Sassar{ 93572445Sassar kadm5_ret_t ret; 936178825Sdfr uint32_t vno; 93772445Sassar 93872445Sassar ret = kadm5_log_init (server_context); 93972445Sassar if (ret) 94072445Sassar return ret; 94172445Sassar 94272445Sassar ret = kadm5_log_get_version (server_context, &vno); 94372445Sassar if (ret) 94472445Sassar return ret; 94572445Sassar 94672445Sassar ret = kadm5_log_reinit (server_context); 94772445Sassar if (ret) 94872445Sassar return ret; 94972445Sassar 950178825Sdfr ret = kadm5_log_set_version (server_context, vno); 95172445Sassar if (ret) 95272445Sassar return ret; 95372445Sassar 95472445Sassar ret = kadm5_log_nop (server_context); 95572445Sassar if (ret) 95672445Sassar return ret; 95772445Sassar 95872445Sassar ret = kadm5_log_end (server_context); 95972445Sassar if (ret) 96072445Sassar return ret; 96172445Sassar return 0; 96272445Sassar 96372445Sassar} 964178825Sdfr 965178825Sdfrstatic char *default_signal = NULL; 966178825Sdfrstatic HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER; 967178825Sdfr 968178825Sdfrconst char * 969178825Sdfrkadm5_log_signal_socket(krb5_context context) 970178825Sdfr{ 971178825Sdfr HEIMDAL_MUTEX_lock(&signal_mutex); 972178825Sdfr if (!default_signal) 973178825Sdfr asprintf(&default_signal, "%s/signal", hdb_db_dir(context)); 974178825Sdfr HEIMDAL_MUTEX_unlock(&signal_mutex); 975178825Sdfr 976178825Sdfr return krb5_config_get_string_default(context, 977178825Sdfr NULL, 978178825Sdfr default_signal, 979178825Sdfr "kdc", 980178825Sdfr "signal_socket", 981178825Sdfr NULL); 982178825Sdfr} 983