1 /* $NetBSD: log.c,v 1.1.1.2 2014/04/24 12:45:49 pettai Exp $ */
2
3 /*
4 * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "kadm5_locl.h"
37 #include "heim_threads.h"
38
39 __RCSID("NetBSD");
40
41 /*
42 * A log record consists of:
43 *
44 * version number 4 bytes
45 * time in seconds 4 bytes
46 * operation (enum kadm_ops) 4 bytes
47 * length of record 4 bytes
48 * data... n bytes
49 * length of record 4 bytes
50 * version number 4 bytes
51 *
52 */
53
54 kadm5_ret_t
kadm5_log_get_version_fd(int fd,uint32_t * ver)55 kadm5_log_get_version_fd (int fd,
56 uint32_t *ver)
57 {
58 int ret;
59 krb5_storage *sp;
60 int32_t old_version;
61
62 ret = lseek (fd, 0, SEEK_END);
63 if(ret < 0)
64 return errno;
65 if(ret == 0) {
66 *ver = 0;
67 return 0;
68 }
69 sp = krb5_storage_from_fd (fd);
70 krb5_storage_seek(sp, -4, SEEK_CUR);
71 krb5_ret_int32 (sp, &old_version);
72 *ver = old_version;
73 krb5_storage_free(sp);
74 lseek (fd, 0, SEEK_END);
75 return 0;
76 }
77
78 kadm5_ret_t
kadm5_log_get_version(kadm5_server_context * context,uint32_t * ver)79 kadm5_log_get_version (kadm5_server_context *context, uint32_t *ver)
80 {
81 return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
82 }
83
84 kadm5_ret_t
kadm5_log_set_version(kadm5_server_context * context,uint32_t vno)85 kadm5_log_set_version (kadm5_server_context *context, uint32_t vno)
86 {
87 kadm5_log_context *log_context = &context->log_context;
88
89 log_context->version = vno;
90 return 0;
91 }
92
93 kadm5_ret_t
kadm5_log_init(kadm5_server_context * context)94 kadm5_log_init (kadm5_server_context *context)
95 {
96 int fd;
97 kadm5_ret_t ret;
98 kadm5_log_context *log_context = &context->log_context;
99
100 if (log_context->log_fd != -1)
101 return 0;
102 fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
103 if (fd < 0) {
104 ret = errno;
105 krb5_set_error_message(context->context, ret, "kadm5_log_init: open %s",
106 log_context->log_file);
107 return ret;
108 }
109 if (flock (fd, LOCK_EX) < 0) {
110 ret = errno;
111 krb5_set_error_message(context->context, ret, "kadm5_log_init: flock %s",
112 log_context->log_file);
113 close (fd);
114 return errno;
115 }
116
117 ret = kadm5_log_get_version_fd (fd, &log_context->version);
118 if (ret)
119 return ret;
120
121 log_context->log_fd = fd;
122 return 0;
123 }
124
125 kadm5_ret_t
kadm5_log_reinit(kadm5_server_context * context)126 kadm5_log_reinit (kadm5_server_context *context)
127 {
128 int fd;
129 kadm5_log_context *log_context = &context->log_context;
130
131 if (log_context->log_fd != -1) {
132 flock (log_context->log_fd, LOCK_UN);
133 close (log_context->log_fd);
134 log_context->log_fd = -1;
135 }
136 fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
137 if (fd < 0)
138 return errno;
139 if (flock (fd, LOCK_EX) < 0) {
140 close (fd);
141 return errno;
142 }
143
144 log_context->version = 0;
145 log_context->log_fd = fd;
146 return 0;
147 }
148
149
150 kadm5_ret_t
kadm5_log_end(kadm5_server_context * context)151 kadm5_log_end (kadm5_server_context *context)
152 {
153 kadm5_log_context *log_context = &context->log_context;
154 int fd = log_context->log_fd;
155
156 flock (fd, LOCK_UN);
157 close(fd);
158 log_context->log_fd = -1;
159 return 0;
160 }
161
162 static kadm5_ret_t
kadm5_log_preamble(kadm5_server_context * context,krb5_storage * sp,enum kadm_ops op)163 kadm5_log_preamble (kadm5_server_context *context,
164 krb5_storage *sp,
165 enum kadm_ops op)
166 {
167 kadm5_log_context *log_context = &context->log_context;
168 kadm5_ret_t kadm_ret;
169
170 kadm_ret = kadm5_log_init (context);
171 if (kadm_ret)
172 return kadm_ret;
173
174 krb5_store_int32 (sp, ++log_context->version);
175 krb5_store_int32 (sp, time(NULL));
176 krb5_store_int32 (sp, op);
177 return 0;
178 }
179
180 static kadm5_ret_t
kadm5_log_postamble(kadm5_log_context * context,krb5_storage * sp)181 kadm5_log_postamble (kadm5_log_context *context,
182 krb5_storage *sp)
183 {
184 krb5_store_int32 (sp, context->version);
185 return 0;
186 }
187
188 /*
189 * flush the log record in `sp'.
190 */
191
192 static kadm5_ret_t
kadm5_log_flush(kadm5_log_context * log_context,krb5_storage * sp)193 kadm5_log_flush (kadm5_log_context *log_context,
194 krb5_storage *sp)
195 {
196 krb5_data data;
197 size_t len;
198 ssize_t ret;
199
200 krb5_storage_to_data(sp, &data);
201 len = data.length;
202 ret = write (log_context->log_fd, data.data, len);
203 if (ret < 0 || (size_t)ret != len) {
204 krb5_data_free(&data);
205 return errno;
206 }
207 if (fsync (log_context->log_fd) < 0) {
208 krb5_data_free(&data);
209 return errno;
210 }
211
212 /*
213 * Try to send a signal to any running `ipropd-master'
214 */
215 #ifndef NO_UNIX_SOCKETS
216 sendto (log_context->socket_fd,
217 (void *)&log_context->version,
218 sizeof(log_context->version),
219 0,
220 (struct sockaddr *)&log_context->socket_name,
221 sizeof(log_context->socket_name));
222 #else
223 sendto (log_context->socket_fd,
224 (void *)&log_context->version,
225 sizeof(log_context->version),
226 0,
227 log_context->socket_info->ai_addr,
228 log_context->socket_info->ai_addrlen);
229 #endif
230
231 krb5_data_free(&data);
232 return 0;
233 }
234
235 /*
236 * Add a `create' operation to the log.
237 */
238
239 kadm5_ret_t
kadm5_log_create(kadm5_server_context * context,hdb_entry * ent)240 kadm5_log_create (kadm5_server_context *context,
241 hdb_entry *ent)
242 {
243 krb5_storage *sp;
244 kadm5_ret_t ret;
245 krb5_data value;
246 kadm5_log_context *log_context = &context->log_context;
247
248 sp = krb5_storage_emem();
249 ret = hdb_entry2value (context->context, ent, &value);
250 if (ret) {
251 krb5_storage_free(sp);
252 return ret;
253 }
254 ret = kadm5_log_preamble (context, sp, kadm_create);
255 if (ret) {
256 krb5_data_free (&value);
257 krb5_storage_free(sp);
258 return ret;
259 }
260 krb5_store_int32 (sp, value.length);
261 krb5_storage_write(sp, value.data, value.length);
262 krb5_store_int32 (sp, value.length);
263 krb5_data_free (&value);
264 ret = kadm5_log_postamble (log_context, sp);
265 if (ret) {
266 krb5_storage_free (sp);
267 return ret;
268 }
269 ret = kadm5_log_flush (log_context, sp);
270 krb5_storage_free (sp);
271 if (ret)
272 return ret;
273 ret = kadm5_log_end (context);
274 return ret;
275 }
276
277 /*
278 * Read the data of a create log record from `sp' and change the
279 * database.
280 */
281
282 static kadm5_ret_t
kadm5_log_replay_create(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)283 kadm5_log_replay_create (kadm5_server_context *context,
284 uint32_t ver,
285 uint32_t len,
286 krb5_storage *sp)
287 {
288 krb5_error_code ret;
289 krb5_data data;
290 hdb_entry_ex ent;
291
292 memset(&ent, 0, sizeof(ent));
293
294 ret = krb5_data_alloc (&data, len);
295 if (ret) {
296 krb5_set_error_message(context->context, ret, "out of memory");
297 return ret;
298 }
299 krb5_storage_read (sp, data.data, len);
300 ret = hdb_value2entry (context->context, &data, &ent.entry);
301 krb5_data_free(&data);
302 if (ret) {
303 krb5_set_error_message(context->context, ret,
304 "Unmarshaling hdb entry failed");
305 return ret;
306 }
307 ret = context->db->hdb_store(context->context, context->db, 0, &ent);
308 hdb_free_entry (context->context, &ent);
309 return ret;
310 }
311
312 /*
313 * Add a `delete' operation to the log.
314 */
315
316 kadm5_ret_t
kadm5_log_delete(kadm5_server_context * context,krb5_principal princ)317 kadm5_log_delete (kadm5_server_context *context,
318 krb5_principal princ)
319 {
320 krb5_storage *sp;
321 kadm5_ret_t ret;
322 off_t off;
323 off_t len;
324 kadm5_log_context *log_context = &context->log_context;
325
326 sp = krb5_storage_emem();
327 if (sp == NULL)
328 return ENOMEM;
329 ret = kadm5_log_preamble (context, sp, kadm_delete);
330 if (ret)
331 goto out;
332 ret = krb5_store_int32 (sp, 0);
333 if (ret)
334 goto out;
335 off = krb5_storage_seek (sp, 0, SEEK_CUR);
336 ret = krb5_store_principal (sp, princ);
337 if (ret)
338 goto out;
339 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
340 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
341 ret = krb5_store_int32 (sp, len);
342 if (ret)
343 goto out;
344 krb5_storage_seek(sp, len, SEEK_CUR);
345 ret = krb5_store_int32 (sp, len);
346 if (ret)
347 goto out;
348 ret = kadm5_log_postamble (log_context, sp);
349 if (ret)
350 goto out;
351 ret = kadm5_log_flush (log_context, sp);
352 if (ret)
353 goto out;
354 ret = kadm5_log_end (context);
355 out:
356 krb5_storage_free (sp);
357 return ret;
358 }
359
360 /*
361 * Read a `delete' log operation from `sp' and apply it.
362 */
363
364 static kadm5_ret_t
kadm5_log_replay_delete(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)365 kadm5_log_replay_delete (kadm5_server_context *context,
366 uint32_t ver,
367 uint32_t len,
368 krb5_storage *sp)
369 {
370 krb5_error_code ret;
371 krb5_principal principal;
372
373 ret = krb5_ret_principal (sp, &principal);
374 if (ret) {
375 krb5_set_error_message(context->context, ret, "Failed to read deleted "
376 "principal from log version: %ld", (long)ver);
377 return ret;
378 }
379
380 ret = context->db->hdb_remove(context->context, context->db, principal);
381 krb5_free_principal (context->context, principal);
382 return ret;
383 }
384
385 /*
386 * Add a `rename' operation to the log.
387 */
388
389 kadm5_ret_t
kadm5_log_rename(kadm5_server_context * context,krb5_principal source,hdb_entry * ent)390 kadm5_log_rename (kadm5_server_context *context,
391 krb5_principal source,
392 hdb_entry *ent)
393 {
394 krb5_storage *sp;
395 kadm5_ret_t ret;
396 off_t off;
397 off_t len;
398 krb5_data value;
399 kadm5_log_context *log_context = &context->log_context;
400
401 krb5_data_zero(&value);
402
403 sp = krb5_storage_emem();
404 ret = hdb_entry2value (context->context, ent, &value);
405 if (ret)
406 goto failed;
407
408 ret = kadm5_log_preamble (context, sp, kadm_rename);
409 if (ret)
410 goto failed;
411
412 ret = krb5_store_int32 (sp, 0);
413 if (ret)
414 goto failed;
415 off = krb5_storage_seek (sp, 0, SEEK_CUR);
416 ret = krb5_store_principal (sp, source);
417 if (ret)
418 goto failed;
419
420 krb5_storage_write(sp, value.data, value.length);
421 len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
422
423 krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
424 ret = krb5_store_int32 (sp, len);
425 if (ret)
426 goto failed;
427
428 krb5_storage_seek(sp, len, SEEK_CUR);
429 ret = krb5_store_int32 (sp, len);
430 if (ret)
431 goto failed;
432
433 ret = kadm5_log_postamble (log_context, sp);
434 if (ret)
435 goto failed;
436
437 ret = kadm5_log_flush (log_context, sp);
438 if (ret)
439 goto failed;
440 krb5_storage_free (sp);
441 krb5_data_free (&value);
442
443 return kadm5_log_end (context);
444
445 failed:
446 krb5_data_free(&value);
447 krb5_storage_free(sp);
448 return ret;
449 }
450
451 /*
452 * Read a `rename' log operation from `sp' and apply it.
453 */
454
455 static kadm5_ret_t
kadm5_log_replay_rename(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)456 kadm5_log_replay_rename (kadm5_server_context *context,
457 uint32_t ver,
458 uint32_t len,
459 krb5_storage *sp)
460 {
461 krb5_error_code ret;
462 krb5_principal source;
463 hdb_entry_ex target_ent;
464 krb5_data value;
465 off_t off;
466 size_t princ_len, data_len;
467
468 memset(&target_ent, 0, sizeof(target_ent));
469
470 off = krb5_storage_seek(sp, 0, SEEK_CUR);
471 ret = krb5_ret_principal (sp, &source);
472 if (ret) {
473 krb5_set_error_message(context->context, ret, "Failed to read renamed "
474 "principal in log, version: %ld", (long)ver);
475 return ret;
476 }
477 princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
478 data_len = len - princ_len;
479 ret = krb5_data_alloc (&value, data_len);
480 if (ret) {
481 krb5_free_principal (context->context, source);
482 return ret;
483 }
484 krb5_storage_read (sp, value.data, data_len);
485 ret = hdb_value2entry (context->context, &value, &target_ent.entry);
486 krb5_data_free(&value);
487 if (ret) {
488 krb5_free_principal (context->context, source);
489 return ret;
490 }
491 ret = context->db->hdb_store (context->context, context->db,
492 0, &target_ent);
493 hdb_free_entry (context->context, &target_ent);
494 if (ret) {
495 krb5_free_principal (context->context, source);
496 return ret;
497 }
498 ret = context->db->hdb_remove (context->context, context->db, source);
499 krb5_free_principal (context->context, source);
500 return ret;
501 }
502
503
504 /*
505 * Add a `modify' operation to the log.
506 */
507
508 kadm5_ret_t
kadm5_log_modify(kadm5_server_context * context,hdb_entry * ent,uint32_t mask)509 kadm5_log_modify (kadm5_server_context *context,
510 hdb_entry *ent,
511 uint32_t mask)
512 {
513 krb5_storage *sp;
514 kadm5_ret_t ret;
515 krb5_data value;
516 uint32_t len;
517 kadm5_log_context *log_context = &context->log_context;
518
519 krb5_data_zero(&value);
520
521 sp = krb5_storage_emem();
522 ret = hdb_entry2value (context->context, ent, &value);
523 if (ret)
524 goto failed;
525
526 ret = kadm5_log_preamble (context, sp, kadm_modify);
527 if (ret)
528 goto failed;
529
530 len = value.length + 4;
531 ret = krb5_store_int32 (sp, len);
532 if (ret)
533 goto failed;
534 ret = krb5_store_int32 (sp, mask);
535 if (ret)
536 goto failed;
537 krb5_storage_write (sp, value.data, value.length);
538
539 ret = krb5_store_int32 (sp, len);
540 if (ret)
541 goto failed;
542 ret = kadm5_log_postamble (log_context, sp);
543 if (ret)
544 goto failed;
545 ret = kadm5_log_flush (log_context, sp);
546 if (ret)
547 goto failed;
548 krb5_data_free(&value);
549 krb5_storage_free (sp);
550 return kadm5_log_end (context);
551 failed:
552 krb5_data_free(&value);
553 krb5_storage_free(sp);
554 return ret;
555 }
556
557 /*
558 * Read a `modify' log operation from `sp' and apply it.
559 */
560
561 static kadm5_ret_t
kadm5_log_replay_modify(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)562 kadm5_log_replay_modify (kadm5_server_context *context,
563 uint32_t ver,
564 uint32_t len,
565 krb5_storage *sp)
566 {
567 krb5_error_code ret;
568 int32_t mask;
569 krb5_data value;
570 hdb_entry_ex ent, log_ent;
571
572 memset(&log_ent, 0, sizeof(log_ent));
573
574 krb5_ret_int32 (sp, &mask);
575 len -= 4;
576 ret = krb5_data_alloc (&value, len);
577 if (ret) {
578 krb5_set_error_message(context->context, ret, "out of memory");
579 return ret;
580 }
581 krb5_storage_read (sp, value.data, len);
582 ret = hdb_value2entry (context->context, &value, &log_ent.entry);
583 krb5_data_free(&value);
584 if (ret)
585 return ret;
586
587 memset(&ent, 0, sizeof(ent));
588 ret = context->db->hdb_fetch_kvno(context->context, context->db,
589 log_ent.entry.principal,
590 HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
591 if (ret)
592 goto out;
593 if (mask & KADM5_PRINC_EXPIRE_TIME) {
594 if (log_ent.entry.valid_end == NULL) {
595 ent.entry.valid_end = NULL;
596 } else {
597 if (ent.entry.valid_end == NULL) {
598 ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
599 if (ent.entry.valid_end == NULL) {
600 ret = ENOMEM;
601 krb5_set_error_message(context->context, ret, "out of memory");
602 goto out;
603 }
604 }
605 *ent.entry.valid_end = *log_ent.entry.valid_end;
606 }
607 }
608 if (mask & KADM5_PW_EXPIRATION) {
609 if (log_ent.entry.pw_end == NULL) {
610 ent.entry.pw_end = NULL;
611 } else {
612 if (ent.entry.pw_end == NULL) {
613 ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
614 if (ent.entry.pw_end == NULL) {
615 ret = ENOMEM;
616 krb5_set_error_message(context->context, ret, "out of memory");
617 goto out;
618 }
619 }
620 *ent.entry.pw_end = *log_ent.entry.pw_end;
621 }
622 }
623 if (mask & KADM5_LAST_PWD_CHANGE) {
624 krb5_warnx (context->context, "Unimplemented mask KADM5_LAST_PWD_CHANGE");
625 }
626 if (mask & KADM5_ATTRIBUTES) {
627 ent.entry.flags = log_ent.entry.flags;
628 }
629 if (mask & KADM5_MAX_LIFE) {
630 if (log_ent.entry.max_life == NULL) {
631 ent.entry.max_life = NULL;
632 } else {
633 if (ent.entry.max_life == NULL) {
634 ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
635 if (ent.entry.max_life == NULL) {
636 ret = ENOMEM;
637 krb5_set_error_message(context->context, ret, "out of memory");
638 goto out;
639 }
640 }
641 *ent.entry.max_life = *log_ent.entry.max_life;
642 }
643 }
644 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
645 if (ent.entry.modified_by == NULL) {
646 ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
647 if (ent.entry.modified_by == NULL) {
648 ret = ENOMEM;
649 krb5_set_error_message(context->context, ret, "out of memory");
650 goto out;
651 }
652 } else
653 free_Event(ent.entry.modified_by);
654 ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
655 if (ret) {
656 krb5_set_error_message(context->context, ret, "out of memory");
657 goto out;
658 }
659 }
660 if (mask & KADM5_KVNO) {
661 ent.entry.kvno = log_ent.entry.kvno;
662 }
663 if (mask & KADM5_MKVNO) {
664 krb5_warnx (context->context, "Unimplemented mask KADM5_KVNO");
665 }
666 if (mask & KADM5_AUX_ATTRIBUTES) {
667 krb5_warnx (context->context, "Unimplemented mask KADM5_AUX_ATTRIBUTES");
668 }
669 if (mask & KADM5_POLICY) {
670 krb5_warnx (context->context, "Unimplemented mask KADM5_POLICY");
671 }
672 if (mask & KADM5_POLICY_CLR) {
673 krb5_warnx (context->context, "Unimplemented mask KADM5_POLICY_CLR");
674 }
675 if (mask & KADM5_MAX_RLIFE) {
676 if (log_ent.entry.max_renew == NULL) {
677 ent.entry.max_renew = NULL;
678 } else {
679 if (ent.entry.max_renew == NULL) {
680 ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
681 if (ent.entry.max_renew == NULL) {
682 ret = ENOMEM;
683 krb5_set_error_message(context->context, ret, "out of memory");
684 goto out;
685 }
686 }
687 *ent.entry.max_renew = *log_ent.entry.max_renew;
688 }
689 }
690 if (mask & KADM5_LAST_SUCCESS) {
691 krb5_warnx (context->context, "Unimplemented mask KADM5_LAST_SUCCESS");
692 }
693 if (mask & KADM5_LAST_FAILED) {
694 krb5_warnx (context->context, "Unimplemented mask KADM5_LAST_FAILED");
695 }
696 if (mask & KADM5_FAIL_AUTH_COUNT) {
697 krb5_warnx (context->context, "Unimplemented mask KADM5_FAIL_AUTH_COUNT");
698 }
699 if (mask & KADM5_KEY_DATA) {
700 size_t num;
701 size_t i;
702
703 for (i = 0; i < ent.entry.keys.len; ++i)
704 free_Key(&ent.entry.keys.val[i]);
705 free (ent.entry.keys.val);
706
707 num = log_ent.entry.keys.len;
708
709 ent.entry.keys.len = num;
710 ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
711 if (ent.entry.keys.val == NULL) {
712 krb5_set_error_message(context->context, ENOMEM, "out of memory");
713 return ENOMEM;
714 }
715 for (i = 0; i < ent.entry.keys.len; ++i) {
716 ret = copy_Key(&log_ent.entry.keys.val[i],
717 &ent.entry.keys.val[i]);
718 if (ret) {
719 krb5_set_error_message(context->context, ret, "out of memory");
720 goto out;
721 }
722 }
723 }
724 if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
725 HDB_extensions *es = ent.entry.extensions;
726
727 ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
728 if (ent.entry.extensions == NULL)
729 goto out;
730
731 ret = copy_HDB_extensions(log_ent.entry.extensions,
732 ent.entry.extensions);
733 if (ret) {
734 krb5_set_error_message(context->context, ret, "out of memory");
735 free(ent.entry.extensions);
736 ent.entry.extensions = es;
737 goto out;
738 }
739 if (es) {
740 free_HDB_extensions(es);
741 free(es);
742 }
743 }
744 ret = context->db->hdb_store(context->context, context->db,
745 HDB_F_REPLACE, &ent);
746 out:
747 hdb_free_entry (context->context, &ent);
748 hdb_free_entry (context->context, &log_ent);
749 return ret;
750 }
751
752 /*
753 * Add a `nop' operation to the log. Does not close the log.
754 */
755
756 kadm5_ret_t
kadm5_log_nop(kadm5_server_context * context)757 kadm5_log_nop (kadm5_server_context *context)
758 {
759 krb5_storage *sp;
760 kadm5_ret_t ret;
761 kadm5_log_context *log_context = &context->log_context;
762
763 sp = krb5_storage_emem();
764 ret = kadm5_log_preamble (context, sp, kadm_nop);
765 if (ret) {
766 krb5_storage_free (sp);
767 return ret;
768 }
769 krb5_store_int32 (sp, 0);
770 krb5_store_int32 (sp, 0);
771 ret = kadm5_log_postamble (log_context, sp);
772 if (ret) {
773 krb5_storage_free (sp);
774 return ret;
775 }
776 ret = kadm5_log_flush (log_context, sp);
777 krb5_storage_free (sp);
778
779 return ret;
780 }
781
782 /*
783 * Read a `nop' log operation from `sp' and apply it.
784 */
785
786 static kadm5_ret_t
kadm5_log_replay_nop(kadm5_server_context * context,uint32_t ver,uint32_t len,krb5_storage * sp)787 kadm5_log_replay_nop (kadm5_server_context *context,
788 uint32_t ver,
789 uint32_t len,
790 krb5_storage *sp)
791 {
792 return 0;
793 }
794
795 /*
796 * Call `func' for each log record in the log in `context'
797 */
798
799 kadm5_ret_t
kadm5_log_foreach(kadm5_server_context * context,void (* func)(kadm5_server_context * server_context,uint32_t ver,time_t timestamp,enum kadm_ops op,uint32_t len,krb5_storage *,void *),void * ctx)800 kadm5_log_foreach (kadm5_server_context *context,
801 void (*func)(kadm5_server_context *server_context,
802 uint32_t ver,
803 time_t timestamp,
804 enum kadm_ops op,
805 uint32_t len,
806 krb5_storage *,
807 void *),
808 void *ctx)
809 {
810 int fd = context->log_context.log_fd;
811 krb5_storage *sp;
812
813 lseek (fd, 0, SEEK_SET);
814 sp = krb5_storage_from_fd (fd);
815 for (;;) {
816 int32_t ver, timestamp, op, len, len2, ver2;
817
818 if(krb5_ret_int32 (sp, &ver) != 0)
819 break;
820 krb5_ret_int32 (sp, ×tamp);
821 krb5_ret_int32 (sp, &op);
822 krb5_ret_int32 (sp, &len);
823 (*func)(context, ver, timestamp, op, len, sp, ctx);
824 krb5_ret_int32 (sp, &len2);
825 krb5_ret_int32 (sp, &ver2);
826 if (len != len2)
827 abort();
828 if (ver != ver2)
829 abort();
830 }
831 krb5_storage_free(sp);
832 return 0;
833 }
834
835 /*
836 * Go to end of log.
837 */
838
839 krb5_storage *
kadm5_log_goto_end(int fd)840 kadm5_log_goto_end (int fd)
841 {
842 krb5_storage *sp;
843
844 sp = krb5_storage_from_fd (fd);
845 krb5_storage_seek(sp, 0, SEEK_END);
846 return sp;
847 }
848
849 /*
850 * Return previous log entry.
851 *
852 * The pointer in `sp´ is assumed to be at the top of the entry before
853 * previous entry. On success, the `sp´ pointer is set to data portion
854 * of previous entry. In case of error, it's not changed at all.
855 */
856
857 kadm5_ret_t
kadm5_log_previous(krb5_context context,krb5_storage * sp,uint32_t * ver,time_t * timestamp,enum kadm_ops * op,uint32_t * len)858 kadm5_log_previous (krb5_context context,
859 krb5_storage *sp,
860 uint32_t *ver,
861 time_t *timestamp,
862 enum kadm_ops *op,
863 uint32_t *len)
864 {
865 krb5_error_code ret;
866 off_t off, oldoff;
867 int32_t tmp;
868
869 oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
870
871 krb5_storage_seek(sp, -8, SEEK_CUR);
872 ret = krb5_ret_int32 (sp, &tmp);
873 if (ret)
874 goto end_of_storage;
875 *len = tmp;
876 ret = krb5_ret_int32 (sp, &tmp);
877 if (ret)
878 goto end_of_storage;
879 *ver = tmp;
880 off = 24 + *len;
881 krb5_storage_seek(sp, -off, SEEK_CUR);
882 ret = krb5_ret_int32 (sp, &tmp);
883 if (ret)
884 goto end_of_storage;
885 if ((uint32_t)tmp != *ver) {
886 krb5_storage_seek(sp, oldoff, SEEK_SET);
887 krb5_set_error_message(context, KADM5_BAD_DB,
888 "kadm5_log_previous: log entry "
889 "have consistency failure, version number wrong "
890 "(tmp %lu ver %lu)",
891 (unsigned long)tmp,
892 (unsigned long)*ver);
893 return KADM5_BAD_DB;
894 }
895 ret = krb5_ret_int32 (sp, &tmp);
896 if (ret)
897 goto end_of_storage;
898 *timestamp = tmp;
899 ret = krb5_ret_int32 (sp, &tmp);
900 if (ret)
901 goto end_of_storage;
902 *op = tmp;
903 ret = krb5_ret_int32 (sp, &tmp);
904 if (ret)
905 goto end_of_storage;
906 if ((uint32_t)tmp != *len) {
907 krb5_storage_seek(sp, oldoff, SEEK_SET);
908 krb5_set_error_message(context, KADM5_BAD_DB,
909 "kadm5_log_previous: log entry "
910 "have consistency failure, length wrong");
911 return KADM5_BAD_DB;
912 }
913 return 0;
914
915 end_of_storage:
916 krb5_storage_seek(sp, oldoff, SEEK_SET);
917 krb5_set_error_message(context, ret, "kadm5_log_previous: end of storage "
918 "reached before end");
919 return ret;
920 }
921
922 /*
923 * Replay a record from the log
924 */
925
926 kadm5_ret_t
kadm5_log_replay(kadm5_server_context * context,enum kadm_ops op,uint32_t ver,uint32_t len,krb5_storage * sp)927 kadm5_log_replay (kadm5_server_context *context,
928 enum kadm_ops op,
929 uint32_t ver,
930 uint32_t len,
931 krb5_storage *sp)
932 {
933 switch (op) {
934 case kadm_create :
935 return kadm5_log_replay_create (context, ver, len, sp);
936 case kadm_delete :
937 return kadm5_log_replay_delete (context, ver, len, sp);
938 case kadm_rename :
939 return kadm5_log_replay_rename (context, ver, len, sp);
940 case kadm_modify :
941 return kadm5_log_replay_modify (context, ver, len, sp);
942 case kadm_nop :
943 return kadm5_log_replay_nop (context, ver, len, sp);
944 default :
945 krb5_set_error_message(context->context, KADM5_FAILURE,
946 "Unsupported replay op %d", (int)op);
947 return KADM5_FAILURE;
948 }
949 }
950
951 /*
952 * truncate the log - i.e. create an empty file with just (nop vno + 2)
953 */
954
955 kadm5_ret_t
kadm5_log_truncate(kadm5_server_context * server_context)956 kadm5_log_truncate (kadm5_server_context *server_context)
957 {
958 kadm5_ret_t ret;
959 uint32_t vno;
960
961 ret = kadm5_log_init (server_context);
962 if (ret)
963 return ret;
964
965 ret = kadm5_log_get_version (server_context, &vno);
966 if (ret)
967 return ret;
968
969 ret = kadm5_log_reinit (server_context);
970 if (ret)
971 return ret;
972
973 ret = kadm5_log_set_version (server_context, vno);
974 if (ret)
975 return ret;
976
977 ret = kadm5_log_nop (server_context);
978 if (ret)
979 return ret;
980
981 ret = kadm5_log_end (server_context);
982 if (ret)
983 return ret;
984 return 0;
985
986 }
987
988 #ifndef NO_UNIX_SOCKETS
989
990 static char *default_signal = NULL;
991 static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
992
993 const char *
kadm5_log_signal_socket(krb5_context context)994 kadm5_log_signal_socket(krb5_context context)
995 {
996 HEIMDAL_MUTEX_lock(&signal_mutex);
997 if (!default_signal)
998 asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
999 HEIMDAL_MUTEX_unlock(&signal_mutex);
1000
1001 return krb5_config_get_string_default(context,
1002 NULL,
1003 default_signal,
1004 "kdc",
1005 "signal_socket",
1006 NULL);
1007 }
1008
1009 #else /* NO_UNIX_SOCKETS */
1010
1011 #define SIGNAL_SOCKET_HOST "127.0.0.1"
1012 #define SIGNAL_SOCKET_PORT "12701"
1013
1014 kadm5_ret_t
kadm5_log_signal_socket_info(krb5_context context,int server_end,struct addrinfo ** ret_addrs)1015 kadm5_log_signal_socket_info(krb5_context context,
1016 int server_end,
1017 struct addrinfo **ret_addrs)
1018 {
1019 struct addrinfo hints;
1020 struct addrinfo *addrs = NULL;
1021 kadm5_ret_t ret = KADM5_FAILURE;
1022 int wsret;
1023
1024 memset(&hints, 0, sizeof(hints));
1025
1026 hints.ai_flags = AI_NUMERICHOST;
1027 if (server_end)
1028 hints.ai_flags |= AI_PASSIVE;
1029 hints.ai_family = AF_INET;
1030 hints.ai_socktype = SOCK_STREAM;
1031 hints.ai_protocol = IPPROTO_TCP;
1032
1033 wsret = getaddrinfo(SIGNAL_SOCKET_HOST,
1034 SIGNAL_SOCKET_PORT,
1035 &hints, &addrs);
1036
1037 if (wsret != 0) {
1038 krb5_set_error_message(context, KADM5_FAILURE,
1039 "%s", gai_strerror(wsret));
1040 goto done;
1041 }
1042
1043 if (addrs == NULL) {
1044 krb5_set_error_message(context, KADM5_FAILURE,
1045 "getaddrinfo() failed to return address list");
1046 goto done;
1047 }
1048
1049 *ret_addrs = addrs;
1050 addrs = NULL;
1051 ret = 0;
1052
1053 done:
1054 if (addrs)
1055 freeaddrinfo(addrs);
1056 return ret;
1057 }
1058
1059 #endif
1060