Rename context handle lifetime to endtime
[heimdal.git] / lib / kadm5 / log.c
blobe31a30e436d39d17a646e3a045ee325336174837
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 int ret;
128 kadm5_log_context *log_context = &context->log_context;
130 if (log_context->log_fd != -1) {
131 flock (log_context->log_fd, LOCK_UN);
132 close (log_context->log_fd);
133 log_context->log_fd = -1;
135 fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
136 if (fd < 0)
137 return errno;
138 if (flock (fd, LOCK_EX) < 0) {
139 ret = errno;
140 close (fd);
141 return ret;
143 if (ftruncate(fd, 0) < 0) {
144 ret = errno;
145 close(fd);
146 return ret;
149 log_context->version = 0;
150 log_context->log_fd = fd;
151 return 0;
155 kadm5_ret_t
156 kadm5_log_end (kadm5_server_context *context)
158 kadm5_log_context *log_context = &context->log_context;
159 int fd = log_context->log_fd;
161 flock (fd, LOCK_UN);
162 close(fd);
163 log_context->log_fd = -1;
164 return 0;
167 static kadm5_ret_t
168 kadm5_log_preamble (kadm5_server_context *context,
169 krb5_storage *sp,
170 enum kadm_ops op)
172 kadm5_log_context *log_context = &context->log_context;
173 kadm5_ret_t kadm_ret;
175 kadm_ret = kadm5_log_init (context);
176 if (kadm_ret)
177 return kadm_ret;
179 krb5_store_int32 (sp, ++log_context->version);
180 krb5_store_int32 (sp, time(NULL));
181 krb5_store_int32 (sp, op);
182 return 0;
185 static kadm5_ret_t
186 kadm5_log_postamble (kadm5_log_context *context,
187 krb5_storage *sp)
189 krb5_store_int32 (sp, context->version);
190 return 0;
194 * flush the log record in `sp'.
197 static kadm5_ret_t
198 kadm5_log_flush (kadm5_log_context *log_context,
199 krb5_storage *sp)
201 krb5_data data;
202 size_t len;
203 ssize_t ret;
205 krb5_storage_to_data(sp, &data);
206 len = data.length;
207 ret = write (log_context->log_fd, data.data, len);
208 if (ret < 0 || (size_t)ret != len) {
209 krb5_data_free(&data);
210 return errno;
212 if (fsync (log_context->log_fd) < 0) {
213 krb5_data_free(&data);
214 return errno;
218 * Try to send a signal to any running `ipropd-master'
220 #ifndef NO_UNIX_SOCKETS
221 sendto (log_context->socket_fd,
222 (void *)&log_context->version,
223 sizeof(log_context->version),
225 (struct sockaddr *)&log_context->socket_name,
226 sizeof(log_context->socket_name));
227 #else
228 sendto (log_context->socket_fd,
229 (void *)&log_context->version,
230 sizeof(log_context->version),
232 log_context->socket_info->ai_addr,
233 log_context->socket_info->ai_addrlen);
234 #endif
236 krb5_data_free(&data);
237 return 0;
241 * Add a `create' operation to the log.
244 kadm5_ret_t
245 kadm5_log_create (kadm5_server_context *context,
246 hdb_entry *ent)
248 krb5_storage *sp;
249 kadm5_ret_t ret;
250 krb5_data value;
251 kadm5_log_context *log_context = &context->log_context;
253 sp = krb5_storage_emem();
254 ret = hdb_entry2value (context->context, ent, &value);
255 if (ret) {
256 krb5_storage_free(sp);
257 return ret;
259 ret = kadm5_log_preamble (context, sp, kadm_create);
260 if (ret) {
261 krb5_data_free (&value);
262 krb5_storage_free(sp);
263 return ret;
265 krb5_store_int32 (sp, value.length);
266 krb5_storage_write(sp, value.data, value.length);
267 krb5_store_int32 (sp, value.length);
268 krb5_data_free (&value);
269 ret = kadm5_log_postamble (log_context, sp);
270 if (ret) {
271 krb5_storage_free (sp);
272 return ret;
274 ret = kadm5_log_flush (log_context, sp);
275 krb5_storage_free (sp);
276 if (ret)
277 return ret;
278 ret = kadm5_log_end (context);
279 return ret;
283 * Read the data of a create log record from `sp' and change the
284 * database.
287 static kadm5_ret_t
288 kadm5_log_replay_create (kadm5_server_context *context,
289 uint32_t ver,
290 uint32_t len,
291 krb5_storage *sp)
293 krb5_error_code ret;
294 krb5_data data;
295 hdb_entry_ex ent;
297 memset(&ent, 0, sizeof(ent));
299 ret = krb5_data_alloc (&data, len);
300 if (ret) {
301 krb5_set_error_message(context->context, ret, "out of memory");
302 return ret;
304 krb5_storage_read (sp, data.data, len);
305 ret = hdb_value2entry (context->context, &data, &ent.entry);
306 krb5_data_free(&data);
307 if (ret) {
308 krb5_set_error_message(context->context, ret,
309 "Unmarshaling hdb entry failed");
310 return ret;
312 ret = context->db->hdb_store(context->context, context->db, 0, &ent);
313 hdb_free_entry (context->context, &ent);
314 return ret;
318 * Add a `delete' operation to the log.
321 kadm5_ret_t
322 kadm5_log_delete (kadm5_server_context *context,
323 krb5_principal princ)
325 krb5_storage *sp;
326 kadm5_ret_t ret;
327 off_t off;
328 off_t len;
329 kadm5_log_context *log_context = &context->log_context;
331 sp = krb5_storage_emem();
332 if (sp == NULL)
333 return ENOMEM;
334 ret = kadm5_log_preamble (context, sp, kadm_delete);
335 if (ret)
336 goto out;
337 ret = krb5_store_int32 (sp, 0);
338 if (ret)
339 goto out;
340 off = krb5_storage_seek (sp, 0, SEEK_CUR);
341 ret = krb5_store_principal (sp, princ);
342 if (ret)
343 goto out;
344 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
345 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
346 ret = krb5_store_int32 (sp, len);
347 if (ret)
348 goto out;
349 krb5_storage_seek(sp, len, SEEK_CUR);
350 ret = krb5_store_int32 (sp, len);
351 if (ret)
352 goto out;
353 ret = kadm5_log_postamble (log_context, sp);
354 if (ret)
355 goto out;
356 ret = kadm5_log_flush (log_context, sp);
357 if (ret)
358 goto out;
359 ret = kadm5_log_end (context);
360 out:
361 krb5_storage_free (sp);
362 return ret;
366 * Read a `delete' log operation from `sp' and apply it.
369 static kadm5_ret_t
370 kadm5_log_replay_delete (kadm5_server_context *context,
371 uint32_t ver,
372 uint32_t len,
373 krb5_storage *sp)
375 krb5_error_code ret;
376 krb5_principal principal;
378 ret = krb5_ret_principal (sp, &principal);
379 if (ret) {
380 krb5_set_error_message(context->context, ret, "Failed to read deleted "
381 "principal from log version: %ld", (long)ver);
382 return ret;
385 ret = context->db->hdb_remove(context->context, context->db, principal);
386 krb5_free_principal (context->context, principal);
387 return ret;
391 * Add a `rename' operation to the log.
394 kadm5_ret_t
395 kadm5_log_rename (kadm5_server_context *context,
396 krb5_principal source,
397 hdb_entry *ent)
399 krb5_storage *sp;
400 kadm5_ret_t ret;
401 off_t off;
402 off_t len;
403 krb5_data value;
404 kadm5_log_context *log_context = &context->log_context;
406 krb5_data_zero(&value);
408 sp = krb5_storage_emem();
409 ret = hdb_entry2value (context->context, ent, &value);
410 if (ret)
411 goto failed;
413 ret = kadm5_log_preamble (context, sp, kadm_rename);
414 if (ret)
415 goto failed;
417 ret = krb5_store_int32 (sp, 0);
418 if (ret)
419 goto failed;
420 off = krb5_storage_seek (sp, 0, SEEK_CUR);
421 ret = krb5_store_principal (sp, source);
422 if (ret)
423 goto failed;
425 krb5_storage_write(sp, value.data, value.length);
426 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
428 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
429 ret = krb5_store_int32 (sp, len);
430 if (ret)
431 goto failed;
433 krb5_storage_seek(sp, len, SEEK_CUR);
434 ret = krb5_store_int32 (sp, len);
435 if (ret)
436 goto failed;
438 ret = kadm5_log_postamble (log_context, sp);
439 if (ret)
440 goto failed;
442 ret = kadm5_log_flush (log_context, sp);
443 if (ret)
444 goto failed;
445 krb5_storage_free (sp);
446 krb5_data_free (&value);
448 return kadm5_log_end (context);
450 failed:
451 krb5_data_free(&value);
452 krb5_storage_free(sp);
453 return ret;
457 * Read a `rename' log operation from `sp' and apply it.
460 static kadm5_ret_t
461 kadm5_log_replay_rename (kadm5_server_context *context,
462 uint32_t ver,
463 uint32_t len,
464 krb5_storage *sp)
466 krb5_error_code ret;
467 krb5_principal source;
468 hdb_entry_ex target_ent;
469 krb5_data value;
470 off_t off;
471 size_t princ_len, data_len;
473 memset(&target_ent, 0, sizeof(target_ent));
475 off = krb5_storage_seek(sp, 0, SEEK_CUR);
476 ret = krb5_ret_principal (sp, &source);
477 if (ret) {
478 krb5_set_error_message(context->context, ret, "Failed to read renamed "
479 "principal in log, version: %ld", (long)ver);
480 return ret;
482 princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
483 data_len = len - princ_len;
484 ret = krb5_data_alloc (&value, data_len);
485 if (ret) {
486 krb5_free_principal (context->context, source);
487 return ret;
489 krb5_storage_read (sp, value.data, data_len);
490 ret = hdb_value2entry (context->context, &value, &target_ent.entry);
491 krb5_data_free(&value);
492 if (ret) {
493 krb5_free_principal (context->context, source);
494 return ret;
496 ret = context->db->hdb_store (context->context, context->db,
497 0, &target_ent);
498 hdb_free_entry (context->context, &target_ent);
499 if (ret) {
500 krb5_free_principal (context->context, source);
501 return ret;
503 ret = context->db->hdb_remove (context->context, context->db, source);
504 krb5_free_principal (context->context, source);
505 return ret;
510 * Add a `modify' operation to the log.
513 kadm5_ret_t
514 kadm5_log_modify (kadm5_server_context *context,
515 hdb_entry *ent,
516 uint32_t mask)
518 krb5_storage *sp;
519 kadm5_ret_t ret;
520 krb5_data value;
521 uint32_t len;
522 kadm5_log_context *log_context = &context->log_context;
524 krb5_data_zero(&value);
526 sp = krb5_storage_emem();
527 ret = hdb_entry2value (context->context, ent, &value);
528 if (ret)
529 goto failed;
531 ret = kadm5_log_preamble (context, sp, kadm_modify);
532 if (ret)
533 goto failed;
535 len = value.length + 4;
536 ret = krb5_store_int32 (sp, len);
537 if (ret)
538 goto failed;
539 ret = krb5_store_int32 (sp, mask);
540 if (ret)
541 goto failed;
542 krb5_storage_write (sp, value.data, value.length);
544 ret = krb5_store_int32 (sp, len);
545 if (ret)
546 goto failed;
547 ret = kadm5_log_postamble (log_context, sp);
548 if (ret)
549 goto failed;
550 ret = kadm5_log_flush (log_context, sp);
551 if (ret)
552 goto failed;
553 krb5_data_free(&value);
554 krb5_storage_free (sp);
555 return kadm5_log_end (context);
556 failed:
557 krb5_data_free(&value);
558 krb5_storage_free(sp);
559 return ret;
563 * Read a `modify' log operation from `sp' and apply it.
566 static kadm5_ret_t
567 kadm5_log_replay_modify (kadm5_server_context *context,
568 uint32_t ver,
569 uint32_t len,
570 krb5_storage *sp)
572 krb5_error_code ret;
573 int32_t mask;
574 krb5_data value;
575 hdb_entry_ex ent, log_ent;
577 memset(&log_ent, 0, sizeof(log_ent));
579 krb5_ret_int32 (sp, &mask);
580 len -= 4;
581 ret = krb5_data_alloc (&value, len);
582 if (ret) {
583 krb5_set_error_message(context->context, ret, "out of memory");
584 return ret;
586 krb5_storage_read (sp, value.data, len);
587 ret = hdb_value2entry (context->context, &value, &log_ent.entry);
588 krb5_data_free(&value);
589 if (ret)
590 return ret;
592 memset(&ent, 0, sizeof(ent));
593 ret = context->db->hdb_fetch_kvno(context->context, context->db,
594 log_ent.entry.principal,
595 HDB_F_DECRYPT|HDB_F_ALL_KVNOS|
596 HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
597 if (ret)
598 goto out;
599 if (mask & KADM5_PRINC_EXPIRE_TIME) {
600 if (log_ent.entry.valid_end == NULL) {
601 ent.entry.valid_end = NULL;
602 } else {
603 if (ent.entry.valid_end == NULL) {
604 ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
605 if (ent.entry.valid_end == NULL) {
606 ret = ENOMEM;
607 krb5_set_error_message(context->context, ret, "out of memory");
608 goto out;
611 *ent.entry.valid_end = *log_ent.entry.valid_end;
614 if (mask & KADM5_PW_EXPIRATION) {
615 if (log_ent.entry.pw_end == NULL) {
616 ent.entry.pw_end = NULL;
617 } else {
618 if (ent.entry.pw_end == NULL) {
619 ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
620 if (ent.entry.pw_end == NULL) {
621 ret = ENOMEM;
622 krb5_set_error_message(context->context, ret, "out of memory");
623 goto out;
626 *ent.entry.pw_end = *log_ent.entry.pw_end;
629 if (mask & KADM5_LAST_PWD_CHANGE) {
630 krb5_warnx (context->context, "Unimplemented mask KADM5_LAST_PWD_CHANGE");
632 if (mask & KADM5_ATTRIBUTES) {
633 ent.entry.flags = log_ent.entry.flags;
635 if (mask & KADM5_MAX_LIFE) {
636 if (log_ent.entry.max_life == NULL) {
637 ent.entry.max_life = NULL;
638 } else {
639 if (ent.entry.max_life == NULL) {
640 ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
641 if (ent.entry.max_life == NULL) {
642 ret = ENOMEM;
643 krb5_set_error_message(context->context, ret, "out of memory");
644 goto out;
647 *ent.entry.max_life = *log_ent.entry.max_life;
650 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
651 if (ent.entry.modified_by == NULL) {
652 ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
653 if (ent.entry.modified_by == NULL) {
654 ret = ENOMEM;
655 krb5_set_error_message(context->context, ret, "out of memory");
656 goto out;
658 } else
659 free_Event(ent.entry.modified_by);
660 ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
661 if (ret) {
662 krb5_set_error_message(context->context, ret, "out of memory");
663 goto out;
666 if (mask & KADM5_KVNO) {
667 ent.entry.kvno = log_ent.entry.kvno;
669 if (mask & KADM5_MKVNO) {
670 krb5_warnx (context->context, "Unimplemented mask KADM5_KVNO");
672 if (mask & KADM5_AUX_ATTRIBUTES) {
673 krb5_warnx (context->context, "Unimplemented mask KADM5_AUX_ATTRIBUTES");
675 if (mask & KADM5_POLICY_CLR) {
676 krb5_warnx (context->context, "Unimplemented mask KADM5_POLICY_CLR");
678 if (mask & KADM5_MAX_RLIFE) {
679 if (log_ent.entry.max_renew == NULL) {
680 ent.entry.max_renew = NULL;
681 } else {
682 if (ent.entry.max_renew == NULL) {
683 ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
684 if (ent.entry.max_renew == NULL) {
685 ret = ENOMEM;
686 krb5_set_error_message(context->context, ret, "out of memory");
687 goto out;
690 *ent.entry.max_renew = *log_ent.entry.max_renew;
693 if (mask & KADM5_LAST_SUCCESS) {
694 krb5_warnx (context->context, "Unimplemented mask KADM5_LAST_SUCCESS");
696 if (mask & KADM5_LAST_FAILED) {
697 krb5_warnx (context->context, "Unimplemented mask KADM5_LAST_FAILED");
699 if (mask & KADM5_FAIL_AUTH_COUNT) {
700 krb5_warnx (context->context, "Unimplemented mask KADM5_FAIL_AUTH_COUNT");
702 if (mask & KADM5_KEY_DATA) {
703 size_t num;
704 size_t i;
707 * We don't need to do anything about key history here because
708 * the log entry contains a complete entry, including hdb
709 * extensions. We do need to make sure that KADM5_TL_DATA is in
710 * the mask though, since that's what it takes to update the
711 * extensions (see below).
713 mask |= KADM5_TL_DATA;
715 for (i = 0; i < ent.entry.keys.len; ++i)
716 free_Key(&ent.entry.keys.val[i]);
717 free (ent.entry.keys.val);
719 num = log_ent.entry.keys.len;
721 ent.entry.keys.len = num;
722 ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
723 if (ent.entry.keys.val == NULL) {
724 krb5_set_error_message(context->context, ENOMEM, "out of memory");
725 return ENOMEM;
727 for (i = 0; i < ent.entry.keys.len; ++i) {
728 ret = copy_Key(&log_ent.entry.keys.val[i],
729 &ent.entry.keys.val[i]);
730 if (ret) {
731 krb5_set_error_message(context->context, ret, "out of memory");
732 goto out;
736 if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
737 HDB_extensions *es = ent.entry.extensions;
739 ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
740 if (ent.entry.extensions == NULL)
741 goto out;
743 ret = copy_HDB_extensions(log_ent.entry.extensions,
744 ent.entry.extensions);
745 if (ret) {
746 krb5_set_error_message(context->context, ret, "out of memory");
747 free(ent.entry.extensions);
748 ent.entry.extensions = es;
749 goto out;
751 if (es) {
752 free_HDB_extensions(es);
753 free(es);
756 ret = context->db->hdb_store(context->context, context->db,
757 HDB_F_REPLACE, &ent);
758 out:
759 hdb_free_entry (context->context, &ent);
760 hdb_free_entry (context->context, &log_ent);
761 return ret;
765 * Add a `nop' operation to the log. Does not close the log.
768 kadm5_ret_t
769 kadm5_log_nop (kadm5_server_context *context)
771 krb5_storage *sp;
772 kadm5_ret_t ret;
773 kadm5_log_context *log_context = &context->log_context;
775 sp = krb5_storage_emem();
776 ret = kadm5_log_preamble (context, sp, kadm_nop);
777 if (ret) {
778 krb5_storage_free (sp);
779 return ret;
781 krb5_store_int32 (sp, 0);
782 krb5_store_int32 (sp, 0);
783 ret = kadm5_log_postamble (log_context, sp);
784 if (ret) {
785 krb5_storage_free (sp);
786 return ret;
788 ret = kadm5_log_flush (log_context, sp);
789 krb5_storage_free (sp);
791 return ret;
795 * Read a `nop' log operation from `sp' and apply it.
798 static kadm5_ret_t
799 kadm5_log_replay_nop (kadm5_server_context *context,
800 uint32_t ver,
801 uint32_t len,
802 krb5_storage *sp)
804 return 0;
808 * Call `func' for each log record in the log in `context'
811 kadm5_ret_t
812 kadm5_log_foreach (kadm5_server_context *context,
813 void (*func)(kadm5_server_context *server_context,
814 uint32_t ver,
815 time_t timestamp,
816 enum kadm_ops op,
817 uint32_t len,
818 krb5_storage *,
819 void *),
820 void *ctx)
822 int fd = context->log_context.log_fd;
823 krb5_storage *sp;
825 lseek (fd, 0, SEEK_SET);
826 sp = krb5_storage_from_fd (fd);
827 for (;;) {
828 int32_t ver, timestamp, op, len, len2, ver2;
830 if(krb5_ret_int32 (sp, &ver) != 0)
831 break;
832 krb5_ret_int32 (sp, &timestamp);
833 krb5_ret_int32 (sp, &op);
834 krb5_ret_int32 (sp, &len);
835 (*func)(context, ver, timestamp, op, len, sp, ctx);
836 krb5_ret_int32 (sp, &len2);
837 krb5_ret_int32 (sp, &ver2);
838 if (len != len2)
839 abort();
840 if (ver != ver2)
841 abort();
843 krb5_storage_free(sp);
844 return 0;
848 * Go to end of log.
851 krb5_storage *
852 kadm5_log_goto_end (int fd)
854 krb5_storage *sp;
856 sp = krb5_storage_from_fd (fd);
857 krb5_storage_seek(sp, 0, SEEK_END);
858 return sp;
862 * Return previous log entry.
864 * The pointer in `sp´ is assumed to be at the top of the entry before
865 * previous entry. On success, the `sp´ pointer is set to data portion
866 * of previous entry. In case of error, it's not changed at all.
869 kadm5_ret_t
870 kadm5_log_previous (krb5_context context,
871 krb5_storage *sp,
872 uint32_t *ver,
873 time_t *timestamp,
874 enum kadm_ops *op,
875 uint32_t *len)
877 krb5_error_code ret;
878 off_t off, oldoff;
879 int32_t tmp;
881 oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
883 krb5_storage_seek(sp, -8, SEEK_CUR);
884 ret = krb5_ret_int32 (sp, &tmp);
885 if (ret)
886 goto end_of_storage;
887 *len = tmp;
888 ret = krb5_ret_int32 (sp, &tmp);
889 if (ret)
890 goto end_of_storage;
891 *ver = tmp;
892 off = 24 + *len;
893 krb5_storage_seek(sp, -off, SEEK_CUR);
894 ret = krb5_ret_int32 (sp, &tmp);
895 if (ret)
896 goto end_of_storage;
897 if ((uint32_t)tmp != *ver) {
898 krb5_storage_seek(sp, oldoff, SEEK_SET);
899 krb5_set_error_message(context, KADM5_BAD_DB,
900 "kadm5_log_previous: log entry "
901 "have consistency failure, version number wrong "
902 "(tmp %lu ver %lu)",
903 (unsigned long)tmp,
904 (unsigned long)*ver);
905 return KADM5_BAD_DB;
907 ret = krb5_ret_int32 (sp, &tmp);
908 if (ret)
909 goto end_of_storage;
910 *timestamp = tmp;
911 ret = krb5_ret_int32 (sp, &tmp);
912 if (ret)
913 goto end_of_storage;
914 *op = tmp;
915 ret = krb5_ret_int32 (sp, &tmp);
916 if (ret)
917 goto end_of_storage;
918 if ((uint32_t)tmp != *len) {
919 krb5_storage_seek(sp, oldoff, SEEK_SET);
920 krb5_set_error_message(context, KADM5_BAD_DB,
921 "kadm5_log_previous: log entry "
922 "have consistency failure, length wrong");
923 return KADM5_BAD_DB;
925 return 0;
927 end_of_storage:
928 krb5_storage_seek(sp, oldoff, SEEK_SET);
929 krb5_set_error_message(context, ret, "kadm5_log_previous: end of storage "
930 "reached before end");
931 return ret;
935 * Replay a record from the log
938 kadm5_ret_t
939 kadm5_log_replay (kadm5_server_context *context,
940 enum kadm_ops op,
941 uint32_t ver,
942 uint32_t len,
943 krb5_storage *sp)
945 switch (op) {
946 case kadm_create :
947 return kadm5_log_replay_create (context, ver, len, sp);
948 case kadm_delete :
949 return kadm5_log_replay_delete (context, ver, len, sp);
950 case kadm_rename :
951 return kadm5_log_replay_rename (context, ver, len, sp);
952 case kadm_modify :
953 return kadm5_log_replay_modify (context, ver, len, sp);
954 case kadm_nop :
955 return kadm5_log_replay_nop (context, ver, len, sp);
956 default :
957 krb5_set_error_message(context->context, KADM5_FAILURE,
958 "Unsupported replay op %d", (int)op);
959 return KADM5_FAILURE;
964 * truncate the log - i.e. create an empty file with just (nop vno + 2)
967 kadm5_ret_t
968 kadm5_log_truncate (kadm5_server_context *server_context)
970 kadm5_ret_t ret;
971 uint32_t vno;
973 ret = kadm5_log_init (server_context);
974 if (ret)
975 return ret;
977 ret = kadm5_log_get_version (server_context, &vno);
978 if (ret)
979 return ret;
981 ret = kadm5_log_reinit (server_context);
982 if (ret)
983 return ret;
985 ret = kadm5_log_set_version (server_context, vno);
986 if (ret)
987 return ret;
989 ret = kadm5_log_nop (server_context);
990 if (ret)
991 return ret;
993 ret = kadm5_log_end (server_context);
994 if (ret)
995 return ret;
996 return 0;
1000 #ifndef NO_UNIX_SOCKETS
1002 static char *default_signal = NULL;
1003 static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
1005 const char *
1006 kadm5_log_signal_socket(krb5_context context)
1008 int ret = 0;
1010 HEIMDAL_MUTEX_lock(&signal_mutex);
1011 if (!default_signal)
1012 ret = asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
1013 if (ret == -1)
1014 default_signal = NULL;
1015 HEIMDAL_MUTEX_unlock(&signal_mutex);
1017 return krb5_config_get_string_default(context,
1018 NULL,
1019 default_signal,
1020 "kdc",
1021 "signal_socket",
1022 NULL);
1025 #else /* NO_UNIX_SOCKETS */
1027 #define SIGNAL_SOCKET_HOST "127.0.0.1"
1028 #define SIGNAL_SOCKET_PORT "12701"
1030 kadm5_ret_t
1031 kadm5_log_signal_socket_info(krb5_context context,
1032 int server_end,
1033 struct addrinfo **ret_addrs)
1035 struct addrinfo hints;
1036 struct addrinfo *addrs = NULL;
1037 kadm5_ret_t ret = KADM5_FAILURE;
1038 int wsret;
1040 memset(&hints, 0, sizeof(hints));
1042 hints.ai_flags = AI_NUMERICHOST;
1043 if (server_end)
1044 hints.ai_flags |= AI_PASSIVE;
1045 hints.ai_family = AF_INET;
1046 hints.ai_socktype = SOCK_STREAM;
1047 hints.ai_protocol = IPPROTO_TCP;
1049 wsret = getaddrinfo(SIGNAL_SOCKET_HOST,
1050 SIGNAL_SOCKET_PORT,
1051 &hints, &addrs);
1053 if (wsret != 0) {
1054 krb5_set_error_message(context, KADM5_FAILURE,
1055 "%s", gai_strerror(wsret));
1056 goto done;
1059 if (addrs == NULL) {
1060 krb5_set_error_message(context, KADM5_FAILURE,
1061 "getaddrinfo() failed to return address list");
1062 goto done;
1065 *ret_addrs = addrs;
1066 addrs = NULL;
1067 ret = 0;
1069 done:
1070 if (addrs)
1071 freeaddrinfo(addrs);
1072 return ret;
1075 #endif