2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "kadm5_locl.h"
36 RCSID("$Id: log.c,v 1.20 2003/04/16 17:56:55 lha Exp $");
39 * A log record consists of:
41 * version number 4 bytes
42 * time in seconds 4 bytes
43 * operation (enum kadm_ops) 4 bytes
44 * length of record 4 bytes
46 * length of record 4 bytes
47 * version number 4 bytes
52 kadm5_log_get_version_fd (int fd,
59 ret = lseek (fd, 0, SEEK_END);
66 sp = krb5_storage_from_fd (fd);
67 krb5_storage_seek(sp, -4, SEEK_CUR);
68 krb5_ret_int32 (sp, &old_version);
70 krb5_storage_free(sp);
71 lseek (fd, 0, SEEK_END);
76 kadm5_log_get_version (kadm5_server_context *context, u_int32_t *ver)
78 return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
82 kadm5_log_set_version (kadm5_server_context *context, u_int32_t vno)
84 kadm5_log_context *log_context = &context->log_context;
86 log_context->version = vno;
91 kadm5_log_init (kadm5_server_context *context)
95 kadm5_log_context *log_context = &context->log_context;
97 if (log_context->log_fd != -1)
99 fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
102 if (flock (fd, LOCK_EX) < 0) {
107 ret = kadm5_log_get_version_fd (fd, &log_context->version);
111 log_context->log_fd = fd;
116 kadm5_log_reinit (kadm5_server_context *context)
119 kadm5_log_context *log_context = &context->log_context;
121 if (log_context->log_fd != -1) {
122 close (log_context->log_fd);
123 log_context->log_fd = -1;
125 fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
128 if (flock (fd, LOCK_EX) < 0) {
133 log_context->version = 0;
134 log_context->log_fd = fd;
140 kadm5_log_end (kadm5_server_context *context)
142 kadm5_log_context *log_context = &context->log_context;
143 int fd = log_context->log_fd;
147 log_context->log_fd = -1;
152 kadm5_log_preamble (kadm5_server_context *context,
156 kadm5_log_context *log_context = &context->log_context;
157 kadm5_ret_t kadm_ret;
159 kadm_ret = kadm5_log_init (context);
163 krb5_store_int32 (sp, ++log_context->version);
164 krb5_store_int32 (sp, time(NULL));
165 krb5_store_int32 (sp, op);
170 kadm5_log_postamble (kadm5_log_context *context,
173 krb5_store_int32 (sp, context->version);
178 * flush the log record in `sp'.
182 kadm5_log_flush (kadm5_log_context *log_context,
189 krb5_storage_to_data(sp, &data);
191 ret = write (log_context->log_fd, data.data, len);
193 krb5_data_free(&data);
196 if (fsync (log_context->log_fd) < 0) {
197 krb5_data_free(&data);
201 * Try to send a signal to any running `ipropd-master'
203 sendto (log_context->socket_fd,
204 (void *)&log_context->version,
205 sizeof(log_context->version),
207 (struct sockaddr *)&log_context->socket_name,
208 sizeof(log_context->socket_name));
210 krb5_data_free(&data);
215 * Add a `create' operation to the log.
219 kadm5_log_create (kadm5_server_context *context,
225 kadm5_log_context *log_context = &context->log_context;
227 sp = krb5_storage_emem();
228 ret = hdb_entry2value (context->context, ent, &value);
230 krb5_storage_free(sp);
233 ret = kadm5_log_preamble (context, sp, kadm_create);
235 krb5_data_free (&value);
236 krb5_storage_free(sp);
239 krb5_store_int32 (sp, value.length);
240 krb5_storage_write(sp, value.data, value.length);
241 krb5_store_int32 (sp, value.length);
242 krb5_data_free (&value);
243 ret = kadm5_log_postamble (log_context, sp);
245 krb5_storage_free (sp);
248 ret = kadm5_log_flush (log_context, sp);
249 krb5_storage_free (sp);
252 ret = kadm5_log_end (context);
257 * Read the data of a create log record from `sp' and change the
262 kadm5_log_replay_create (kadm5_server_context *context,
271 ret = krb5_data_alloc (&data, len);
274 krb5_storage_read (sp, data.data, len);
275 ret = hdb_value2entry (context->context, &data, &ent);
276 krb5_data_free(&data);
279 ret = context->db->store(context->context, context->db, 0, &ent);
280 hdb_free_entry (context->context, &ent);
285 * Add a `delete' operation to the log.
289 kadm5_log_delete (kadm5_server_context *context,
290 krb5_principal princ)
296 kadm5_log_context *log_context = &context->log_context;
298 sp = krb5_storage_emem();
299 ret = kadm5_log_preamble (context, sp, kadm_delete);
301 krb5_storage_free(sp);
304 krb5_store_int32 (sp, 0);
305 off = krb5_storage_seek (sp, 0, SEEK_CUR);
306 krb5_store_principal (sp, princ);
307 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
308 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
309 krb5_store_int32 (sp, len);
310 krb5_storage_seek(sp, len, SEEK_CUR);
311 krb5_store_int32 (sp, len);
313 krb5_storage_free (sp);
316 ret = kadm5_log_postamble (log_context, sp);
318 krb5_storage_free (sp);
321 ret = kadm5_log_flush (log_context, sp);
322 krb5_storage_free (sp);
325 ret = kadm5_log_end (context);
330 * Read a `delete' log operation from `sp' and apply it.
334 kadm5_log_replay_delete (kadm5_server_context *context,
342 krb5_ret_principal (sp, &ent.principal);
344 ret = context->db->remove(context->context, context->db, &ent);
345 krb5_free_principal (context->context, ent.principal);
350 * Add a `rename' operation to the log.
354 kadm5_log_rename (kadm5_server_context *context,
355 krb5_principal source,
363 kadm5_log_context *log_context = &context->log_context;
365 sp = krb5_storage_emem();
366 ret = hdb_entry2value (context->context, ent, &value);
368 krb5_storage_free(sp);
371 ret = kadm5_log_preamble (context, sp, kadm_rename);
373 krb5_storage_free(sp);
374 krb5_data_free (&value);
377 krb5_store_int32 (sp, 0);
378 off = krb5_storage_seek (sp, 0, SEEK_CUR);
379 krb5_store_principal (sp, source);
380 krb5_storage_write(sp, value.data, value.length);
381 krb5_data_free (&value);
382 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
384 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
385 krb5_store_int32 (sp, len);
386 krb5_storage_seek(sp, len, SEEK_CUR);
387 krb5_store_int32 (sp, len);
389 krb5_storage_free (sp);
392 ret = kadm5_log_postamble (log_context, sp);
394 krb5_storage_free (sp);
397 ret = kadm5_log_flush (log_context, sp);
398 krb5_storage_free (sp);
401 ret = kadm5_log_end (context);
406 * Read a `rename' log operation from `sp' and apply it.
410 kadm5_log_replay_rename (kadm5_server_context *context,
416 krb5_principal source;
417 hdb_entry source_ent, target_ent;
420 size_t princ_len, data_len;
422 off = krb5_storage_seek(sp, 0, SEEK_CUR);
423 krb5_ret_principal (sp, &source);
424 princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
425 data_len = len - princ_len;
426 ret = krb5_data_alloc (&value, data_len);
428 krb5_free_principal (context->context, source);
431 krb5_storage_read (sp, value.data, data_len);
432 ret = hdb_value2entry (context->context, &value, &target_ent);
433 krb5_data_free(&value);
435 krb5_free_principal (context->context, source);
438 ret = context->db->store (context->context, context->db, 0, &target_ent);
439 hdb_free_entry (context->context, &target_ent);
441 krb5_free_principal (context->context, source);
444 source_ent.principal = source;
445 ret = context->db->remove (context->context, context->db, &source_ent);
446 krb5_free_principal (context->context, source);
452 * Add a `modify' operation to the log.
456 kadm5_log_modify (kadm5_server_context *context,
464 kadm5_log_context *log_context = &context->log_context;
466 sp = krb5_storage_emem();
467 ret = hdb_entry2value (context->context, ent, &value);
469 krb5_storage_free(sp);
472 ret = kadm5_log_preamble (context, sp, kadm_modify);
474 krb5_data_free (&value);
475 krb5_storage_free(sp);
478 len = value.length + 4;
479 krb5_store_int32 (sp, len);
480 krb5_store_int32 (sp, mask);
481 krb5_storage_write (sp, value.data, value.length);
482 krb5_data_free (&value);
483 krb5_store_int32 (sp, len);
485 krb5_storage_free (sp);
488 ret = kadm5_log_postamble (log_context, sp);
490 krb5_storage_free (sp);
493 ret = kadm5_log_flush (log_context, sp);
494 krb5_storage_free (sp);
497 ret = kadm5_log_end (context);
502 * Read a `modify' log operation from `sp' and apply it.
506 kadm5_log_replay_modify (kadm5_server_context *context,
514 hdb_entry ent, log_ent;
516 krb5_ret_int32 (sp, &mask);
518 ret = krb5_data_alloc (&value, len);
521 krb5_storage_read (sp, value.data, len);
522 ret = hdb_value2entry (context->context, &value, &log_ent);
523 krb5_data_free(&value);
526 ent.principal = log_ent.principal;
527 log_ent.principal = NULL;
528 ret = context->db->fetch(context->context, context->db,
529 HDB_F_DECRYPT, &ent);
532 if (mask & KADM5_PRINC_EXPIRE_TIME) {
533 if (log_ent.valid_end == NULL) {
534 ent.valid_end = NULL;
536 if (ent.valid_end == NULL)
537 ent.valid_end = malloc(sizeof(*ent.valid_end));
538 *ent.valid_end = *log_ent.valid_end;
541 if (mask & KADM5_PW_EXPIRATION) {
542 if (log_ent.pw_end == NULL) {
545 if (ent.pw_end == NULL)
546 ent.pw_end = malloc(sizeof(*ent.pw_end));
547 *ent.pw_end = *log_ent.pw_end;
550 if (mask & KADM5_LAST_PWD_CHANGE) {
553 if (mask & KADM5_ATTRIBUTES) {
554 ent.flags = log_ent.flags;
556 if (mask & KADM5_MAX_LIFE) {
557 if (log_ent.max_life == NULL) {
560 if (ent.max_life == NULL)
561 ent.max_life = malloc (sizeof(*ent.max_life));
562 *ent.max_life = *log_ent.max_life;
565 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
566 if (ent.modified_by == NULL) {
567 ent.modified_by = malloc(sizeof(*ent.modified_by));
569 free_Event(ent.modified_by);
570 copy_Event(log_ent.modified_by, ent.modified_by);
572 if (mask & KADM5_KVNO) {
573 ent.kvno = log_ent.kvno;
575 if (mask & KADM5_MKVNO) {
578 if (mask & KADM5_AUX_ATTRIBUTES) {
581 if (mask & KADM5_POLICY) {
584 if (mask & KADM5_POLICY_CLR) {
587 if (mask & KADM5_MAX_RLIFE) {
588 if (log_ent.max_renew == NULL) {
589 ent.max_renew = NULL;
591 if (ent.max_renew == NULL)
592 ent.max_renew = malloc (sizeof(*ent.max_renew));
593 *ent.max_renew = *log_ent.max_renew;
596 if (mask & KADM5_LAST_SUCCESS) {
599 if (mask & KADM5_LAST_FAILED) {
602 if (mask & KADM5_FAIL_AUTH_COUNT) {
605 if (mask & KADM5_KEY_DATA) {
609 for (i = 0; i < ent.keys.len; ++i)
610 free_Key(&ent.keys.val[i]);
613 len = log_ent.keys.len;
616 ent.keys.val = malloc(len * sizeof(*ent.keys.val));
617 for (i = 0; i < ent.keys.len; ++i)
618 copy_Key(&log_ent.keys.val[i],
621 ret = context->db->store(context->context, context->db,
622 HDB_F_REPLACE, &ent);
623 hdb_free_entry (context->context, &ent);
624 hdb_free_entry (context->context, &log_ent);
629 * Add a `nop' operation to the log.
633 kadm5_log_nop (kadm5_server_context *context)
637 kadm5_log_context *log_context = &context->log_context;
639 sp = krb5_storage_emem();
640 ret = kadm5_log_preamble (context, sp, kadm_nop);
642 krb5_storage_free (sp);
645 krb5_store_int32 (sp, 0);
646 krb5_store_int32 (sp, 0);
647 ret = kadm5_log_postamble (log_context, sp);
649 krb5_storage_free (sp);
652 ret = kadm5_log_flush (log_context, sp);
653 krb5_storage_free (sp);
656 ret = kadm5_log_end (context);
661 * Read a `nop' log operation from `sp' and apply it.
665 kadm5_log_replay_nop (kadm5_server_context *context,
674 * Call `func' for each log record in the log in `context'
678 kadm5_log_foreach (kadm5_server_context *context,
679 void (*func)(kadm5_server_context *server_context,
686 int fd = context->log_context.log_fd;
689 lseek (fd, 0, SEEK_SET);
690 sp = krb5_storage_from_fd (fd);
692 int32_t ver, timestamp, op, len;
694 if(krb5_ret_int32 (sp, &ver) != 0)
696 krb5_ret_int32 (sp, ×tamp);
697 krb5_ret_int32 (sp, &op);
698 krb5_ret_int32 (sp, &len);
699 (*func)(context, ver, timestamp, op, len, sp);
700 krb5_storage_seek(sp, 8, SEEK_CUR);
710 kadm5_log_goto_end (int fd)
714 sp = krb5_storage_from_fd (fd);
715 krb5_storage_seek(sp, 0, SEEK_END);
720 * Return previous log entry.
724 kadm5_log_previous (krb5_storage *sp,
733 krb5_storage_seek(sp, -8, SEEK_CUR);
734 krb5_ret_int32 (sp, &tmp);
736 krb5_ret_int32 (sp, &tmp);
739 krb5_storage_seek(sp, -off, SEEK_CUR);
740 krb5_ret_int32 (sp, &tmp);
742 krb5_ret_int32 (sp, &tmp);
744 krb5_ret_int32 (sp, &tmp);
746 krb5_ret_int32 (sp, &tmp);
752 * Replay a record from the log
756 kadm5_log_replay (kadm5_server_context *context,
764 return kadm5_log_replay_create (context, ver, len, sp);
766 return kadm5_log_replay_delete (context, ver, len, sp);
768 return kadm5_log_replay_rename (context, ver, len, sp);
770 return kadm5_log_replay_modify (context, ver, len, sp);
772 return kadm5_log_replay_nop (context, ver, len, sp);
774 return KADM5_FAILURE;
779 * truncate the log - i.e. create an empty file with just (nop vno + 2)
783 kadm5_log_truncate (kadm5_server_context *server_context)
788 ret = kadm5_log_init (server_context);
792 ret = kadm5_log_get_version (server_context, &vno);
796 ret = kadm5_log_reinit (server_context);
800 ret = kadm5_log_set_version (server_context, vno + 1);
804 ret = kadm5_log_nop (server_context);
808 ret = kadm5_log_end (server_context);