2 * Copyright (c) 1997 - 2002 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.19 2002/05/24 15:19:21 joda 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 krb5_data_alloc (&data, len);
272 krb5_storage_read (sp, data.data, len);
273 ret = hdb_value2entry (context->context, &data, &ent);
274 krb5_data_free(&data);
277 ret = context->db->store(context->context, context->db, 0, &ent);
278 hdb_free_entry (context->context, &ent);
283 * Add a `delete' operation to the log.
287 kadm5_log_delete (kadm5_server_context *context,
288 krb5_principal princ)
294 kadm5_log_context *log_context = &context->log_context;
296 sp = krb5_storage_emem();
297 ret = kadm5_log_preamble (context, sp, kadm_delete);
299 krb5_storage_free(sp);
302 krb5_store_int32 (sp, 0);
303 off = krb5_storage_seek (sp, 0, SEEK_CUR);
304 krb5_store_principal (sp, princ);
305 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
306 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
307 krb5_store_int32 (sp, len);
308 krb5_storage_seek(sp, len, SEEK_CUR);
309 krb5_store_int32 (sp, len);
311 krb5_storage_free (sp);
314 ret = kadm5_log_postamble (log_context, sp);
316 krb5_storage_free (sp);
319 ret = kadm5_log_flush (log_context, sp);
320 krb5_storage_free (sp);
323 ret = kadm5_log_end (context);
328 * Read a `delete' log operation from `sp' and apply it.
332 kadm5_log_replay_delete (kadm5_server_context *context,
340 krb5_ret_principal (sp, &ent.principal);
342 ret = context->db->remove(context->context, context->db, &ent);
343 krb5_free_principal (context->context, ent.principal);
348 * Add a `rename' operation to the log.
352 kadm5_log_rename (kadm5_server_context *context,
353 krb5_principal source,
361 kadm5_log_context *log_context = &context->log_context;
363 sp = krb5_storage_emem();
364 ret = hdb_entry2value (context->context, ent, &value);
366 krb5_storage_free(sp);
369 ret = kadm5_log_preamble (context, sp, kadm_rename);
371 krb5_storage_free(sp);
372 krb5_data_free (&value);
375 krb5_store_int32 (sp, 0);
376 off = krb5_storage_seek (sp, 0, SEEK_CUR);
377 krb5_store_principal (sp, source);
378 krb5_storage_write(sp, value.data, value.length);
379 krb5_data_free (&value);
380 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
382 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
383 krb5_store_int32 (sp, len);
384 krb5_storage_seek(sp, len, SEEK_CUR);
385 krb5_store_int32 (sp, len);
387 krb5_storage_free (sp);
390 ret = kadm5_log_postamble (log_context, sp);
392 krb5_storage_free (sp);
395 ret = kadm5_log_flush (log_context, sp);
396 krb5_storage_free (sp);
399 ret = kadm5_log_end (context);
404 * Read a `rename' log operation from `sp' and apply it.
408 kadm5_log_replay_rename (kadm5_server_context *context,
414 krb5_principal source;
415 hdb_entry source_ent, target_ent;
418 size_t princ_len, data_len;
420 off = krb5_storage_seek(sp, 0, SEEK_CUR);
421 krb5_ret_principal (sp, &source);
422 princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
423 data_len = len - princ_len;
424 krb5_data_alloc (&value, data_len);
425 krb5_storage_read (sp, value.data, data_len);
426 ret = hdb_value2entry (context->context, &value, &target_ent);
427 krb5_data_free(&value);
429 krb5_free_principal (context->context, source);
432 ret = context->db->store (context->context, context->db, 0, &target_ent);
433 hdb_free_entry (context->context, &target_ent);
435 krb5_free_principal (context->context, source);
438 source_ent.principal = source;
439 ret = context->db->remove (context->context, context->db, &source_ent);
440 krb5_free_principal (context->context, source);
446 * Add a `modify' operation to the log.
450 kadm5_log_modify (kadm5_server_context *context,
458 kadm5_log_context *log_context = &context->log_context;
460 sp = krb5_storage_emem();
461 ret = hdb_entry2value (context->context, ent, &value);
463 krb5_storage_free(sp);
466 ret = kadm5_log_preamble (context, sp, kadm_modify);
468 krb5_data_free (&value);
469 krb5_storage_free(sp);
472 len = value.length + 4;
473 krb5_store_int32 (sp, len);
474 krb5_store_int32 (sp, mask);
475 krb5_storage_write (sp, value.data, value.length);
476 krb5_data_free (&value);
477 krb5_store_int32 (sp, len);
479 krb5_storage_free (sp);
482 ret = kadm5_log_postamble (log_context, sp);
484 krb5_storage_free (sp);
487 ret = kadm5_log_flush (log_context, sp);
488 krb5_storage_free (sp);
491 ret = kadm5_log_end (context);
496 * Read a `modify' log operation from `sp' and apply it.
500 kadm5_log_replay_modify (kadm5_server_context *context,
508 hdb_entry ent, log_ent;
510 krb5_ret_int32 (sp, &mask);
512 krb5_data_alloc (&value, len);
513 krb5_storage_read (sp, value.data, len);
514 ret = hdb_value2entry (context->context, &value, &log_ent);
515 krb5_data_free(&value);
518 ent.principal = log_ent.principal;
519 log_ent.principal = NULL;
520 ret = context->db->fetch(context->context, context->db,
521 HDB_F_DECRYPT, &ent);
524 if (mask & KADM5_PRINC_EXPIRE_TIME) {
525 if (log_ent.valid_end == NULL) {
526 ent.valid_end = NULL;
528 if (ent.valid_end == NULL)
529 ent.valid_end = malloc(sizeof(*ent.valid_end));
530 *ent.valid_end = *log_ent.valid_end;
533 if (mask & KADM5_PW_EXPIRATION) {
534 if (log_ent.pw_end == NULL) {
537 if (ent.pw_end == NULL)
538 ent.pw_end = malloc(sizeof(*ent.pw_end));
539 *ent.pw_end = *log_ent.pw_end;
542 if (mask & KADM5_LAST_PWD_CHANGE) {
545 if (mask & KADM5_ATTRIBUTES) {
546 ent.flags = log_ent.flags;
548 if (mask & KADM5_MAX_LIFE) {
549 if (log_ent.max_life == NULL) {
552 if (ent.max_life == NULL)
553 ent.max_life = malloc (sizeof(*ent.max_life));
554 *ent.max_life = *log_ent.max_life;
557 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
558 if (ent.modified_by == NULL) {
559 ent.modified_by = malloc(sizeof(*ent.modified_by));
561 free_Event(ent.modified_by);
562 copy_Event(log_ent.modified_by, ent.modified_by);
564 if (mask & KADM5_KVNO) {
565 ent.kvno = log_ent.kvno;
567 if (mask & KADM5_MKVNO) {
570 if (mask & KADM5_AUX_ATTRIBUTES) {
573 if (mask & KADM5_POLICY) {
576 if (mask & KADM5_POLICY_CLR) {
579 if (mask & KADM5_MAX_RLIFE) {
580 if (log_ent.max_renew == NULL) {
581 ent.max_renew = NULL;
583 if (ent.max_renew == NULL)
584 ent.max_renew = malloc (sizeof(*ent.max_renew));
585 *ent.max_renew = *log_ent.max_renew;
588 if (mask & KADM5_LAST_SUCCESS) {
591 if (mask & KADM5_LAST_FAILED) {
594 if (mask & KADM5_FAIL_AUTH_COUNT) {
597 if (mask & KADM5_KEY_DATA) {
601 for (i = 0; i < ent.keys.len; ++i)
602 free_Key(&ent.keys.val[i]);
605 len = log_ent.keys.len;
608 ent.keys.val = malloc(len * sizeof(*ent.keys.val));
609 for (i = 0; i < ent.keys.len; ++i)
610 copy_Key(&log_ent.keys.val[i],
613 ret = context->db->store(context->context, context->db,
614 HDB_F_REPLACE, &ent);
615 hdb_free_entry (context->context, &ent);
616 hdb_free_entry (context->context, &log_ent);
621 * Add a `nop' operation to the log.
625 kadm5_log_nop (kadm5_server_context *context)
629 kadm5_log_context *log_context = &context->log_context;
631 sp = krb5_storage_emem();
632 ret = kadm5_log_preamble (context, sp, kadm_nop);
634 krb5_storage_free (sp);
637 krb5_store_int32 (sp, 0);
638 krb5_store_int32 (sp, 0);
639 ret = kadm5_log_postamble (log_context, sp);
641 krb5_storage_free (sp);
644 ret = kadm5_log_flush (log_context, sp);
645 krb5_storage_free (sp);
648 ret = kadm5_log_end (context);
653 * Read a `nop' log operation from `sp' and apply it.
657 kadm5_log_replay_nop (kadm5_server_context *context,
666 * Call `func' for each log record in the log in `context'
670 kadm5_log_foreach (kadm5_server_context *context,
671 void (*func)(kadm5_server_context *server_context,
678 int fd = context->log_context.log_fd;
681 lseek (fd, 0, SEEK_SET);
682 sp = krb5_storage_from_fd (fd);
684 int32_t ver, timestamp, op, len;
686 if(krb5_ret_int32 (sp, &ver) != 0)
688 krb5_ret_int32 (sp, ×tamp);
689 krb5_ret_int32 (sp, &op);
690 krb5_ret_int32 (sp, &len);
691 (*func)(context, ver, timestamp, op, len, sp);
692 krb5_storage_seek(sp, 8, SEEK_CUR);
702 kadm5_log_goto_end (int fd)
706 sp = krb5_storage_from_fd (fd);
707 krb5_storage_seek(sp, 0, SEEK_END);
712 * Return previous log entry.
716 kadm5_log_previous (krb5_storage *sp,
725 krb5_storage_seek(sp, -8, SEEK_CUR);
726 krb5_ret_int32 (sp, &tmp);
728 krb5_ret_int32 (sp, &tmp);
731 krb5_storage_seek(sp, -off, SEEK_CUR);
732 krb5_ret_int32 (sp, &tmp);
734 krb5_ret_int32 (sp, &tmp);
736 krb5_ret_int32 (sp, &tmp);
738 krb5_ret_int32 (sp, &tmp);
744 * Replay a record from the log
748 kadm5_log_replay (kadm5_server_context *context,
756 return kadm5_log_replay_create (context, ver, len, sp);
758 return kadm5_log_replay_delete (context, ver, len, sp);
760 return kadm5_log_replay_rename (context, ver, len, sp);
762 return kadm5_log_replay_modify (context, ver, len, sp);
764 return kadm5_log_replay_nop (context, ver, len, sp);
766 return KADM5_FAILURE;
771 * truncate the log - i.e. create an empty file with just (nop vno + 2)
775 kadm5_log_truncate (kadm5_server_context *server_context)
780 ret = kadm5_log_init (server_context);
784 ret = kadm5_log_get_version (server_context, &vno);
788 ret = kadm5_log_reinit (server_context);
792 ret = kadm5_log_set_version (server_context, vno + 1);
796 ret = kadm5_log_nop (server_context);
800 ret = kadm5_log_end (server_context);