1 /* $NetBSD: log.c,v 1.1.1.1 2011/04/13 18:15:30 elric 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: log.c,v 1.1.1.1 2011/04/13 18:15:30 elric Exp $"); 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 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 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 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 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 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 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 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 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 193 kadm5_log_flush (kadm5_log_context *log_context, 194 krb5_storage *sp) 195 { 196 krb5_data data; 197 size_t len; 198 int 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 != 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 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 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 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 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 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 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 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 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 abort (); /* XXX */ 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 abort (); /* XXX */ 665 } 666 if (mask & KADM5_AUX_ATTRIBUTES) { 667 abort (); /* XXX */ 668 } 669 if (mask & KADM5_POLICY) { 670 abort (); /* XXX */ 671 } 672 if (mask & KADM5_POLICY_CLR) { 673 abort (); /* XXX */ 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 abort (); /* XXX */ 692 } 693 if (mask & KADM5_LAST_FAILED) { 694 abort (); /* XXX */ 695 } 696 if (mask & KADM5_FAIL_AUTH_COUNT) { 697 abort (); /* XXX */ 698 } 699 if (mask & KADM5_KEY_DATA) { 700 size_t num; 701 int 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 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 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 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 * 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 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 (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 (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 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 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 * 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 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