Use unsigned where appropriate.
[heimdal.git] / lib / kadm5 / log.c
blob1fec09f3dde48d167da0ec5a935984d814ce1213
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 krb5_set_error_string(context->context, "kadm5_log_init: open %s",
103 log_context->log_file);
104 return errno;
106 if (flock (fd, LOCK_EX) < 0) {
107 krb5_set_error_string(context->context, "kadm5_log_init: flock %s",
108 log_context->log_file);
109 close (fd);
110 return errno;
113 ret = kadm5_log_get_version_fd (fd, &log_context->version);
114 if (ret)
115 return ret;
117 log_context->log_fd = fd;
118 return 0;
121 kadm5_ret_t
122 kadm5_log_reinit (kadm5_server_context *context)
124 int fd;
125 kadm5_log_context *log_context = &context->log_context;
127 if (log_context->log_fd != -1) {
128 flock (log_context->log_fd, LOCK_UN);
129 close (log_context->log_fd);
130 log_context->log_fd = -1;
132 fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
133 if (fd < 0)
134 return errno;
135 if (flock (fd, LOCK_EX) < 0) {
136 close (fd);
137 return errno;
140 log_context->version = 0;
141 log_context->log_fd = fd;
142 return 0;
146 kadm5_ret_t
147 kadm5_log_end (kadm5_server_context *context)
149 kadm5_log_context *log_context = &context->log_context;
150 int fd = log_context->log_fd;
152 flock (fd, LOCK_UN);
153 close(fd);
154 log_context->log_fd = -1;
155 return 0;
158 static kadm5_ret_t
159 kadm5_log_preamble (kadm5_server_context *context,
160 krb5_storage *sp,
161 enum kadm_ops op)
163 kadm5_log_context *log_context = &context->log_context;
164 kadm5_ret_t kadm_ret;
166 kadm_ret = kadm5_log_init (context);
167 if (kadm_ret)
168 return kadm_ret;
170 krb5_store_int32 (sp, ++log_context->version);
171 krb5_store_int32 (sp, time(NULL));
172 krb5_store_int32 (sp, op);
173 return 0;
176 static kadm5_ret_t
177 kadm5_log_postamble (kadm5_log_context *context,
178 krb5_storage *sp)
180 krb5_store_int32 (sp, context->version);
181 return 0;
185 * flush the log record in `sp'.
188 static kadm5_ret_t
189 kadm5_log_flush (kadm5_log_context *log_context,
190 krb5_storage *sp)
192 krb5_data data;
193 size_t len;
194 int ret;
196 krb5_storage_to_data(sp, &data);
197 len = data.length;
198 ret = write (log_context->log_fd, data.data, len);
199 if (ret != len) {
200 krb5_data_free(&data);
201 return errno;
203 if (fsync (log_context->log_fd) < 0) {
204 krb5_data_free(&data);
205 return errno;
208 * Try to send a signal to any running `ipropd-master'
210 sendto (log_context->socket_fd,
211 (void *)&log_context->version,
212 sizeof(log_context->version),
214 (struct sockaddr *)&log_context->socket_name,
215 sizeof(log_context->socket_name));
217 krb5_data_free(&data);
218 return 0;
222 * Add a `create' operation to the log.
225 kadm5_ret_t
226 kadm5_log_create (kadm5_server_context *context,
227 hdb_entry *ent)
229 krb5_storage *sp;
230 kadm5_ret_t ret;
231 krb5_data value;
232 kadm5_log_context *log_context = &context->log_context;
234 sp = krb5_storage_emem();
235 ret = hdb_entry2value (context->context, ent, &value);
236 if (ret) {
237 krb5_storage_free(sp);
238 return ret;
240 ret = kadm5_log_preamble (context, sp, kadm_create);
241 if (ret) {
242 krb5_data_free (&value);
243 krb5_storage_free(sp);
244 return ret;
246 krb5_store_int32 (sp, value.length);
247 krb5_storage_write(sp, value.data, value.length);
248 krb5_store_int32 (sp, value.length);
249 krb5_data_free (&value);
250 ret = kadm5_log_postamble (log_context, sp);
251 if (ret) {
252 krb5_storage_free (sp);
253 return ret;
255 ret = kadm5_log_flush (log_context, sp);
256 krb5_storage_free (sp);
257 if (ret)
258 return ret;
259 ret = kadm5_log_end (context);
260 return ret;
264 * Read the data of a create log record from `sp' and change the
265 * database.
268 static kadm5_ret_t
269 kadm5_log_replay_create (kadm5_server_context *context,
270 uint32_t ver,
271 uint32_t len,
272 krb5_storage *sp)
274 krb5_error_code ret;
275 krb5_data data;
276 hdb_entry_ex ent;
278 memset(&ent, 0, sizeof(ent));
280 ret = krb5_data_alloc (&data, len);
281 if (ret) {
282 krb5_set_error_string(context->context, "out of memory");
283 return ret;
285 krb5_storage_read (sp, data.data, len);
286 ret = hdb_value2entry (context->context, &data, &ent.entry);
287 krb5_data_free(&data);
288 if (ret) {
289 krb5_set_error_string(context->context,
290 "Unmarshaling hdb entry failed");
291 return ret;
293 ret = context->db->hdb_store(context->context, context->db, 0, &ent);
294 hdb_free_entry (context->context, &ent);
295 return ret;
299 * Add a `delete' operation to the log.
302 kadm5_ret_t
303 kadm5_log_delete (kadm5_server_context *context,
304 krb5_principal princ)
306 krb5_storage *sp;
307 kadm5_ret_t ret;
308 off_t off;
309 off_t len;
310 kadm5_log_context *log_context = &context->log_context;
312 sp = krb5_storage_emem();
313 if (sp == NULL)
314 return ENOMEM;
315 ret = kadm5_log_preamble (context, sp, kadm_delete);
316 if (ret)
317 goto out;
318 ret = krb5_store_int32 (sp, 0);
319 if (ret)
320 goto out;
321 off = krb5_storage_seek (sp, 0, SEEK_CUR);
322 ret = krb5_store_principal (sp, princ);
323 if (ret)
324 goto out;
325 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
326 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
327 ret = krb5_store_int32 (sp, len);
328 if (ret)
329 goto out;
330 krb5_storage_seek(sp, len, SEEK_CUR);
331 ret = krb5_store_int32 (sp, len);
332 if (ret)
333 goto out;
334 ret = kadm5_log_postamble (log_context, sp);
335 if (ret)
336 goto out;
337 ret = kadm5_log_flush (log_context, sp);
338 if (ret)
339 goto out;
340 ret = kadm5_log_end (context);
341 out:
342 krb5_storage_free (sp);
343 return ret;
347 * Read a `delete' log operation from `sp' and apply it.
350 static kadm5_ret_t
351 kadm5_log_replay_delete (kadm5_server_context *context,
352 uint32_t ver,
353 uint32_t len,
354 krb5_storage *sp)
356 krb5_error_code ret;
357 krb5_principal principal;
359 ret = krb5_ret_principal (sp, &principal);
360 if (ret) {
361 krb5_set_error_string(context->context, "Failed to read deleted "
362 "principal from log version: %ld", (long)ver);
363 return ret;
366 ret = context->db->hdb_remove(context->context, context->db, principal);
367 krb5_free_principal (context->context, principal);
368 return ret;
372 * Add a `rename' operation to the log.
375 kadm5_ret_t
376 kadm5_log_rename (kadm5_server_context *context,
377 krb5_principal source,
378 hdb_entry *ent)
380 krb5_storage *sp;
381 kadm5_ret_t ret;
382 off_t off;
383 off_t len;
384 krb5_data value;
385 kadm5_log_context *log_context = &context->log_context;
387 krb5_data_zero(&value);
389 sp = krb5_storage_emem();
390 ret = hdb_entry2value (context->context, ent, &value);
391 if (ret)
392 goto failed;
394 ret = kadm5_log_preamble (context, sp, kadm_rename);
395 if (ret)
396 goto failed;
398 ret = krb5_store_int32 (sp, 0);
399 if (ret)
400 goto failed;
401 off = krb5_storage_seek (sp, 0, SEEK_CUR);
402 ret = krb5_store_principal (sp, source);
403 if (ret)
404 goto failed;
406 krb5_storage_write(sp, value.data, value.length);
407 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
409 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
410 ret = krb5_store_int32 (sp, len);
411 if (ret)
412 goto failed;
414 krb5_storage_seek(sp, len, SEEK_CUR);
415 ret = krb5_store_int32 (sp, len);
416 if (ret)
417 goto failed;
419 ret = kadm5_log_postamble (log_context, sp);
420 if (ret)
421 goto failed;
423 ret = kadm5_log_flush (log_context, sp);
424 if (ret)
425 goto failed;
426 krb5_storage_free (sp);
427 krb5_data_free (&value);
429 return kadm5_log_end (context);
431 failed:
432 krb5_data_free(&value);
433 krb5_storage_free(sp);
434 return ret;
438 * Read a `rename' log operation from `sp' and apply it.
441 static kadm5_ret_t
442 kadm5_log_replay_rename (kadm5_server_context *context,
443 uint32_t ver,
444 uint32_t len,
445 krb5_storage *sp)
447 krb5_error_code ret;
448 krb5_principal source;
449 hdb_entry_ex target_ent;
450 krb5_data value;
451 off_t off;
452 size_t princ_len, data_len;
454 memset(&target_ent, 0, sizeof(target_ent));
456 off = krb5_storage_seek(sp, 0, SEEK_CUR);
457 ret = krb5_ret_principal (sp, &source);
458 if (ret) {
459 krb5_set_error_string(context->context, "Failed to read renamed "
460 "principal in log, version: %ld", (long)ver);
461 return ret;
463 princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
464 data_len = len - princ_len;
465 ret = krb5_data_alloc (&value, data_len);
466 if (ret) {
467 krb5_free_principal (context->context, source);
468 return ret;
470 krb5_storage_read (sp, value.data, data_len);
471 ret = hdb_value2entry (context->context, &value, &target_ent.entry);
472 krb5_data_free(&value);
473 if (ret) {
474 krb5_free_principal (context->context, source);
475 return ret;
477 ret = context->db->hdb_store (context->context, context->db,
478 0, &target_ent);
479 hdb_free_entry (context->context, &target_ent);
480 if (ret) {
481 krb5_free_principal (context->context, source);
482 return ret;
484 ret = context->db->hdb_remove (context->context, context->db, source);
485 krb5_free_principal (context->context, source);
486 return ret;
491 * Add a `modify' operation to the log.
494 kadm5_ret_t
495 kadm5_log_modify (kadm5_server_context *context,
496 hdb_entry *ent,
497 uint32_t mask)
499 krb5_storage *sp;
500 kadm5_ret_t ret;
501 krb5_data value;
502 uint32_t len;
503 kadm5_log_context *log_context = &context->log_context;
505 krb5_data_zero(&value);
507 sp = krb5_storage_emem();
508 ret = hdb_entry2value (context->context, ent, &value);
509 if (ret)
510 goto failed;
512 ret = kadm5_log_preamble (context, sp, kadm_modify);
513 if (ret)
514 goto failed;
516 len = value.length + 4;
517 ret = krb5_store_int32 (sp, len);
518 if (ret)
519 goto failed;
520 ret = krb5_store_int32 (sp, mask);
521 if (ret)
522 goto failed;
523 krb5_storage_write (sp, value.data, value.length);
525 ret = krb5_store_int32 (sp, len);
526 if (ret)
527 goto failed;
528 ret = kadm5_log_postamble (log_context, sp);
529 if (ret)
530 goto failed;
531 ret = kadm5_log_flush (log_context, sp);
532 if (ret)
533 goto failed;
534 krb5_data_free(&value);
535 krb5_storage_free (sp);
536 return kadm5_log_end (context);
537 failed:
538 krb5_data_free(&value);
539 krb5_storage_free(sp);
540 return ret;
544 * Read a `modify' log operation from `sp' and apply it.
547 static kadm5_ret_t
548 kadm5_log_replay_modify (kadm5_server_context *context,
549 uint32_t ver,
550 uint32_t len,
551 krb5_storage *sp)
553 krb5_error_code ret;
554 int32_t mask;
555 krb5_data value;
556 hdb_entry_ex ent, log_ent;
558 memset(&log_ent, 0, sizeof(log_ent));
560 krb5_ret_int32 (sp, &mask);
561 len -= 4;
562 ret = krb5_data_alloc (&value, len);
563 if (ret) {
564 krb5_set_error_string(context->context, "out of memory");
565 return ret;
567 krb5_storage_read (sp, value.data, len);
568 ret = hdb_value2entry (context->context, &value, &log_ent.entry);
569 krb5_data_free(&value);
570 if (ret)
571 return ret;
573 memset(&ent, 0, sizeof(ent));
574 ret = context->db->hdb_fetch(context->context, context->db,
575 log_ent.entry.principal,
576 HDB_F_DECRYPT|HDB_F_GET_ANY, &ent);
577 if (ret)
578 goto out;
579 if (mask & KADM5_PRINC_EXPIRE_TIME) {
580 if (log_ent.entry.valid_end == NULL) {
581 ent.entry.valid_end = NULL;
582 } else {
583 if (ent.entry.valid_end == NULL) {
584 ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
585 if (ent.entry.valid_end == NULL) {
586 krb5_set_error_string(context->context, "out of memory");
587 ret = ENOMEM;
588 goto out;
591 *ent.entry.valid_end = *log_ent.entry.valid_end;
594 if (mask & KADM5_PW_EXPIRATION) {
595 if (log_ent.entry.pw_end == NULL) {
596 ent.entry.pw_end = NULL;
597 } else {
598 if (ent.entry.pw_end == NULL) {
599 ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
600 if (ent.entry.pw_end == NULL) {
601 krb5_set_error_string(context->context, "out of memory");
602 ret = ENOMEM;
603 goto out;
606 *ent.entry.pw_end = *log_ent.entry.pw_end;
609 if (mask & KADM5_LAST_PWD_CHANGE) {
610 abort (); /* XXX */
612 if (mask & KADM5_ATTRIBUTES) {
613 ent.entry.flags = log_ent.entry.flags;
615 if (mask & KADM5_MAX_LIFE) {
616 if (log_ent.entry.max_life == NULL) {
617 ent.entry.max_life = NULL;
618 } else {
619 if (ent.entry.max_life == NULL) {
620 ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
621 if (ent.entry.max_life == NULL) {
622 krb5_set_error_string(context->context, "out of memory");
623 ret = ENOMEM;
624 goto out;
627 *ent.entry.max_life = *log_ent.entry.max_life;
630 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
631 if (ent.entry.modified_by == NULL) {
632 ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
633 if (ent.entry.modified_by == NULL) {
634 krb5_set_error_string(context->context, "out of memory");
635 ret = ENOMEM;
636 goto out;
638 } else
639 free_Event(ent.entry.modified_by);
640 ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
641 if (ret) {
642 krb5_set_error_string(context->context, "out of memory");
643 goto out;
646 if (mask & KADM5_KVNO) {
647 ent.entry.kvno = log_ent.entry.kvno;
649 if (mask & KADM5_MKVNO) {
650 abort (); /* XXX */
652 if (mask & KADM5_AUX_ATTRIBUTES) {
653 abort (); /* XXX */
655 if (mask & KADM5_POLICY) {
656 abort (); /* XXX */
658 if (mask & KADM5_POLICY_CLR) {
659 abort (); /* XXX */
661 if (mask & KADM5_MAX_RLIFE) {
662 if (log_ent.entry.max_renew == NULL) {
663 ent.entry.max_renew = NULL;
664 } else {
665 if (ent.entry.max_renew == NULL) {
666 ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
667 if (ent.entry.max_renew == NULL) {
668 krb5_set_error_string(context->context, "out of memory");
669 ret = ENOMEM;
670 goto out;
673 *ent.entry.max_renew = *log_ent.entry.max_renew;
676 if (mask & KADM5_LAST_SUCCESS) {
677 abort (); /* XXX */
679 if (mask & KADM5_LAST_FAILED) {
680 abort (); /* XXX */
682 if (mask & KADM5_FAIL_AUTH_COUNT) {
683 abort (); /* XXX */
685 if (mask & KADM5_KEY_DATA) {
686 size_t num;
687 int i;
689 for (i = 0; i < ent.entry.keys.len; ++i)
690 free_Key(&ent.entry.keys.val[i]);
691 free (ent.entry.keys.val);
693 num = log_ent.entry.keys.len;
695 ent.entry.keys.len = num;
696 ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
697 if (ent.entry.keys.val == NULL) {
698 krb5_set_error_string(context->context, "out of memory");
699 return ENOMEM;
701 for (i = 0; i < ent.entry.keys.len; ++i) {
702 ret = copy_Key(&log_ent.entry.keys.val[i],
703 &ent.entry.keys.val[i]);
704 if (ret) {
705 krb5_set_error_string(context->context, "out of memory");
706 goto out;
710 if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
711 HDB_extensions *es = ent.entry.extensions;
713 ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
714 if (ent.entry.extensions == NULL)
715 goto out;
717 ret = copy_HDB_extensions(log_ent.entry.extensions,
718 ent.entry.extensions);
719 if (ret) {
720 krb5_set_error_string(context->context, "out of memory");
721 free(ent.entry.extensions);
722 ent.entry.extensions = es;
723 goto out;
725 if (es) {
726 free_HDB_extensions(es);
727 free(es);
730 ret = context->db->hdb_store(context->context, context->db,
731 HDB_F_REPLACE, &ent);
732 out:
733 hdb_free_entry (context->context, &ent);
734 hdb_free_entry (context->context, &log_ent);
735 return ret;
739 * Add a `nop' operation to the log. Does not close the log.
742 kadm5_ret_t
743 kadm5_log_nop (kadm5_server_context *context)
745 krb5_storage *sp;
746 kadm5_ret_t ret;
747 kadm5_log_context *log_context = &context->log_context;
749 sp = krb5_storage_emem();
750 ret = kadm5_log_preamble (context, sp, kadm_nop);
751 if (ret) {
752 krb5_storage_free (sp);
753 return ret;
755 krb5_store_int32 (sp, 0);
756 krb5_store_int32 (sp, 0);
757 ret = kadm5_log_postamble (log_context, sp);
758 if (ret) {
759 krb5_storage_free (sp);
760 return ret;
762 ret = kadm5_log_flush (log_context, sp);
763 krb5_storage_free (sp);
765 return ret;
769 * Read a `nop' log operation from `sp' and apply it.
772 static kadm5_ret_t
773 kadm5_log_replay_nop (kadm5_server_context *context,
774 uint32_t ver,
775 uint32_t len,
776 krb5_storage *sp)
778 return 0;
782 * Call `func' for each log record in the log in `context'
785 kadm5_ret_t
786 kadm5_log_foreach (kadm5_server_context *context,
787 void (*func)(kadm5_server_context *server_context,
788 uint32_t ver,
789 time_t timestamp,
790 enum kadm_ops op,
791 uint32_t len,
792 krb5_storage *,
793 void *),
794 void *ctx)
796 int fd = context->log_context.log_fd;
797 krb5_storage *sp;
799 lseek (fd, 0, SEEK_SET);
800 sp = krb5_storage_from_fd (fd);
801 for (;;) {
802 int32_t ver, timestamp, op, len, len2, ver2;
804 if(krb5_ret_int32 (sp, &ver) != 0)
805 break;
806 krb5_ret_int32 (sp, &timestamp);
807 krb5_ret_int32 (sp, &op);
808 krb5_ret_int32 (sp, &len);
809 (*func)(context, ver, timestamp, op, len, sp, ctx);
810 krb5_ret_int32 (sp, &len2);
811 krb5_ret_int32 (sp, &ver2);
812 if (len != len2)
813 abort();
814 if (ver != ver2)
815 abort();
817 krb5_storage_free(sp);
818 return 0;
822 * Go to end of log.
825 krb5_storage *
826 kadm5_log_goto_end (int fd)
828 krb5_storage *sp;
830 sp = krb5_storage_from_fd (fd);
831 krb5_storage_seek(sp, 0, SEEK_END);
832 return sp;
836 * Return previous log entry.
838 * The pointer in `sp´ is assumed to be at the top of the entry before
839 * previous entry. On success, the `sp´ pointer is set to data portion
840 * of previous entry. In case of error, it's not changed at all.
843 kadm5_ret_t
844 kadm5_log_previous (krb5_context context,
845 krb5_storage *sp,
846 uint32_t *ver,
847 time_t *timestamp,
848 enum kadm_ops *op,
849 uint32_t *len)
851 krb5_error_code ret;
852 off_t off, oldoff;
853 int32_t tmp;
855 oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
857 krb5_storage_seek(sp, -8, SEEK_CUR);
858 ret = krb5_ret_int32 (sp, &tmp);
859 if (ret)
860 goto end_of_storage;
861 *len = tmp;
862 ret = krb5_ret_int32 (sp, &tmp);
863 *ver = tmp;
864 off = 24 + *len;
865 krb5_storage_seek(sp, -off, SEEK_CUR);
866 ret = krb5_ret_int32 (sp, &tmp);
867 if (ret)
868 goto end_of_storage;
869 if (tmp != *ver) {
870 krb5_storage_seek(sp, oldoff, SEEK_SET);
871 krb5_set_error_string(context, "kadm5_log_previous: log entry "
872 "have consistency failure, version number wrong");
873 return KADM5_BAD_DB;
875 ret = krb5_ret_int32 (sp, &tmp);
876 if (ret)
877 goto end_of_storage;
878 *timestamp = tmp;
879 ret = krb5_ret_int32 (sp, &tmp);
880 *op = tmp;
881 ret = krb5_ret_int32 (sp, &tmp);
882 if (ret)
883 goto end_of_storage;
884 if (tmp != *len) {
885 krb5_storage_seek(sp, oldoff, SEEK_SET);
886 krb5_set_error_string(context, "kadm5_log_previous: log entry "
887 "have consistency failure, length wrong");
888 return KADM5_BAD_DB;
890 return 0;
892 end_of_storage:
893 krb5_storage_seek(sp, oldoff, SEEK_SET);
894 krb5_set_error_string(context, "kadm5_log_previous: end of storage "
895 "reached before end");
896 return ret;
900 * Replay a record from the log
903 kadm5_ret_t
904 kadm5_log_replay (kadm5_server_context *context,
905 enum kadm_ops op,
906 uint32_t ver,
907 uint32_t len,
908 krb5_storage *sp)
910 switch (op) {
911 case kadm_create :
912 return kadm5_log_replay_create (context, ver, len, sp);
913 case kadm_delete :
914 return kadm5_log_replay_delete (context, ver, len, sp);
915 case kadm_rename :
916 return kadm5_log_replay_rename (context, ver, len, sp);
917 case kadm_modify :
918 return kadm5_log_replay_modify (context, ver, len, sp);
919 case kadm_nop :
920 return kadm5_log_replay_nop (context, ver, len, sp);
921 default :
922 krb5_set_error_string(context->context,
923 "Unsupported replay op %d", (int)op);
924 return KADM5_FAILURE;
929 * truncate the log - i.e. create an empty file with just (nop vno + 2)
932 kadm5_ret_t
933 kadm5_log_truncate (kadm5_server_context *server_context)
935 kadm5_ret_t ret;
936 uint32_t vno;
938 ret = kadm5_log_init (server_context);
939 if (ret)
940 return ret;
942 ret = kadm5_log_get_version (server_context, &vno);
943 if (ret)
944 return ret;
946 ret = kadm5_log_reinit (server_context);
947 if (ret)
948 return ret;
950 ret = kadm5_log_set_version (server_context, vno);
951 if (ret)
952 return ret;
954 ret = kadm5_log_nop (server_context);
955 if (ret)
956 return ret;
958 ret = kadm5_log_end (server_context);
959 if (ret)
960 return ret;
961 return 0;
965 static char *default_signal = NULL;
966 static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
968 const char *
969 kadm5_log_signal_socket(krb5_context context)
971 HEIMDAL_MUTEX_lock(&signal_mutex);
972 if (!default_signal)
973 asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
974 HEIMDAL_MUTEX_unlock(&signal_mutex);
976 return krb5_config_get_string_default(context,
977 NULL,
978 default_signal,
979 "kdc",
980 "signal_socket",
981 NULL);