No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / kadm5 / log.c
blob2aa2d3974bf87b64ae4e0829abc54684eb449105
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("$Heimdal: log.c 22211 2007-12-07 19:27:27Z lha $"
38 "$NetBSD$");
41 * A log record consists of:
43 * version number 4 bytes
44 * time in seconds 4 bytes
45 * operation (enum kadm_ops) 4 bytes
46 * length of record 4 bytes
47 * data... n bytes
48 * length of record 4 bytes
49 * version number 4 bytes
53 kadm5_ret_t
54 kadm5_log_get_version_fd (int fd,
55 uint32_t *ver)
57 int ret;
58 krb5_storage *sp;
59 int32_t old_version;
61 ret = lseek (fd, 0, SEEK_END);
62 if(ret < 0)
63 return errno;
64 if(ret == 0) {
65 *ver = 0;
66 return 0;
68 sp = krb5_storage_from_fd (fd);
69 krb5_storage_seek(sp, -4, SEEK_CUR);
70 krb5_ret_int32 (sp, &old_version);
71 *ver = old_version;
72 krb5_storage_free(sp);
73 lseek (fd, 0, SEEK_END);
74 return 0;
77 kadm5_ret_t
78 kadm5_log_get_version (kadm5_server_context *context, uint32_t *ver)
80 return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
83 kadm5_ret_t
84 kadm5_log_set_version (kadm5_server_context *context, uint32_t vno)
86 kadm5_log_context *log_context = &context->log_context;
88 log_context->version = vno;
89 return 0;
92 kadm5_ret_t
93 kadm5_log_init (kadm5_server_context *context)
95 int fd;
96 kadm5_ret_t ret;
97 kadm5_log_context *log_context = &context->log_context;
99 if (log_context->log_fd != -1)
100 return 0;
101 fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
102 if (fd < 0) {
103 krb5_set_error_string(context->context, "kadm5_log_init: open %s",
104 log_context->log_file);
105 return errno;
107 if (flock (fd, LOCK_EX) < 0) {
108 krb5_set_error_string(context->context, "kadm5_log_init: flock %s",
109 log_context->log_file);
110 close (fd);
111 return errno;
114 ret = kadm5_log_get_version_fd (fd, &log_context->version);
115 if (ret)
116 return ret;
118 log_context->log_fd = fd;
119 return 0;
122 kadm5_ret_t
123 kadm5_log_reinit (kadm5_server_context *context)
125 int fd;
126 kadm5_log_context *log_context = &context->log_context;
128 if (log_context->log_fd != -1) {
129 flock (log_context->log_fd, LOCK_UN);
130 close (log_context->log_fd);
131 log_context->log_fd = -1;
133 fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
134 if (fd < 0)
135 return errno;
136 if (flock (fd, LOCK_EX) < 0) {
137 close (fd);
138 return errno;
141 log_context->version = 0;
142 log_context->log_fd = fd;
143 return 0;
147 kadm5_ret_t
148 kadm5_log_end (kadm5_server_context *context)
150 kadm5_log_context *log_context = &context->log_context;
151 int fd = log_context->log_fd;
153 flock (fd, LOCK_UN);
154 close(fd);
155 log_context->log_fd = -1;
156 return 0;
159 static kadm5_ret_t
160 kadm5_log_preamble (kadm5_server_context *context,
161 krb5_storage *sp,
162 enum kadm_ops op)
164 kadm5_log_context *log_context = &context->log_context;
165 kadm5_ret_t kadm_ret;
167 kadm_ret = kadm5_log_init (context);
168 if (kadm_ret)
169 return kadm_ret;
171 krb5_store_int32 (sp, ++log_context->version);
172 krb5_store_int32 (sp, time(NULL));
173 krb5_store_int32 (sp, op);
174 return 0;
177 static kadm5_ret_t
178 kadm5_log_postamble (kadm5_log_context *context,
179 krb5_storage *sp)
181 krb5_store_int32 (sp, context->version);
182 return 0;
186 * flush the log record in `sp'.
189 static kadm5_ret_t
190 kadm5_log_flush (kadm5_log_context *log_context,
191 krb5_storage *sp)
193 krb5_data data;
194 size_t len;
195 int ret;
197 krb5_storage_to_data(sp, &data);
198 len = data.length;
199 ret = write (log_context->log_fd, data.data, len);
200 if (ret != len) {
201 krb5_data_free(&data);
202 return errno;
204 if (fsync (log_context->log_fd) < 0) {
205 krb5_data_free(&data);
206 return errno;
209 * Try to send a signal to any running `ipropd-master'
211 sendto (log_context->socket_fd,
212 (void *)&log_context->version,
213 sizeof(log_context->version),
215 (struct sockaddr *)&log_context->socket_name,
216 sizeof(log_context->socket_name));
218 krb5_data_free(&data);
219 return 0;
223 * Add a `create' operation to the log.
226 kadm5_ret_t
227 kadm5_log_create (kadm5_server_context *context,
228 hdb_entry *ent)
230 krb5_storage *sp;
231 kadm5_ret_t ret;
232 krb5_data value;
233 kadm5_log_context *log_context = &context->log_context;
235 sp = krb5_storage_emem();
236 ret = hdb_entry2value (context->context, ent, &value);
237 if (ret) {
238 krb5_storage_free(sp);
239 return ret;
241 ret = kadm5_log_preamble (context, sp, kadm_create);
242 if (ret) {
243 krb5_data_free (&value);
244 krb5_storage_free(sp);
245 return ret;
247 krb5_store_int32 (sp, value.length);
248 krb5_storage_write(sp, value.data, value.length);
249 krb5_store_int32 (sp, value.length);
250 krb5_data_free (&value);
251 ret = kadm5_log_postamble (log_context, sp);
252 if (ret) {
253 krb5_storage_free (sp);
254 return ret;
256 ret = kadm5_log_flush (log_context, sp);
257 krb5_storage_free (sp);
258 if (ret)
259 return ret;
260 ret = kadm5_log_end (context);
261 return ret;
265 * Read the data of a create log record from `sp' and change the
266 * database.
269 static kadm5_ret_t
270 kadm5_log_replay_create (kadm5_server_context *context,
271 uint32_t ver,
272 uint32_t len,
273 krb5_storage *sp)
275 krb5_error_code ret;
276 krb5_data data;
277 hdb_entry_ex ent;
279 memset(&ent, 0, sizeof(ent));
281 ret = krb5_data_alloc (&data, len);
282 if (ret) {
283 krb5_set_error_string(context->context, "out of memory");
284 return ret;
286 krb5_storage_read (sp, data.data, len);
287 ret = hdb_value2entry (context->context, &data, &ent.entry);
288 krb5_data_free(&data);
289 if (ret) {
290 krb5_set_error_string(context->context,
291 "Unmarshaling hdb entry failed");
292 return ret;
294 ret = context->db->hdb_store(context->context, context->db, 0, &ent);
295 hdb_free_entry (context->context, &ent);
296 return ret;
300 * Add a `delete' operation to the log.
303 kadm5_ret_t
304 kadm5_log_delete (kadm5_server_context *context,
305 krb5_principal princ)
307 krb5_storage *sp;
308 kadm5_ret_t ret;
309 off_t off;
310 off_t len;
311 kadm5_log_context *log_context = &context->log_context;
313 sp = krb5_storage_emem();
314 if (sp == NULL)
315 return ENOMEM;
316 ret = kadm5_log_preamble (context, sp, kadm_delete);
317 if (ret)
318 goto out;
319 ret = krb5_store_int32 (sp, 0);
320 if (ret)
321 goto out;
322 off = krb5_storage_seek (sp, 0, SEEK_CUR);
323 ret = krb5_store_principal (sp, princ);
324 if (ret)
325 goto out;
326 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
327 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
328 ret = krb5_store_int32 (sp, len);
329 if (ret)
330 goto out;
331 krb5_storage_seek(sp, len, SEEK_CUR);
332 ret = krb5_store_int32 (sp, len);
333 if (ret)
334 goto out;
335 ret = kadm5_log_postamble (log_context, sp);
336 if (ret)
337 goto out;
338 ret = kadm5_log_flush (log_context, sp);
339 if (ret)
340 goto out;
341 ret = kadm5_log_end (context);
342 out:
343 krb5_storage_free (sp);
344 return ret;
348 * Read a `delete' log operation from `sp' and apply it.
351 static kadm5_ret_t
352 kadm5_log_replay_delete (kadm5_server_context *context,
353 uint32_t ver,
354 uint32_t len,
355 krb5_storage *sp)
357 krb5_error_code ret;
358 krb5_principal principal;
360 ret = krb5_ret_principal (sp, &principal);
361 if (ret) {
362 krb5_set_error_string(context->context, "Failed to read deleted "
363 "principal from log version: %ld", (long)ver);
364 return ret;
367 ret = context->db->hdb_remove(context->context, context->db, principal);
368 krb5_free_principal (context->context, principal);
369 return ret;
373 * Add a `rename' operation to the log.
376 kadm5_ret_t
377 kadm5_log_rename (kadm5_server_context *context,
378 krb5_principal source,
379 hdb_entry *ent)
381 krb5_storage *sp;
382 kadm5_ret_t ret;
383 off_t off;
384 off_t len;
385 krb5_data value;
386 kadm5_log_context *log_context = &context->log_context;
388 krb5_data_zero(&value);
390 sp = krb5_storage_emem();
391 ret = hdb_entry2value (context->context, ent, &value);
392 if (ret)
393 goto failed;
395 ret = kadm5_log_preamble (context, sp, kadm_rename);
396 if (ret)
397 goto failed;
399 ret = krb5_store_int32 (sp, 0);
400 if (ret)
401 goto failed;
402 off = krb5_storage_seek (sp, 0, SEEK_CUR);
403 ret = krb5_store_principal (sp, source);
404 if (ret)
405 goto failed;
407 krb5_storage_write(sp, value.data, value.length);
408 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
410 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
411 ret = krb5_store_int32 (sp, len);
412 if (ret)
413 goto failed;
415 krb5_storage_seek(sp, len, SEEK_CUR);
416 ret = krb5_store_int32 (sp, len);
417 if (ret)
418 goto failed;
420 ret = kadm5_log_postamble (log_context, sp);
421 if (ret)
422 goto failed;
424 ret = kadm5_log_flush (log_context, sp);
425 if (ret)
426 goto failed;
427 krb5_storage_free (sp);
428 krb5_data_free (&value);
430 return kadm5_log_end (context);
432 failed:
433 krb5_data_free(&value);
434 krb5_storage_free(sp);
435 return ret;
439 * Read a `rename' log operation from `sp' and apply it.
442 static kadm5_ret_t
443 kadm5_log_replay_rename (kadm5_server_context *context,
444 uint32_t ver,
445 uint32_t len,
446 krb5_storage *sp)
448 krb5_error_code ret;
449 krb5_principal source;
450 hdb_entry_ex target_ent;
451 krb5_data value;
452 off_t off;
453 size_t princ_len, data_len;
455 memset(&target_ent, 0, sizeof(target_ent));
457 off = krb5_storage_seek(sp, 0, SEEK_CUR);
458 ret = krb5_ret_principal (sp, &source);
459 if (ret) {
460 krb5_set_error_string(context->context, "Failed to read renamed "
461 "principal in log, version: %ld", (long)ver);
462 return ret;
464 princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
465 data_len = len - princ_len;
466 ret = krb5_data_alloc (&value, data_len);
467 if (ret) {
468 krb5_free_principal (context->context, source);
469 return ret;
471 krb5_storage_read (sp, value.data, data_len);
472 ret = hdb_value2entry (context->context, &value, &target_ent.entry);
473 krb5_data_free(&value);
474 if (ret) {
475 krb5_free_principal (context->context, source);
476 return ret;
478 ret = context->db->hdb_store (context->context, context->db,
479 0, &target_ent);
480 hdb_free_entry (context->context, &target_ent);
481 if (ret) {
482 krb5_free_principal (context->context, source);
483 return ret;
485 ret = context->db->hdb_remove (context->context, context->db, source);
486 krb5_free_principal (context->context, source);
487 return ret;
492 * Add a `modify' operation to the log.
495 kadm5_ret_t
496 kadm5_log_modify (kadm5_server_context *context,
497 hdb_entry *ent,
498 uint32_t mask)
500 krb5_storage *sp;
501 kadm5_ret_t ret;
502 krb5_data value;
503 uint32_t len;
504 kadm5_log_context *log_context = &context->log_context;
506 krb5_data_zero(&value);
508 sp = krb5_storage_emem();
509 ret = hdb_entry2value (context->context, ent, &value);
510 if (ret)
511 goto failed;
513 ret = kadm5_log_preamble (context, sp, kadm_modify);
514 if (ret)
515 goto failed;
517 len = value.length + 4;
518 ret = krb5_store_int32 (sp, len);
519 if (ret)
520 goto failed;
521 ret = krb5_store_int32 (sp, mask);
522 if (ret)
523 goto failed;
524 krb5_storage_write (sp, value.data, value.length);
526 ret = krb5_store_int32 (sp, len);
527 if (ret)
528 goto failed;
529 ret = kadm5_log_postamble (log_context, sp);
530 if (ret)
531 goto failed;
532 ret = kadm5_log_flush (log_context, sp);
533 if (ret)
534 goto failed;
535 krb5_data_free(&value);
536 krb5_storage_free (sp);
537 return kadm5_log_end (context);
538 failed:
539 krb5_data_free(&value);
540 krb5_storage_free(sp);
541 return ret;
545 * Read a `modify' log operation from `sp' and apply it.
548 static kadm5_ret_t
549 kadm5_log_replay_modify (kadm5_server_context *context,
550 uint32_t ver,
551 uint32_t len,
552 krb5_storage *sp)
554 krb5_error_code ret;
555 int32_t mask;
556 krb5_data value;
557 hdb_entry_ex ent, log_ent;
559 memset(&log_ent, 0, sizeof(log_ent));
561 krb5_ret_int32 (sp, &mask);
562 len -= 4;
563 ret = krb5_data_alloc (&value, len);
564 if (ret) {
565 krb5_set_error_string(context->context, "out of memory");
566 return ret;
568 krb5_storage_read (sp, value.data, len);
569 ret = hdb_value2entry (context->context, &value, &log_ent.entry);
570 krb5_data_free(&value);
571 if (ret)
572 return ret;
574 memset(&ent, 0, sizeof(ent));
575 ret = context->db->hdb_fetch(context->context, context->db,
576 log_ent.entry.principal,
577 HDB_F_DECRYPT|HDB_F_GET_ANY, &ent);
578 if (ret)
579 goto out;
580 if (mask & KADM5_PRINC_EXPIRE_TIME) {
581 if (log_ent.entry.valid_end == NULL) {
582 ent.entry.valid_end = NULL;
583 } else {
584 if (ent.entry.valid_end == NULL) {
585 ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
586 if (ent.entry.valid_end == NULL) {
587 krb5_set_error_string(context->context, "out of memory");
588 ret = ENOMEM;
589 goto out;
592 *ent.entry.valid_end = *log_ent.entry.valid_end;
595 if (mask & KADM5_PW_EXPIRATION) {
596 if (log_ent.entry.pw_end == NULL) {
597 ent.entry.pw_end = NULL;
598 } else {
599 if (ent.entry.pw_end == NULL) {
600 ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
601 if (ent.entry.pw_end == NULL) {
602 krb5_set_error_string(context->context, "out of memory");
603 ret = ENOMEM;
604 goto out;
607 *ent.entry.pw_end = *log_ent.entry.pw_end;
610 if (mask & KADM5_LAST_PWD_CHANGE) {
611 abort (); /* XXX */
613 if (mask & KADM5_ATTRIBUTES) {
614 ent.entry.flags = log_ent.entry.flags;
616 if (mask & KADM5_MAX_LIFE) {
617 if (log_ent.entry.max_life == NULL) {
618 ent.entry.max_life = NULL;
619 } else {
620 if (ent.entry.max_life == NULL) {
621 ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
622 if (ent.entry.max_life == NULL) {
623 krb5_set_error_string(context->context, "out of memory");
624 ret = ENOMEM;
625 goto out;
628 *ent.entry.max_life = *log_ent.entry.max_life;
631 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
632 if (ent.entry.modified_by == NULL) {
633 ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
634 if (ent.entry.modified_by == NULL) {
635 krb5_set_error_string(context->context, "out of memory");
636 ret = ENOMEM;
637 goto out;
639 } else
640 free_Event(ent.entry.modified_by);
641 ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
642 if (ret) {
643 krb5_set_error_string(context->context, "out of memory");
644 goto out;
647 if (mask & KADM5_KVNO) {
648 ent.entry.kvno = log_ent.entry.kvno;
650 if (mask & KADM5_MKVNO) {
651 abort (); /* XXX */
653 if (mask & KADM5_AUX_ATTRIBUTES) {
654 abort (); /* XXX */
656 if (mask & KADM5_POLICY) {
657 abort (); /* XXX */
659 if (mask & KADM5_POLICY_CLR) {
660 abort (); /* XXX */
662 if (mask & KADM5_MAX_RLIFE) {
663 if (log_ent.entry.max_renew == NULL) {
664 ent.entry.max_renew = NULL;
665 } else {
666 if (ent.entry.max_renew == NULL) {
667 ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
668 if (ent.entry.max_renew == NULL) {
669 krb5_set_error_string(context->context, "out of memory");
670 ret = ENOMEM;
671 goto out;
674 *ent.entry.max_renew = *log_ent.entry.max_renew;
677 if (mask & KADM5_LAST_SUCCESS) {
678 abort (); /* XXX */
680 if (mask & KADM5_LAST_FAILED) {
681 abort (); /* XXX */
683 if (mask & KADM5_FAIL_AUTH_COUNT) {
684 abort (); /* XXX */
686 if (mask & KADM5_KEY_DATA) {
687 size_t num;
688 int i;
690 for (i = 0; i < ent.entry.keys.len; ++i)
691 free_Key(&ent.entry.keys.val[i]);
692 free (ent.entry.keys.val);
694 num = log_ent.entry.keys.len;
696 ent.entry.keys.len = num;
697 ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
698 if (ent.entry.keys.val == NULL) {
699 krb5_set_error_string(context->context, "out of memory");
700 return ENOMEM;
702 for (i = 0; i < ent.entry.keys.len; ++i) {
703 ret = copy_Key(&log_ent.entry.keys.val[i],
704 &ent.entry.keys.val[i]);
705 if (ret) {
706 krb5_set_error_string(context->context, "out of memory");
707 goto out;
711 if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
712 HDB_extensions *es = ent.entry.extensions;
714 ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
715 if (ent.entry.extensions == NULL)
716 goto out;
718 ret = copy_HDB_extensions(log_ent.entry.extensions,
719 ent.entry.extensions);
720 if (ret) {
721 krb5_set_error_string(context->context, "out of memory");
722 free(ent.entry.extensions);
723 ent.entry.extensions = es;
724 goto out;
726 if (es) {
727 free_HDB_extensions(es);
728 free(es);
731 ret = context->db->hdb_store(context->context, context->db,
732 HDB_F_REPLACE, &ent);
733 out:
734 hdb_free_entry (context->context, &ent);
735 hdb_free_entry (context->context, &log_ent);
736 return ret;
740 * Add a `nop' operation to the log. Does not close the log.
743 kadm5_ret_t
744 kadm5_log_nop (kadm5_server_context *context)
746 krb5_storage *sp;
747 kadm5_ret_t ret;
748 kadm5_log_context *log_context = &context->log_context;
750 sp = krb5_storage_emem();
751 ret = kadm5_log_preamble (context, sp, kadm_nop);
752 if (ret) {
753 krb5_storage_free (sp);
754 return ret;
756 krb5_store_int32 (sp, 0);
757 krb5_store_int32 (sp, 0);
758 ret = kadm5_log_postamble (log_context, sp);
759 if (ret) {
760 krb5_storage_free (sp);
761 return ret;
763 ret = kadm5_log_flush (log_context, sp);
764 krb5_storage_free (sp);
766 return ret;
770 * Read a `nop' log operation from `sp' and apply it.
773 static kadm5_ret_t
774 kadm5_log_replay_nop (kadm5_server_context *context,
775 uint32_t ver,
776 uint32_t len,
777 krb5_storage *sp)
779 return 0;
783 * Call `func' for each log record in the log in `context'
786 kadm5_ret_t
787 kadm5_log_foreach (kadm5_server_context *context,
788 void (*func)(kadm5_server_context *server_context,
789 uint32_t ver,
790 time_t timestamp,
791 enum kadm_ops op,
792 uint32_t len,
793 krb5_storage *,
794 void *),
795 void *ctx)
797 int fd = context->log_context.log_fd;
798 krb5_storage *sp;
800 lseek (fd, 0, SEEK_SET);
801 sp = krb5_storage_from_fd (fd);
802 for (;;) {
803 int32_t ver, timestamp, op, len, len2, ver2;
805 if(krb5_ret_int32 (sp, &ver) != 0)
806 break;
807 krb5_ret_int32 (sp, &timestamp);
808 krb5_ret_int32 (sp, &op);
809 krb5_ret_int32 (sp, &len);
810 (*func)(context, ver, timestamp, op, len, sp, ctx);
811 krb5_ret_int32 (sp, &len2);
812 krb5_ret_int32 (sp, &ver2);
813 if (len != len2)
814 abort();
815 if (ver != ver2)
816 abort();
818 krb5_storage_free(sp);
819 return 0;
823 * Go to end of log.
826 krb5_storage *
827 kadm5_log_goto_end (int fd)
829 krb5_storage *sp;
831 sp = krb5_storage_from_fd (fd);
832 krb5_storage_seek(sp, 0, SEEK_END);
833 return sp;
837 * Return previous log entry.
839 * The pointer in `sp´ is assumed to be at the top of the entry before
840 * previous entry. On success, the `sp´ pointer is set to data portion
841 * of previous entry. In case of error, it's not changed at all.
844 kadm5_ret_t
845 kadm5_log_previous (krb5_context context,
846 krb5_storage *sp,
847 uint32_t *ver,
848 time_t *timestamp,
849 enum kadm_ops *op,
850 uint32_t *len)
852 krb5_error_code ret;
853 off_t off, oldoff;
854 int32_t tmp;
856 oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
858 krb5_storage_seek(sp, -8, SEEK_CUR);
859 ret = krb5_ret_int32 (sp, &tmp);
860 if (ret)
861 goto end_of_storage;
862 *len = tmp;
863 ret = krb5_ret_int32 (sp, &tmp);
864 *ver = tmp;
865 off = 24 + *len;
866 krb5_storage_seek(sp, -off, SEEK_CUR);
867 ret = krb5_ret_int32 (sp, &tmp);
868 if (ret)
869 goto end_of_storage;
870 if (tmp != *ver) {
871 krb5_storage_seek(sp, oldoff, SEEK_SET);
872 krb5_set_error_string(context, "kadm5_log_previous: log entry "
873 "have consistency failure, version number wrong");
874 return KADM5_BAD_DB;
876 ret = krb5_ret_int32 (sp, &tmp);
877 if (ret)
878 goto end_of_storage;
879 *timestamp = tmp;
880 ret = krb5_ret_int32 (sp, &tmp);
881 *op = tmp;
882 ret = krb5_ret_int32 (sp, &tmp);
883 if (ret)
884 goto end_of_storage;
885 if (tmp != *len) {
886 krb5_storage_seek(sp, oldoff, SEEK_SET);
887 krb5_set_error_string(context, "kadm5_log_previous: log entry "
888 "have consistency failure, length wrong");
889 return KADM5_BAD_DB;
891 return 0;
893 end_of_storage:
894 krb5_storage_seek(sp, oldoff, SEEK_SET);
895 krb5_set_error_string(context, "kadm5_log_previous: end of storage "
896 "reached before end");
897 return ret;
901 * Replay a record from the log
904 kadm5_ret_t
905 kadm5_log_replay (kadm5_server_context *context,
906 enum kadm_ops op,
907 uint32_t ver,
908 uint32_t len,
909 krb5_storage *sp)
911 switch (op) {
912 case kadm_create :
913 return kadm5_log_replay_create (context, ver, len, sp);
914 case kadm_delete :
915 return kadm5_log_replay_delete (context, ver, len, sp);
916 case kadm_rename :
917 return kadm5_log_replay_rename (context, ver, len, sp);
918 case kadm_modify :
919 return kadm5_log_replay_modify (context, ver, len, sp);
920 case kadm_nop :
921 return kadm5_log_replay_nop (context, ver, len, sp);
922 default :
923 krb5_set_error_string(context->context,
924 "Unsupported replay op %d", (int)op);
925 return KADM5_FAILURE;
930 * truncate the log - i.e. create an empty file with just (nop vno + 2)
933 kadm5_ret_t
934 kadm5_log_truncate (kadm5_server_context *server_context)
936 kadm5_ret_t ret;
937 uint32_t vno;
939 ret = kadm5_log_init (server_context);
940 if (ret)
941 return ret;
943 ret = kadm5_log_get_version (server_context, &vno);
944 if (ret)
945 return ret;
947 ret = kadm5_log_reinit (server_context);
948 if (ret)
949 return ret;
951 ret = kadm5_log_set_version (server_context, vno);
952 if (ret)
953 return ret;
955 ret = kadm5_log_nop (server_context);
956 if (ret)
957 return ret;
959 ret = kadm5_log_end (server_context);
960 if (ret)
961 return ret;
962 return 0;
966 static char *default_signal = NULL;
967 static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
969 const char *
970 kadm5_log_signal_socket(krb5_context context)
972 HEIMDAL_MUTEX_lock(&signal_mutex);
973 if (!default_signal)
974 asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
975 HEIMDAL_MUTEX_unlock(&signal_mutex);
977 return krb5_config_get_string_default(context,
978 NULL,
979 default_signal,
980 "kdc",
981 "signal_socket",
982 NULL);