log.c revision 72445
155682Smarkm/*
272445Sassar * Copyright (c) 1997 - 2000 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"
3555682Smarkm
3672445SassarRCSID("$Id: log.c,v 1.18 2000/07/24 04:32:17 assar Exp $");
3755682Smarkm
3855682Smarkm/*
3955682Smarkm * A log record consists of:
4055682Smarkm *
4155682Smarkm * version number		4 bytes
4255682Smarkm * time in seconds		4 bytes
4355682Smarkm * operation (enum kadm_ops)	4 bytes
4455682Smarkm * length of record		4 bytes
4555682Smarkm * data...			n bytes
4655682Smarkm * length of record		4 bytes
4755682Smarkm * version number		4 bytes
4855682Smarkm *
4955682Smarkm */
5055682Smarkm
5155682Smarkmkadm5_ret_t
5272445Sassarkadm5_log_get_version_fd (int fd,
5372445Sassar			  u_int32_t *ver)
5455682Smarkm{
5555682Smarkm    int ret;
5655682Smarkm    krb5_storage *sp;
5755682Smarkm    int32_t old_version;
5855682Smarkm
5955682Smarkm    ret = lseek (fd, 0, SEEK_END);
6055682Smarkm    if(ret < 0)
6155682Smarkm	return errno;
6255682Smarkm    if(ret == 0) {
6355682Smarkm	*ver = 0;
6455682Smarkm	return 0;
6555682Smarkm    }
6655682Smarkm    sp = krb5_storage_from_fd (fd);
6755682Smarkm    sp->seek(sp, -4, SEEK_CUR);
6855682Smarkm    krb5_ret_int32 (sp, &old_version);
6955682Smarkm    *ver = old_version;
7055682Smarkm    krb5_storage_free(sp);
7155682Smarkm    lseek (fd, 0, SEEK_END);
7255682Smarkm    return 0;
7355682Smarkm}
7455682Smarkm
7555682Smarkmkadm5_ret_t
7672445Sassarkadm5_log_get_version (kadm5_server_context *context, u_int32_t *ver)
7772445Sassar{
7872445Sassar    return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
7972445Sassar}
8072445Sassar
8172445Sassarkadm5_ret_t
8272445Sassarkadm5_log_set_version (kadm5_server_context *context, u_int32_t vno)
8372445Sassar{
8472445Sassar    kadm5_log_context *log_context = &context->log_context;
8572445Sassar
8672445Sassar    log_context->version = vno;
8772445Sassar    return 0;
8872445Sassar}
8972445Sassar
9072445Sassarkadm5_ret_t
9155682Smarkmkadm5_log_init (kadm5_server_context *context)
9255682Smarkm{
9355682Smarkm    int fd;
9455682Smarkm    kadm5_ret_t ret;
9555682Smarkm    kadm5_log_context *log_context = &context->log_context;
9655682Smarkm
9755682Smarkm    if (log_context->log_fd != -1)
9855682Smarkm	return 0;
9955682Smarkm    fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
10055682Smarkm    if (fd < 0)
10155682Smarkm	return errno;
10255682Smarkm    if (flock (fd, LOCK_EX) < 0) {
10355682Smarkm	close (fd);
10455682Smarkm	return errno;
10555682Smarkm    }
10655682Smarkm
10772445Sassar    ret = kadm5_log_get_version_fd (fd, &log_context->version);
10855682Smarkm    if (ret)
10955682Smarkm	return ret;
11055682Smarkm
11155682Smarkm    log_context->log_fd  = fd;
11255682Smarkm    return 0;
11355682Smarkm}
11455682Smarkm
11555682Smarkmkadm5_ret_t
11672445Sassarkadm5_log_reinit (kadm5_server_context *context)
11772445Sassar{
11872445Sassar    int fd;
11972445Sassar    kadm5_log_context *log_context = &context->log_context;
12072445Sassar
12172445Sassar    if (log_context->log_fd != -1) {
12272445Sassar	close (log_context->log_fd);
12372445Sassar	log_context->log_fd = -1;
12472445Sassar    }
12572445Sassar    fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
12672445Sassar    if (fd < 0)
12772445Sassar	return errno;
12872445Sassar    if (flock (fd, LOCK_EX) < 0) {
12972445Sassar	close (fd);
13072445Sassar	return errno;
13172445Sassar    }
13272445Sassar
13372445Sassar    log_context->version = 0;
13472445Sassar    log_context->log_fd  = fd;
13572445Sassar    return 0;
13672445Sassar}
13772445Sassar
13872445Sassar
13972445Sassarkadm5_ret_t
14055682Smarkmkadm5_log_end (kadm5_server_context *context)
14155682Smarkm{
14255682Smarkm    kadm5_log_context *log_context = &context->log_context;
14355682Smarkm    int fd = log_context->log_fd;
14455682Smarkm
14555682Smarkm    flock (fd, LOCK_UN);
14655682Smarkm    close(fd);
14755682Smarkm    log_context->log_fd = -1;
14855682Smarkm    return 0;
14955682Smarkm}
15055682Smarkm
15155682Smarkmstatic kadm5_ret_t
15255682Smarkmkadm5_log_preamble (kadm5_server_context *context,
15355682Smarkm		    krb5_storage *sp,
15455682Smarkm		    enum kadm_ops op)
15555682Smarkm{
15655682Smarkm    kadm5_log_context *log_context = &context->log_context;
15755682Smarkm    kadm5_ret_t kadm_ret;
15855682Smarkm
15955682Smarkm    kadm_ret = kadm5_log_init (context);
16055682Smarkm    if (kadm_ret)
16155682Smarkm	return kadm_ret;
16255682Smarkm
16355682Smarkm    krb5_store_int32 (sp, ++log_context->version);
16455682Smarkm    krb5_store_int32 (sp, time(NULL));
16555682Smarkm    krb5_store_int32 (sp, op);
16655682Smarkm    return 0;
16755682Smarkm}
16855682Smarkm
16955682Smarkmstatic kadm5_ret_t
17055682Smarkmkadm5_log_postamble (kadm5_log_context *context,
17155682Smarkm		     krb5_storage *sp)
17255682Smarkm{
17355682Smarkm    krb5_store_int32 (sp, context->version);
17455682Smarkm    return 0;
17555682Smarkm}
17655682Smarkm
17755682Smarkm/*
17855682Smarkm * flush the log record in `sp'.
17955682Smarkm */
18055682Smarkm
18155682Smarkmstatic kadm5_ret_t
18255682Smarkmkadm5_log_flush (kadm5_log_context *log_context,
18355682Smarkm		 krb5_storage *sp)
18455682Smarkm{
18555682Smarkm    krb5_data data;
18655682Smarkm    size_t len;
18755682Smarkm    int ret;
18855682Smarkm
18955682Smarkm    krb5_storage_to_data(sp, &data);
19055682Smarkm    len = data.length;
19155682Smarkm    ret = write (log_context->log_fd, data.data, len);
19255682Smarkm    if (ret != len) {
19355682Smarkm	krb5_data_free(&data);
19455682Smarkm	return errno;
19555682Smarkm    }
19655682Smarkm    if (fsync (log_context->log_fd) < 0) {
19755682Smarkm	krb5_data_free(&data);
19855682Smarkm	return errno;
19955682Smarkm    }
20055682Smarkm    /*
20155682Smarkm     * Try to send a signal to any running `ipropd-master'
20255682Smarkm     */
20355682Smarkm    sendto (log_context->socket_fd,
20455682Smarkm	    (void *)&log_context->version,
20555682Smarkm	    sizeof(log_context->version),
20655682Smarkm	    0,
20755682Smarkm	    (struct sockaddr *)&log_context->socket_name,
20855682Smarkm	    sizeof(log_context->socket_name));
20955682Smarkm
21055682Smarkm    krb5_data_free(&data);
21155682Smarkm    return 0;
21255682Smarkm}
21355682Smarkm
21455682Smarkm/*
21555682Smarkm * Add a `create' operation to the log.
21655682Smarkm */
21755682Smarkm
21855682Smarkmkadm5_ret_t
21955682Smarkmkadm5_log_create (kadm5_server_context *context,
22055682Smarkm		  hdb_entry *ent)
22155682Smarkm{
22255682Smarkm    krb5_storage *sp;
22355682Smarkm    kadm5_ret_t ret;
22455682Smarkm    krb5_data value;
22555682Smarkm    kadm5_log_context *log_context = &context->log_context;
22655682Smarkm
22755682Smarkm    sp = krb5_storage_emem();
22855682Smarkm    ret = hdb_entry2value (context->context, ent, &value);
22955682Smarkm    if (ret) {
23055682Smarkm	krb5_storage_free(sp);
23155682Smarkm	return ret;
23255682Smarkm    }
23355682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_create);
23455682Smarkm    if (ret) {
23555682Smarkm	krb5_data_free (&value);
23655682Smarkm	krb5_storage_free(sp);
23755682Smarkm	return ret;
23855682Smarkm    }
23955682Smarkm    krb5_store_int32 (sp, value.length);
24055682Smarkm    sp->store(sp, value.data, value.length);
24155682Smarkm    krb5_store_int32 (sp, value.length);
24255682Smarkm    krb5_data_free (&value);
24355682Smarkm    ret = kadm5_log_postamble (log_context, sp);
24455682Smarkm    if (ret) {
24555682Smarkm	krb5_storage_free (sp);
24655682Smarkm	return ret;
24755682Smarkm    }
24855682Smarkm    ret = kadm5_log_flush (log_context, sp);
24955682Smarkm    krb5_storage_free (sp);
25055682Smarkm    if (ret)
25155682Smarkm	return ret;
25255682Smarkm    ret = kadm5_log_end (context);
25355682Smarkm    return ret;
25455682Smarkm}
25555682Smarkm
25655682Smarkm/*
25755682Smarkm * Read the data of a create log record from `sp' and change the
25855682Smarkm * database.
25955682Smarkm */
26055682Smarkm
26155682Smarkmkadm5_ret_t
26255682Smarkmkadm5_log_replay_create (kadm5_server_context *context,
26355682Smarkm			 u_int32_t ver,
26455682Smarkm			 u_int32_t len,
26555682Smarkm			 krb5_storage *sp)
26655682Smarkm{
26755682Smarkm    krb5_error_code ret;
26855682Smarkm    krb5_data data;
26955682Smarkm    hdb_entry ent;
27055682Smarkm
27155682Smarkm    krb5_data_alloc (&data, len);
27255682Smarkm    sp->fetch (sp, data.data, len);
27355682Smarkm    ret = hdb_value2entry (context->context, &data, &ent);
27455682Smarkm    krb5_data_free(&data);
27555682Smarkm    if (ret)
27655682Smarkm	return ret;
27755682Smarkm    ret = context->db->store(context->context, context->db, 0, &ent);
27855682Smarkm    hdb_free_entry (context->context, &ent);
27955682Smarkm    return ret;
28055682Smarkm}
28155682Smarkm
28255682Smarkm/*
28355682Smarkm * Add a `delete' operation to the log.
28455682Smarkm */
28555682Smarkm
28655682Smarkmkadm5_ret_t
28755682Smarkmkadm5_log_delete (kadm5_server_context *context,
28855682Smarkm		  krb5_principal princ)
28955682Smarkm{
29055682Smarkm    krb5_storage *sp;
29155682Smarkm    kadm5_ret_t ret;
29255682Smarkm    off_t off;
29355682Smarkm    off_t len;
29455682Smarkm    kadm5_log_context *log_context = &context->log_context;
29555682Smarkm
29655682Smarkm    sp = krb5_storage_emem();
29755682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_delete);
29855682Smarkm    if (ret) {
29955682Smarkm	krb5_storage_free(sp);
30055682Smarkm	return ret;
30155682Smarkm    }
30255682Smarkm    krb5_store_int32 (sp, 0);
30355682Smarkm    off = sp->seek (sp, 0, SEEK_CUR);
30455682Smarkm    krb5_store_principal (sp, princ);
30555682Smarkm    len = sp->seek (sp, 0, SEEK_CUR) - off;
30655682Smarkm    sp->seek(sp, -(len + 4), SEEK_CUR);
30755682Smarkm    krb5_store_int32 (sp, len);
30855682Smarkm    sp->seek(sp, len, SEEK_CUR);
30955682Smarkm    krb5_store_int32 (sp, len);
31055682Smarkm    if (ret) {
31155682Smarkm	krb5_storage_free (sp);
31255682Smarkm	return ret;
31355682Smarkm    }
31455682Smarkm    ret = kadm5_log_postamble (log_context, sp);
31555682Smarkm    if (ret) {
31655682Smarkm	krb5_storage_free (sp);
31755682Smarkm	return ret;
31855682Smarkm    }
31955682Smarkm    ret = kadm5_log_flush (log_context, sp);
32055682Smarkm    krb5_storage_free (sp);
32155682Smarkm    if (ret)
32255682Smarkm	return ret;
32355682Smarkm    ret = kadm5_log_end (context);
32455682Smarkm    return ret;
32555682Smarkm}
32655682Smarkm
32755682Smarkm/*
32855682Smarkm * Read a `delete' log operation from `sp' and apply it.
32955682Smarkm */
33055682Smarkm
33155682Smarkmkadm5_ret_t
33255682Smarkmkadm5_log_replay_delete (kadm5_server_context *context,
33355682Smarkm			 u_int32_t ver,
33455682Smarkm			 u_int32_t len,
33555682Smarkm			 krb5_storage *sp)
33655682Smarkm{
33755682Smarkm    krb5_error_code ret;
33855682Smarkm    hdb_entry ent;
33955682Smarkm
34055682Smarkm    krb5_ret_principal (sp, &ent.principal);
34155682Smarkm
34255682Smarkm    ret = context->db->remove(context->context, context->db, &ent);
34355682Smarkm    krb5_free_principal (context->context, ent.principal);
34455682Smarkm    return ret;
34555682Smarkm}
34655682Smarkm
34755682Smarkm/*
34855682Smarkm * Add a `rename' operation to the log.
34955682Smarkm */
35055682Smarkm
35155682Smarkmkadm5_ret_t
35255682Smarkmkadm5_log_rename (kadm5_server_context *context,
35355682Smarkm		  krb5_principal source,
35455682Smarkm		  hdb_entry *ent)
35555682Smarkm{
35655682Smarkm    krb5_storage *sp;
35755682Smarkm    kadm5_ret_t ret;
35855682Smarkm    off_t off;
35955682Smarkm    off_t len;
36055682Smarkm    krb5_data value;
36155682Smarkm    kadm5_log_context *log_context = &context->log_context;
36255682Smarkm
36355682Smarkm    sp = krb5_storage_emem();
36455682Smarkm    ret = hdb_entry2value (context->context, ent, &value);
36555682Smarkm    if (ret) {
36655682Smarkm	krb5_storage_free(sp);
36755682Smarkm	return ret;
36855682Smarkm    }
36955682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_rename);
37055682Smarkm    if (ret) {
37155682Smarkm	krb5_storage_free(sp);
37255682Smarkm	krb5_data_free (&value);
37355682Smarkm	return ret;
37455682Smarkm    }
37555682Smarkm    krb5_store_int32 (sp, 0);
37655682Smarkm    off = sp->seek (sp, 0, SEEK_CUR);
37755682Smarkm    krb5_store_principal (sp, source);
37855682Smarkm    sp->store(sp, value.data, value.length);
37955682Smarkm    krb5_data_free (&value);
38055682Smarkm    len = sp->seek (sp, 0, SEEK_CUR) - off;
38155682Smarkm
38255682Smarkm    sp->seek(sp, -(len + 4), SEEK_CUR);
38355682Smarkm    krb5_store_int32 (sp, len);
38455682Smarkm    sp->seek(sp, len, SEEK_CUR);
38555682Smarkm    krb5_store_int32 (sp, len);
38655682Smarkm    if (ret) {
38755682Smarkm	krb5_storage_free (sp);
38855682Smarkm	return ret;
38955682Smarkm    }
39055682Smarkm    ret = kadm5_log_postamble (log_context, sp);
39155682Smarkm    if (ret) {
39255682Smarkm	krb5_storage_free (sp);
39355682Smarkm	return ret;
39455682Smarkm    }
39555682Smarkm    ret = kadm5_log_flush (log_context, sp);
39655682Smarkm    krb5_storage_free (sp);
39755682Smarkm    if (ret)
39855682Smarkm	return ret;
39955682Smarkm    ret = kadm5_log_end (context);
40055682Smarkm    return ret;
40155682Smarkm}
40255682Smarkm
40355682Smarkm/*
40455682Smarkm * Read a `rename' log operation from `sp' and apply it.
40555682Smarkm */
40655682Smarkm
40755682Smarkmkadm5_ret_t
40855682Smarkmkadm5_log_replay_rename (kadm5_server_context *context,
40955682Smarkm			 u_int32_t ver,
41055682Smarkm			 u_int32_t len,
41155682Smarkm			 krb5_storage *sp)
41255682Smarkm{
41355682Smarkm    krb5_error_code ret;
41455682Smarkm    krb5_principal source;
41555682Smarkm    hdb_entry source_ent, target_ent;
41655682Smarkm    krb5_data value;
41755682Smarkm    off_t off;
41855682Smarkm    size_t princ_len, data_len;
41955682Smarkm
42055682Smarkm    off = sp->seek(sp, 0, SEEK_CUR);
42155682Smarkm    krb5_ret_principal (sp, &source);
42255682Smarkm    princ_len = sp->seek(sp, 0, SEEK_CUR) - off;
42355682Smarkm    data_len = len - princ_len;
42455682Smarkm    krb5_data_alloc (&value, data_len);
42555682Smarkm    sp->fetch (sp, value.data, data_len);
42655682Smarkm    ret = hdb_value2entry (context->context, &value, &target_ent);
42755682Smarkm    krb5_data_free(&value);
42855682Smarkm    if (ret) {
42955682Smarkm	krb5_free_principal (context->context, source);
43055682Smarkm	return ret;
43155682Smarkm    }
43255682Smarkm    ret = context->db->store (context->context, context->db, 0, &target_ent);
43355682Smarkm    hdb_free_entry (context->context, &target_ent);
43455682Smarkm    if (ret) {
43555682Smarkm	krb5_free_principal (context->context, source);
43655682Smarkm	return ret;
43755682Smarkm    }
43855682Smarkm    source_ent.principal = source;
43955682Smarkm    ret = context->db->remove (context->context, context->db, &source_ent);
44055682Smarkm    krb5_free_principal (context->context, source);
44155682Smarkm    return ret;
44255682Smarkm}
44355682Smarkm
44455682Smarkm
44555682Smarkm/*
44655682Smarkm * Add a `modify' operation to the log.
44755682Smarkm */
44855682Smarkm
44955682Smarkmkadm5_ret_t
45055682Smarkmkadm5_log_modify (kadm5_server_context *context,
45155682Smarkm		  hdb_entry *ent,
45255682Smarkm		  u_int32_t mask)
45355682Smarkm{
45455682Smarkm    krb5_storage *sp;
45555682Smarkm    kadm5_ret_t ret;
45655682Smarkm    krb5_data value;
45755682Smarkm    u_int32_t len;
45855682Smarkm    kadm5_log_context *log_context = &context->log_context;
45955682Smarkm
46055682Smarkm    sp = krb5_storage_emem();
46155682Smarkm    ret = hdb_entry2value (context->context, ent, &value);
46255682Smarkm    if (ret) {
46355682Smarkm	krb5_storage_free(sp);
46455682Smarkm	return ret;
46555682Smarkm    }
46655682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_modify);
46755682Smarkm    if (ret) {
46855682Smarkm	krb5_data_free (&value);
46955682Smarkm	krb5_storage_free(sp);
47055682Smarkm	return ret;
47155682Smarkm    }
47255682Smarkm    len = value.length + 4;
47355682Smarkm    krb5_store_int32 (sp, len);
47455682Smarkm    krb5_store_int32 (sp, mask);
47555682Smarkm    sp->store(sp, value.data, value.length);
47655682Smarkm    krb5_data_free (&value);
47755682Smarkm    krb5_store_int32 (sp, len);
47855682Smarkm    if (ret) {
47955682Smarkm	krb5_storage_free (sp);
48055682Smarkm	return ret;
48155682Smarkm    }
48255682Smarkm    ret = kadm5_log_postamble (log_context, sp);
48355682Smarkm    if (ret) {
48455682Smarkm	krb5_storage_free (sp);
48555682Smarkm	return ret;
48655682Smarkm    }
48755682Smarkm    ret = kadm5_log_flush (log_context, sp);
48855682Smarkm    krb5_storage_free (sp);
48955682Smarkm    if (ret)
49055682Smarkm	return ret;
49155682Smarkm    ret = kadm5_log_end (context);
49255682Smarkm    return ret;
49355682Smarkm}
49455682Smarkm
49555682Smarkm/*
49655682Smarkm * Read a `modify' log operation from `sp' and apply it.
49755682Smarkm */
49855682Smarkm
49955682Smarkmkadm5_ret_t
50055682Smarkmkadm5_log_replay_modify (kadm5_server_context *context,
50155682Smarkm			 u_int32_t ver,
50255682Smarkm			 u_int32_t len,
50355682Smarkm			 krb5_storage *sp)
50455682Smarkm{
50555682Smarkm    krb5_error_code ret;
50655682Smarkm    int32_t mask;
50755682Smarkm    krb5_data value;
50855682Smarkm    hdb_entry ent, log_ent;
50955682Smarkm
51055682Smarkm    krb5_ret_int32 (sp, &mask);
51155682Smarkm    len -= 4;
51255682Smarkm    krb5_data_alloc (&value, len);
51355682Smarkm    sp->fetch (sp, value.data, len);
51455682Smarkm    ret = hdb_value2entry (context->context, &value, &log_ent);
51555682Smarkm    krb5_data_free(&value);
51655682Smarkm    if (ret)
51755682Smarkm	return ret;
51855682Smarkm    ent.principal = log_ent.principal;
51955682Smarkm    log_ent.principal = NULL;
52055682Smarkm    ret = context->db->fetch(context->context, context->db,
52155682Smarkm			     HDB_F_DECRYPT, &ent);
52255682Smarkm    if (ret)
52355682Smarkm	return ret;
52455682Smarkm    if (mask & KADM5_PRINC_EXPIRE_TIME) {
52572445Sassar	if (log_ent.valid_end == NULL) {
52672445Sassar	    ent.valid_end = NULL;
52772445Sassar	} else {
52872445Sassar	    if (ent.valid_end == NULL)
52972445Sassar		ent.valid_end = malloc(sizeof(*ent.valid_end));
53072445Sassar	    *ent.valid_end = *log_ent.valid_end;
53172445Sassar	}
53255682Smarkm    }
53355682Smarkm    if (mask & KADM5_PW_EXPIRATION) {
53472445Sassar	if (log_ent.pw_end == NULL) {
53572445Sassar	    ent.pw_end = NULL;
53672445Sassar	} else {
53772445Sassar	    if (ent.pw_end == NULL)
53872445Sassar		ent.pw_end = malloc(sizeof(*ent.pw_end));
53972445Sassar	    *ent.pw_end = *log_ent.pw_end;
54072445Sassar	}
54155682Smarkm    }
54255682Smarkm    if (mask & KADM5_LAST_PWD_CHANGE) {
54355682Smarkm	abort ();		/* XXX */
54455682Smarkm    }
54555682Smarkm    if (mask & KADM5_ATTRIBUTES) {
54655682Smarkm	ent.flags = log_ent.flags;
54755682Smarkm    }
54855682Smarkm    if (mask & KADM5_MAX_LIFE) {
54972445Sassar	if (log_ent.max_life == NULL) {
55072445Sassar	    ent.max_life = NULL;
55172445Sassar	} else {
55272445Sassar	    if (ent.max_life == NULL)
55372445Sassar		ent.max_life = malloc (sizeof(*ent.max_life));
55472445Sassar	    *ent.max_life = *log_ent.max_life;
55572445Sassar	}
55655682Smarkm    }
55755682Smarkm    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
55855682Smarkm	if (ent.modified_by == NULL) {
55955682Smarkm	    ent.modified_by = malloc(sizeof(*ent.modified_by));
56055682Smarkm	} else
56155682Smarkm	    free_Event(ent.modified_by);
56255682Smarkm	copy_Event(log_ent.modified_by, ent.modified_by);
56355682Smarkm    }
56455682Smarkm    if (mask & KADM5_KVNO) {
56555682Smarkm	ent.kvno = log_ent.kvno;
56655682Smarkm    }
56755682Smarkm    if (mask & KADM5_MKVNO) {
56855682Smarkm	abort ();		/* XXX */
56955682Smarkm    }
57055682Smarkm    if (mask & KADM5_AUX_ATTRIBUTES) {
57155682Smarkm	abort ();		/* XXX */
57255682Smarkm    }
57355682Smarkm    if (mask & KADM5_POLICY) {
57455682Smarkm	abort ();		/* XXX */
57555682Smarkm    }
57655682Smarkm    if (mask & KADM5_POLICY_CLR) {
57755682Smarkm	abort ();		/* XXX */
57855682Smarkm    }
57955682Smarkm    if (mask & KADM5_MAX_RLIFE) {
58072445Sassar	if (log_ent.max_renew == NULL) {
58172445Sassar	    ent.max_renew = NULL;
58272445Sassar	} else {
58372445Sassar	    if (ent.max_renew == NULL)
58472445Sassar		ent.max_renew = malloc (sizeof(*ent.max_renew));
58572445Sassar	    *ent.max_renew = *log_ent.max_renew;
58672445Sassar	}
58755682Smarkm    }
58855682Smarkm    if (mask & KADM5_LAST_SUCCESS) {
58955682Smarkm	abort ();		/* XXX */
59055682Smarkm    }
59155682Smarkm    if (mask & KADM5_LAST_FAILED) {
59255682Smarkm	abort ();		/* XXX */
59355682Smarkm    }
59455682Smarkm    if (mask & KADM5_FAIL_AUTH_COUNT) {
59555682Smarkm	abort ();		/* XXX */
59655682Smarkm    }
59755682Smarkm    if (mask & KADM5_KEY_DATA) {
59855682Smarkm	size_t len;
59955682Smarkm	int i;
60055682Smarkm
60155682Smarkm	for (i = 0; i < ent.keys.len; ++i)
60255682Smarkm	    free_Key(&ent.keys.val[i]);
60355682Smarkm	free (ent.keys.val);
60455682Smarkm
60555682Smarkm	len = log_ent.keys.len;
60655682Smarkm
60755682Smarkm	ent.keys.len = len;
60855682Smarkm	ent.keys.val = malloc(len * sizeof(*ent.keys.val));
60955682Smarkm	for (i = 0; i < ent.keys.len; ++i)
61055682Smarkm	    copy_Key(&log_ent.keys.val[i],
61155682Smarkm		     &ent.keys.val[i]);
61255682Smarkm    }
61355682Smarkm    ret = context->db->store(context->context, context->db,
61455682Smarkm			     HDB_F_REPLACE, &ent);
61555682Smarkm    hdb_free_entry (context->context, &ent);
61655682Smarkm    hdb_free_entry (context->context, &log_ent);
61755682Smarkm    return ret;
61855682Smarkm}
61955682Smarkm
62055682Smarkm/*
62172445Sassar * Add a `nop' operation to the log.
62272445Sassar */
62372445Sassar
62472445Sassarkadm5_ret_t
62572445Sassarkadm5_log_nop (kadm5_server_context *context)
62672445Sassar{
62772445Sassar    krb5_storage *sp;
62872445Sassar    kadm5_ret_t ret;
62972445Sassar    kadm5_log_context *log_context = &context->log_context;
63072445Sassar
63172445Sassar    sp = krb5_storage_emem();
63272445Sassar    ret = kadm5_log_preamble (context, sp, kadm_nop);
63372445Sassar    if (ret) {
63472445Sassar	krb5_storage_free (sp);
63572445Sassar	return ret;
63672445Sassar    }
63772445Sassar    krb5_store_int32 (sp, 0);
63872445Sassar    krb5_store_int32 (sp, 0);
63972445Sassar    ret = kadm5_log_postamble (log_context, sp);
64072445Sassar    if (ret) {
64172445Sassar	krb5_storage_free (sp);
64272445Sassar	return ret;
64372445Sassar    }
64472445Sassar    ret = kadm5_log_flush (log_context, sp);
64572445Sassar    krb5_storage_free (sp);
64672445Sassar    if (ret)
64772445Sassar	return ret;
64872445Sassar    ret = kadm5_log_end (context);
64972445Sassar    return ret;
65072445Sassar}
65172445Sassar
65272445Sassar/*
65372445Sassar * Read a `nop' log operation from `sp' and apply it.
65472445Sassar */
65572445Sassar
65672445Sassarkadm5_ret_t
65772445Sassarkadm5_log_replay_nop (kadm5_server_context *context,
65872445Sassar		      u_int32_t ver,
65972445Sassar		      u_int32_t len,
66072445Sassar		      krb5_storage *sp)
66172445Sassar{
66272445Sassar    return 0;
66372445Sassar}
66472445Sassar
66572445Sassar/*
66655682Smarkm * Call `func' for each log record in the log in `context'
66755682Smarkm */
66855682Smarkm
66955682Smarkmkadm5_ret_t
67055682Smarkmkadm5_log_foreach (kadm5_server_context *context,
67155682Smarkm		   void (*func)(kadm5_server_context *server_context,
67255682Smarkm				u_int32_t ver,
67355682Smarkm				time_t timestamp,
67455682Smarkm				enum kadm_ops op,
67555682Smarkm				u_int32_t len,
67655682Smarkm				krb5_storage *sp))
67755682Smarkm{
67855682Smarkm    int fd = context->log_context.log_fd;
67955682Smarkm    krb5_storage *sp;
68055682Smarkm
68155682Smarkm    lseek (fd, 0, SEEK_SET);
68255682Smarkm    sp = krb5_storage_from_fd (fd);
68355682Smarkm    for (;;) {
68455682Smarkm	int32_t ver, timestamp, op, len;
68555682Smarkm
68655682Smarkm	if(krb5_ret_int32 (sp, &ver) != 0)
68755682Smarkm	    break;
68855682Smarkm	krb5_ret_int32 (sp, &timestamp);
68955682Smarkm	krb5_ret_int32 (sp, &op);
69055682Smarkm	krb5_ret_int32 (sp, &len);
69155682Smarkm	(*func)(context, ver, timestamp, op, len, sp);
69255682Smarkm	sp->seek(sp, 8, SEEK_CUR);
69355682Smarkm    }
69455682Smarkm    return 0;
69555682Smarkm}
69655682Smarkm
69755682Smarkm/*
69855682Smarkm * Go to end of log.
69955682Smarkm */
70055682Smarkm
70155682Smarkmkrb5_storage *
70255682Smarkmkadm5_log_goto_end (int fd)
70355682Smarkm{
70455682Smarkm    krb5_storage *sp;
70555682Smarkm
70655682Smarkm    sp = krb5_storage_from_fd (fd);
70755682Smarkm    sp->seek(sp, 0, SEEK_END);
70855682Smarkm    return sp;
70955682Smarkm}
71055682Smarkm
71155682Smarkm/*
71255682Smarkm * Return previous log entry.
71355682Smarkm */
71455682Smarkm
71555682Smarkmkadm5_ret_t
71655682Smarkmkadm5_log_previous (krb5_storage *sp,
71755682Smarkm		    u_int32_t *ver,
71855682Smarkm		    time_t *timestamp,
71955682Smarkm		    enum kadm_ops *op,
72055682Smarkm		    u_int32_t *len)
72155682Smarkm{
72255682Smarkm    off_t off;
72355682Smarkm    int32_t tmp;
72455682Smarkm
72555682Smarkm    sp->seek(sp, -8, SEEK_CUR);
72655682Smarkm    krb5_ret_int32 (sp, &tmp);
72755682Smarkm    *len = tmp;
72855682Smarkm    krb5_ret_int32 (sp, &tmp);
72955682Smarkm    *ver = tmp;
73055682Smarkm    off = 24 + *len;
73155682Smarkm    sp->seek(sp, -off, SEEK_CUR);
73255682Smarkm    krb5_ret_int32 (sp, &tmp);
73355682Smarkm    assert(tmp == *ver);
73455682Smarkm    krb5_ret_int32 (sp, &tmp);
73555682Smarkm    *timestamp = tmp;
73655682Smarkm    krb5_ret_int32 (sp, &tmp);
73755682Smarkm    *op = tmp;
73855682Smarkm    krb5_ret_int32 (sp, &tmp);
73955682Smarkm    assert(tmp == *len);
74055682Smarkm    return 0;
74155682Smarkm}
74255682Smarkm
74355682Smarkm/*
74455682Smarkm * Replay a record from the log
74555682Smarkm */
74655682Smarkm
74755682Smarkmkadm5_ret_t
74855682Smarkmkadm5_log_replay (kadm5_server_context *context,
74955682Smarkm		  enum kadm_ops op,
75055682Smarkm		  u_int32_t ver,
75155682Smarkm		  u_int32_t len,
75255682Smarkm		  krb5_storage *sp)
75355682Smarkm{
75455682Smarkm    switch (op) {
75555682Smarkm    case kadm_create :
75655682Smarkm	return kadm5_log_replay_create (context, ver, len, sp);
75755682Smarkm    case kadm_delete :
75855682Smarkm	return kadm5_log_replay_delete (context, ver, len, sp);
75955682Smarkm    case kadm_rename :
76055682Smarkm	return kadm5_log_replay_rename (context, ver, len, sp);
76155682Smarkm    case kadm_modify :
76255682Smarkm	return kadm5_log_replay_modify (context, ver, len, sp);
76372445Sassar    case kadm_nop :
76472445Sassar	return kadm5_log_replay_nop (context, ver, len, sp);
76555682Smarkm    default :
76655682Smarkm	return KADM5_FAILURE;
76755682Smarkm    }
76855682Smarkm}
76972445Sassar
77072445Sassar/*
77172445Sassar * truncate the log - i.e. create an empty file with just (nop vno + 2)
77272445Sassar */
77372445Sassar
77472445Sassarkadm5_ret_t
77572445Sassarkadm5_log_truncate (kadm5_server_context *server_context)
77672445Sassar{
77772445Sassar    kadm5_ret_t ret;
77872445Sassar    u_int32_t vno;
77972445Sassar
78072445Sassar    ret = kadm5_log_init (server_context);
78172445Sassar    if (ret)
78272445Sassar	return ret;
78372445Sassar
78472445Sassar    ret = kadm5_log_get_version (server_context, &vno);
78572445Sassar    if (ret)
78672445Sassar	return ret;
78772445Sassar
78872445Sassar    ret = kadm5_log_reinit (server_context);
78972445Sassar    if (ret)
79072445Sassar	return ret;
79172445Sassar
79272445Sassar    ret = kadm5_log_set_version (server_context, vno + 1);
79372445Sassar    if (ret)
79472445Sassar	return ret;
79572445Sassar
79672445Sassar    ret = kadm5_log_nop (server_context);
79772445Sassar    if (ret)
79872445Sassar	return ret;
79972445Sassar
80072445Sassar    ret = kadm5_log_end (server_context);
80172445Sassar    if (ret)
80272445Sassar	return ret;
80372445Sassar    return 0;
80472445Sassar
80572445Sassar}
806