use ifdef
[heimdal.git] / lib / kadm5 / log.c
blob7694c715818b9abeb419d268c5a9e4f2a5f1835c
1 /*
2 * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
31 * SUCH DAMAGE.
34 #include "kadm5_locl.h"
35 #include "heim_threads.h"
37 RCSID("$Id$");
40 * A log record consists of:
42 * version number 4 bytes
43 * time in seconds 4 bytes
44 * operation (enum kadm_ops) 4 bytes
45 * length of record 4 bytes
46 * data... n bytes
47 * length of record 4 bytes
48 * version number 4 bytes
52 kadm5_ret_t
53 kadm5_log_get_version_fd (int fd,
54 uint32_t *ver)
56 int ret;
57 krb5_storage *sp;
58 int32_t old_version;
60 ret = lseek (fd, 0, SEEK_END);
61 if(ret < 0)
62 return errno;
63 if(ret == 0) {
64 *ver = 0;
65 return 0;
67 sp = krb5_storage_from_fd (fd);
68 krb5_storage_seek(sp, -4, SEEK_CUR);
69 krb5_ret_int32 (sp, &old_version);
70 *ver = old_version;
71 krb5_storage_free(sp);
72 lseek (fd, 0, SEEK_END);
73 return 0;
76 kadm5_ret_t
77 kadm5_log_get_version (kadm5_server_context *context, uint32_t *ver)
79 return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
82 kadm5_ret_t
83 kadm5_log_set_version (kadm5_server_context *context, uint32_t vno)
85 kadm5_log_context *log_context = &context->log_context;
87 log_context->version = vno;
88 return 0;
91 kadm5_ret_t
92 kadm5_log_init (kadm5_server_context *context)
94 int fd;
95 kadm5_ret_t ret;
96 kadm5_log_context *log_context = &context->log_context;
98 if (log_context->log_fd != -1)
99 return 0;
100 fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
101 if (fd < 0) {
102 ret = errno;
103 krb5_set_error_message(context->context, ret, "kadm5_log_init: open %s",
104 log_context->log_file);
105 return ret;
107 if (flock (fd, LOCK_EX) < 0) {
108 ret = errno;
109 krb5_set_error_message(context->context, ret, "kadm5_log_init: flock %s",
110 log_context->log_file);
111 close (fd);
112 return errno;
115 ret = kadm5_log_get_version_fd (fd, &log_context->version);
116 if (ret)
117 return ret;
119 log_context->log_fd = fd;
120 return 0;
123 kadm5_ret_t
124 kadm5_log_reinit (kadm5_server_context *context)
126 int fd;
127 kadm5_log_context *log_context = &context->log_context;
129 if (log_context->log_fd != -1) {
130 flock (log_context->log_fd, LOCK_UN);
131 close (log_context->log_fd);
132 log_context->log_fd = -1;
134 fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
135 if (fd < 0)
136 return errno;
137 if (flock (fd, LOCK_EX) < 0) {
138 close (fd);
139 return errno;
142 log_context->version = 0;
143 log_context->log_fd = fd;
144 return 0;
148 kadm5_ret_t
149 kadm5_log_end (kadm5_server_context *context)
151 kadm5_log_context *log_context = &context->log_context;
152 int fd = log_context->log_fd;
154 flock (fd, LOCK_UN);
155 close(fd);
156 log_context->log_fd = -1;
157 return 0;
160 static kadm5_ret_t
161 kadm5_log_preamble (kadm5_server_context *context,
162 krb5_storage *sp,
163 enum kadm_ops op)
165 kadm5_log_context *log_context = &context->log_context;
166 kadm5_ret_t kadm_ret;
168 kadm_ret = kadm5_log_init (context);
169 if (kadm_ret)
170 return kadm_ret;
172 krb5_store_int32 (sp, ++log_context->version);
173 krb5_store_int32 (sp, time(NULL));
174 krb5_store_int32 (sp, op);
175 return 0;
178 static kadm5_ret_t
179 kadm5_log_postamble (kadm5_log_context *context,
180 krb5_storage *sp)
182 krb5_store_int32 (sp, context->version);
183 return 0;
187 * flush the log record in `sp'.
190 static kadm5_ret_t
191 kadm5_log_flush (kadm5_log_context *log_context,
192 krb5_storage *sp)
194 krb5_data data;
195 size_t len;
196 int ret;
198 krb5_storage_to_data(sp, &data);
199 len = data.length;
200 ret = write (log_context->log_fd, data.data, len);
201 if (ret != len) {
202 krb5_data_free(&data);
203 return errno;
205 if (fsync (log_context->log_fd) < 0) {
206 krb5_data_free(&data);
207 return errno;
210 * Try to send a signal to any running `ipropd-master'
212 sendto (log_context->socket_fd,
213 (void *)&log_context->version,
214 sizeof(log_context->version),
216 (struct sockaddr *)&log_context->socket_name,
217 sizeof(log_context->socket_name));
219 krb5_data_free(&data);
220 return 0;
224 * Add a `create' operation to the log.
227 kadm5_ret_t
228 kadm5_log_create (kadm5_server_context *context,
229 hdb_entry *ent)
231 krb5_storage *sp;
232 kadm5_ret_t ret;
233 krb5_data value;
234 kadm5_log_context *log_context = &context->log_context;
236 sp = krb5_storage_emem();
237 ret = hdb_entry2value (context->context, ent, &value);
238 if (ret) {
239 krb5_storage_free(sp);
240 return ret;
242 ret = kadm5_log_preamble (context, sp, kadm_create);
243 if (ret) {
244 krb5_data_free (&value);
245 krb5_storage_free(sp);
246 return ret;
248 krb5_store_int32 (sp, value.length);
249 krb5_storage_write(sp, value.data, value.length);
250 krb5_store_int32 (sp, value.length);
251 krb5_data_free (&value);
252 ret = kadm5_log_postamble (log_context, sp);
253 if (ret) {
254 krb5_storage_free (sp);
255 return ret;
257 ret = kadm5_log_flush (log_context, sp);
258 krb5_storage_free (sp);
259 if (ret)
260 return ret;
261 ret = kadm5_log_end (context);
262 return ret;
266 * Read the data of a create log record from `sp' and change the
267 * database.
270 static kadm5_ret_t
271 kadm5_log_replay_create (kadm5_server_context *context,
272 uint32_t ver,
273 uint32_t len,
274 krb5_storage *sp)
276 krb5_error_code ret;
277 krb5_data data;
278 hdb_entry_ex ent;
280 memset(&ent, 0, sizeof(ent));
282 ret = krb5_data_alloc (&data, len);
283 if (ret) {
284 krb5_set_error_message(context->context, ret, "out of memory");
285 return ret;
287 krb5_storage_read (sp, data.data, len);
288 ret = hdb_value2entry (context->context, &data, &ent.entry);
289 krb5_data_free(&data);
290 if (ret) {
291 krb5_set_error_message(context->context, ret,
292 "Unmarshaling hdb entry failed");
293 return ret;
295 ret = context->db->hdb_store(context->context, context->db, 0, &ent);
296 hdb_free_entry (context->context, &ent);
297 return ret;
301 * Add a `delete' operation to the log.
304 kadm5_ret_t
305 kadm5_log_delete (kadm5_server_context *context,
306 krb5_principal princ)
308 krb5_storage *sp;
309 kadm5_ret_t ret;
310 off_t off;
311 off_t len;
312 kadm5_log_context *log_context = &context->log_context;
314 sp = krb5_storage_emem();
315 if (sp == NULL)
316 return ENOMEM;
317 ret = kadm5_log_preamble (context, sp, kadm_delete);
318 if (ret)
319 goto out;
320 ret = krb5_store_int32 (sp, 0);
321 if (ret)
322 goto out;
323 off = krb5_storage_seek (sp, 0, SEEK_CUR);
324 ret = krb5_store_principal (sp, princ);
325 if (ret)
326 goto out;
327 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
328 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
329 ret = krb5_store_int32 (sp, len);
330 if (ret)
331 goto out;
332 krb5_storage_seek(sp, len, SEEK_CUR);
333 ret = krb5_store_int32 (sp, len);
334 if (ret)
335 goto out;
336 ret = kadm5_log_postamble (log_context, sp);
337 if (ret)
338 goto out;
339 ret = kadm5_log_flush (log_context, sp);
340 if (ret)
341 goto out;
342 ret = kadm5_log_end (context);
343 out:
344 krb5_storage_free (sp);
345 return ret;
349 * Read a `delete' log operation from `sp' and apply it.
352 static kadm5_ret_t
353 kadm5_log_replay_delete (kadm5_server_context *context,
354 uint32_t ver,
355 uint32_t len,
356 krb5_storage *sp)
358 krb5_error_code ret;
359 krb5_principal principal;
361 ret = krb5_ret_principal (sp, &principal);
362 if (ret) {
363 krb5_set_error_message(context->context, ret, "Failed to read deleted "
364 "principal from log version: %ld", (long)ver);
365 return ret;
368 ret = context->db->hdb_remove(context->context, context->db, principal);
369 krb5_free_principal (context->context, principal);
370 return ret;
374 * Add a `rename' operation to the log.
377 kadm5_ret_t
378 kadm5_log_rename (kadm5_server_context *context,
379 krb5_principal source,
380 hdb_entry *ent)
382 krb5_storage *sp;
383 kadm5_ret_t ret;
384 off_t off;
385 off_t len;
386 krb5_data value;
387 kadm5_log_context *log_context = &context->log_context;
389 krb5_data_zero(&value);
391 sp = krb5_storage_emem();
392 ret = hdb_entry2value (context->context, ent, &value);
393 if (ret)
394 goto failed;
396 ret = kadm5_log_preamble (context, sp, kadm_rename);
397 if (ret)
398 goto failed;
400 ret = krb5_store_int32 (sp, 0);
401 if (ret)
402 goto failed;
403 off = krb5_storage_seek (sp, 0, SEEK_CUR);
404 ret = krb5_store_principal (sp, source);
405 if (ret)
406 goto failed;
408 krb5_storage_write(sp, value.data, value.length);
409 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
411 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
412 ret = krb5_store_int32 (sp, len);
413 if (ret)
414 goto failed;
416 krb5_storage_seek(sp, len, SEEK_CUR);
417 ret = krb5_store_int32 (sp, len);
418 if (ret)
419 goto failed;
421 ret = kadm5_log_postamble (log_context, sp);
422 if (ret)
423 goto failed;
425 ret = kadm5_log_flush (log_context, sp);
426 if (ret)
427 goto failed;
428 krb5_storage_free (sp);
429 krb5_data_free (&value);
431 return kadm5_log_end (context);
433 failed:
434 krb5_data_free(&value);
435 krb5_storage_free(sp);
436 return ret;
440 * Read a `rename' log operation from `sp' and apply it.
443 static kadm5_ret_t
444 kadm5_log_replay_rename (kadm5_server_context *context,
445 uint32_t ver,
446 uint32_t len,
447 krb5_storage *sp)
449 krb5_error_code ret;
450 krb5_principal source;
451 hdb_entry_ex target_ent;
452 krb5_data value;
453 off_t off;
454 size_t princ_len, data_len;
456 memset(&target_ent, 0, sizeof(target_ent));
458 off = krb5_storage_seek(sp, 0, SEEK_CUR);
459 ret = krb5_ret_principal (sp, &source);
460 if (ret) {
461 krb5_set_error_message(context->context, ret, "Failed to read renamed "
462 "principal in log, version: %ld", (long)ver);
463 return ret;
465 princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
466 data_len = len - princ_len;
467 ret = krb5_data_alloc (&value, data_len);
468 if (ret) {
469 krb5_free_principal (context->context, source);
470 return ret;
472 krb5_storage_read (sp, value.data, data_len);
473 ret = hdb_value2entry (context->context, &value, &target_ent.entry);
474 krb5_data_free(&value);
475 if (ret) {
476 krb5_free_principal (context->context, source);
477 return ret;
479 ret = context->db->hdb_store (context->context, context->db,
480 0, &target_ent);
481 hdb_free_entry (context->context, &target_ent);
482 if (ret) {
483 krb5_free_principal (context->context, source);
484 return ret;
486 ret = context->db->hdb_remove (context->context, context->db, source);
487 krb5_free_principal (context->context, source);
488 return ret;
493 * Add a `modify' operation to the log.
496 kadm5_ret_t
497 kadm5_log_modify (kadm5_server_context *context,
498 hdb_entry *ent,
499 uint32_t mask)
501 krb5_storage *sp;
502 kadm5_ret_t ret;
503 krb5_data value;
504 uint32_t len;
505 kadm5_log_context *log_context = &context->log_context;
507 krb5_data_zero(&value);
509 sp = krb5_storage_emem();
510 ret = hdb_entry2value (context->context, ent, &value);
511 if (ret)
512 goto failed;
514 ret = kadm5_log_preamble (context, sp, kadm_modify);
515 if (ret)
516 goto failed;
518 len = value.length + 4;
519 ret = krb5_store_int32 (sp, len);
520 if (ret)
521 goto failed;
522 ret = krb5_store_int32 (sp, mask);
523 if (ret)
524 goto failed;
525 krb5_storage_write (sp, value.data, value.length);
527 ret = krb5_store_int32 (sp, len);
528 if (ret)
529 goto failed;
530 ret = kadm5_log_postamble (log_context, sp);
531 if (ret)
532 goto failed;
533 ret = kadm5_log_flush (log_context, sp);
534 if (ret)
535 goto failed;
536 krb5_data_free(&value);
537 krb5_storage_free (sp);
538 return kadm5_log_end (context);
539 failed:
540 krb5_data_free(&value);
541 krb5_storage_free(sp);
542 return ret;
546 * Read a `modify' log operation from `sp' and apply it.
549 static kadm5_ret_t
550 kadm5_log_replay_modify (kadm5_server_context *context,
551 uint32_t ver,
552 uint32_t len,
553 krb5_storage *sp)
555 krb5_error_code ret;
556 int32_t mask;
557 krb5_data value;
558 hdb_entry_ex ent, log_ent;
560 memset(&log_ent, 0, sizeof(log_ent));
562 krb5_ret_int32 (sp, &mask);
563 len -= 4;
564 ret = krb5_data_alloc (&value, len);
565 if (ret) {
566 krb5_set_error_message(context->context, ret, "out of memory");
567 return ret;
569 krb5_storage_read (sp, value.data, len);
570 ret = hdb_value2entry (context->context, &value, &log_ent.entry);
571 krb5_data_free(&value);
572 if (ret)
573 return ret;
575 memset(&ent, 0, sizeof(ent));
576 ret = context->db->hdb_fetch(context->context, context->db,
577 log_ent.entry.principal,
578 HDB_F_DECRYPT|HDB_F_GET_ANY, &ent);
579 if (ret)
580 goto out;
581 if (mask & KADM5_PRINC_EXPIRE_TIME) {
582 if (log_ent.entry.valid_end == NULL) {
583 ent.entry.valid_end = NULL;
584 } else {
585 if (ent.entry.valid_end == NULL) {
586 ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
587 if (ent.entry.valid_end == NULL) {
588 ret = ENOMEM;
589 krb5_set_error_message(context->context, ret, "out of memory");
590 goto out;
593 *ent.entry.valid_end = *log_ent.entry.valid_end;
596 if (mask & KADM5_PW_EXPIRATION) {
597 if (log_ent.entry.pw_end == NULL) {
598 ent.entry.pw_end = NULL;
599 } else {
600 if (ent.entry.pw_end == NULL) {
601 ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
602 if (ent.entry.pw_end == NULL) {
603 ret = ENOMEM;
604 krb5_set_error_message(context->context, ret, "out of memory");
605 goto out;
608 *ent.entry.pw_end = *log_ent.entry.pw_end;
611 if (mask & KADM5_LAST_PWD_CHANGE) {
612 abort (); /* XXX */
614 if (mask & KADM5_ATTRIBUTES) {
615 ent.entry.flags = log_ent.entry.flags;
617 if (mask & KADM5_MAX_LIFE) {
618 if (log_ent.entry.max_life == NULL) {
619 ent.entry.max_life = NULL;
620 } else {
621 if (ent.entry.max_life == NULL) {
622 ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
623 if (ent.entry.max_life == NULL) {
624 ret = ENOMEM;
625 krb5_set_error_message(context->context, ret, "out of memory");
626 goto out;
629 *ent.entry.max_life = *log_ent.entry.max_life;
632 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
633 if (ent.entry.modified_by == NULL) {
634 ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
635 if (ent.entry.modified_by == NULL) {
636 ret = ENOMEM;
637 krb5_set_error_message(context->context, ret, "out of memory");
638 goto out;
640 } else
641 free_Event(ent.entry.modified_by);
642 ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
643 if (ret) {
644 krb5_set_error_message(context->context, ret, "out of memory");
645 goto out;
648 if (mask & KADM5_KVNO) {
649 ent.entry.kvno = log_ent.entry.kvno;
651 if (mask & KADM5_MKVNO) {
652 abort (); /* XXX */
654 if (mask & KADM5_AUX_ATTRIBUTES) {
655 abort (); /* XXX */
657 if (mask & KADM5_POLICY) {
658 abort (); /* XXX */
660 if (mask & KADM5_POLICY_CLR) {
661 abort (); /* XXX */
663 if (mask & KADM5_MAX_RLIFE) {
664 if (log_ent.entry.max_renew == NULL) {
665 ent.entry.max_renew = NULL;
666 } else {
667 if (ent.entry.max_renew == NULL) {
668 ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
669 if (ent.entry.max_renew == NULL) {
670 ret = ENOMEM;
671 krb5_set_error_message(context->context, ret, "out of memory");
672 goto out;
675 *ent.entry.max_renew = *log_ent.entry.max_renew;
678 if (mask & KADM5_LAST_SUCCESS) {
679 abort (); /* XXX */
681 if (mask & KADM5_LAST_FAILED) {
682 abort (); /* XXX */
684 if (mask & KADM5_FAIL_AUTH_COUNT) {
685 abort (); /* XXX */
687 if (mask & KADM5_KEY_DATA) {
688 size_t num;
689 int i;
691 for (i = 0; i < ent.entry.keys.len; ++i)
692 free_Key(&ent.entry.keys.val[i]);
693 free (ent.entry.keys.val);
695 num = log_ent.entry.keys.len;
697 ent.entry.keys.len = num;
698 ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
699 if (ent.entry.keys.val == NULL) {
700 krb5_set_error_message(context->context, ENOMEM, "out of memory");
701 return ENOMEM;
703 for (i = 0; i < ent.entry.keys.len; ++i) {
704 ret = copy_Key(&log_ent.entry.keys.val[i],
705 &ent.entry.keys.val[i]);
706 if (ret) {
707 krb5_set_error_message(context->context, ret, "out of memory");
708 goto out;
712 if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
713 HDB_extensions *es = ent.entry.extensions;
715 ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
716 if (ent.entry.extensions == NULL)
717 goto out;
719 ret = copy_HDB_extensions(log_ent.entry.extensions,
720 ent.entry.extensions);
721 if (ret) {
722 krb5_set_error_message(context->context, ret, "out of memory");
723 free(ent.entry.extensions);
724 ent.entry.extensions = es;
725 goto out;
727 if (es) {
728 free_HDB_extensions(es);
729 free(es);
732 ret = context->db->hdb_store(context->context, context->db,
733 HDB_F_REPLACE, &ent);
734 out:
735 hdb_free_entry (context->context, &ent);
736 hdb_free_entry (context->context, &log_ent);
737 return ret;
741 * Add a `nop' operation to the log. Does not close the log.
744 kadm5_ret_t
745 kadm5_log_nop (kadm5_server_context *context)
747 krb5_storage *sp;
748 kadm5_ret_t ret;
749 kadm5_log_context *log_context = &context->log_context;
751 sp = krb5_storage_emem();
752 ret = kadm5_log_preamble (context, sp, kadm_nop);
753 if (ret) {
754 krb5_storage_free (sp);
755 return ret;
757 krb5_store_int32 (sp, 0);
758 krb5_store_int32 (sp, 0);
759 ret = kadm5_log_postamble (log_context, sp);
760 if (ret) {
761 krb5_storage_free (sp);
762 return ret;
764 ret = kadm5_log_flush (log_context, sp);
765 krb5_storage_free (sp);
767 return ret;
771 * Read a `nop' log operation from `sp' and apply it.
774 static kadm5_ret_t
775 kadm5_log_replay_nop (kadm5_server_context *context,
776 uint32_t ver,
777 uint32_t len,
778 krb5_storage *sp)
780 return 0;
784 * Call `func' for each log record in the log in `context'
787 kadm5_ret_t
788 kadm5_log_foreach (kadm5_server_context *context,
789 void (*func)(kadm5_server_context *server_context,
790 uint32_t ver,
791 time_t timestamp,
792 enum kadm_ops op,
793 uint32_t len,
794 krb5_storage *,
795 void *),
796 void *ctx)
798 int fd = context->log_context.log_fd;
799 krb5_storage *sp;
801 lseek (fd, 0, SEEK_SET);
802 sp = krb5_storage_from_fd (fd);
803 for (;;) {
804 int32_t ver, timestamp, op, len, len2, ver2;
806 if(krb5_ret_int32 (sp, &ver) != 0)
807 break;
808 krb5_ret_int32 (sp, &timestamp);
809 krb5_ret_int32 (sp, &op);
810 krb5_ret_int32 (sp, &len);
811 (*func)(context, ver, timestamp, op, len, sp, ctx);
812 krb5_ret_int32 (sp, &len2);
813 krb5_ret_int32 (sp, &ver2);
814 if (len != len2)
815 abort();
816 if (ver != ver2)
817 abort();
819 krb5_storage_free(sp);
820 return 0;
824 * Go to end of log.
827 krb5_storage *
828 kadm5_log_goto_end (int fd)
830 krb5_storage *sp;
832 sp = krb5_storage_from_fd (fd);
833 krb5_storage_seek(sp, 0, SEEK_END);
834 return sp;
838 * Return previous log entry.
840 * The pointer in `sp´ is assumed to be at the top of the entry before
841 * previous entry. On success, the `sp´ pointer is set to data portion
842 * of previous entry. In case of error, it's not changed at all.
845 kadm5_ret_t
846 kadm5_log_previous (krb5_context context,
847 krb5_storage *sp,
848 uint32_t *ver,
849 time_t *timestamp,
850 enum kadm_ops *op,
851 uint32_t *len)
853 krb5_error_code ret;
854 off_t off, oldoff;
855 int32_t tmp;
857 oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
859 krb5_storage_seek(sp, -8, SEEK_CUR);
860 ret = krb5_ret_int32 (sp, &tmp);
861 if (ret)
862 goto end_of_storage;
863 *len = tmp;
864 ret = krb5_ret_int32 (sp, &tmp);
865 if (ret)
866 goto end_of_storage;
867 *ver = tmp;
868 off = 24 + *len;
869 krb5_storage_seek(sp, -off, SEEK_CUR);
870 ret = krb5_ret_int32 (sp, &tmp);
871 if (ret)
872 goto end_of_storage;
873 if (tmp != *ver) {
874 krb5_storage_seek(sp, oldoff, SEEK_SET);
875 krb5_set_error_message(context, KADM5_BAD_DB,
876 "kadm5_log_previous: log entry "
877 "have consistency failure, version number wrong");
878 return KADM5_BAD_DB;
880 ret = krb5_ret_int32 (sp, &tmp);
881 if (ret)
882 goto end_of_storage;
883 *timestamp = tmp;
884 ret = krb5_ret_int32 (sp, &tmp);
885 if (ret)
886 goto end_of_storage;
887 *op = tmp;
888 ret = krb5_ret_int32 (sp, &tmp);
889 if (ret)
890 goto end_of_storage;
891 if (tmp != *len) {
892 krb5_storage_seek(sp, oldoff, SEEK_SET);
893 krb5_set_error_message(context, KADM5_BAD_DB,
894 "kadm5_log_previous: log entry "
895 "have consistency failure, length wrong");
896 return KADM5_BAD_DB;
898 return 0;
900 end_of_storage:
901 krb5_storage_seek(sp, oldoff, SEEK_SET);
902 krb5_set_error_message(context, ret, "kadm5_log_previous: end of storage "
903 "reached before end");
904 return ret;
908 * Replay a record from the log
911 kadm5_ret_t
912 kadm5_log_replay (kadm5_server_context *context,
913 enum kadm_ops op,
914 uint32_t ver,
915 uint32_t len,
916 krb5_storage *sp)
918 switch (op) {
919 case kadm_create :
920 return kadm5_log_replay_create (context, ver, len, sp);
921 case kadm_delete :
922 return kadm5_log_replay_delete (context, ver, len, sp);
923 case kadm_rename :
924 return kadm5_log_replay_rename (context, ver, len, sp);
925 case kadm_modify :
926 return kadm5_log_replay_modify (context, ver, len, sp);
927 case kadm_nop :
928 return kadm5_log_replay_nop (context, ver, len, sp);
929 default :
930 krb5_set_error_message(context->context, KADM5_FAILURE,
931 "Unsupported replay op %d", (int)op);
932 return KADM5_FAILURE;
937 * truncate the log - i.e. create an empty file with just (nop vno + 2)
940 kadm5_ret_t
941 kadm5_log_truncate (kadm5_server_context *server_context)
943 kadm5_ret_t ret;
944 uint32_t vno;
946 ret = kadm5_log_init (server_context);
947 if (ret)
948 return ret;
950 ret = kadm5_log_get_version (server_context, &vno);
951 if (ret)
952 return ret;
954 ret = kadm5_log_reinit (server_context);
955 if (ret)
956 return ret;
958 ret = kadm5_log_set_version (server_context, vno);
959 if (ret)
960 return ret;
962 ret = kadm5_log_nop (server_context);
963 if (ret)
964 return ret;
966 ret = kadm5_log_end (server_context);
967 if (ret)
968 return ret;
969 return 0;
973 static char *default_signal = NULL;
974 static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
976 const char *
977 kadm5_log_signal_socket(krb5_context context)
979 HEIMDAL_MUTEX_lock(&signal_mutex);
980 if (!default_signal)
981 asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
982 HEIMDAL_MUTEX_unlock(&signal_mutex);
984 return krb5_config_get_string_default(context,
985 NULL,
986 default_signal,
987 "kdc",
988 "signal_socket",
989 NULL);