1 /* 2 * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 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. 16 * 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. 20 * 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. 32 */ 33 34 #include "kadm5_locl.h" 35 36 RCSID("$Id: log.c,v 1.18 2000/07/24 04:32:17 assar Exp $"); 37 38 /* 39 * A log record consists of: 40 * 41 * version number 4 bytes 42 * time in seconds 4 bytes 43 * operation (enum kadm_ops) 4 bytes 44 * length of record 4 bytes 45 * data... n bytes 46 * length of record 4 bytes 47 * version number 4 bytes 48 * 49 */ 50 51 kadm5_ret_t 52 kadm5_log_get_version_fd (int fd, 53 u_int32_t *ver) 54 { 55 int ret; 56 krb5_storage *sp; 57 int32_t old_version; 58 59 ret = lseek (fd, 0, SEEK_END); 60 if(ret < 0) 61 return errno; 62 if(ret == 0) { 63 *ver = 0; 64 return 0; 65 } 66 sp = krb5_storage_from_fd (fd); 67 sp->seek(sp, -4, SEEK_CUR); 68 krb5_ret_int32 (sp, &old_version); 69 *ver = old_version; 70 krb5_storage_free(sp); 71 lseek (fd, 0, SEEK_END); 72 return 0; 73 } 74 75 kadm5_ret_t 76 kadm5_log_get_version (kadm5_server_context *context, u_int32_t *ver) 77 { 78 return kadm5_log_get_version_fd (context->log_context.log_fd, ver); 79 } 80 81 kadm5_ret_t 82 kadm5_log_set_version (kadm5_server_context *context, u_int32_t vno) 83 { 84 kadm5_log_context *log_context = &context->log_context; 85 86 log_context->version = vno; 87 return 0; 88 } 89 90 kadm5_ret_t 91 kadm5_log_init (kadm5_server_context *context) 92 { 93 int fd; 94 kadm5_ret_t ret; 95 kadm5_log_context *log_context = &context->log_context; 96 97 if (log_context->log_fd != -1) 98 return 0; 99 fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600); 100 if (fd < 0) 101 return errno; 102 if (flock (fd, LOCK_EX) < 0) { 103 close (fd); 104 return errno; 105 } 106 107 ret = kadm5_log_get_version_fd (fd, &log_context->version); 108 if (ret) 109 return ret; 110 111 log_context->log_fd = fd; 112 return 0; 113 } 114 115 kadm5_ret_t 116 kadm5_log_reinit (kadm5_server_context *context) 117 { 118 int fd; 119 kadm5_log_context *log_context = &context->log_context; 120 121 if (log_context->log_fd != -1) { 122 close (log_context->log_fd); 123 log_context->log_fd = -1; 124 } 125 fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600); 126 if (fd < 0) 127 return errno; 128 if (flock (fd, LOCK_EX) < 0) { 129 close (fd); 130 return errno; 131 } 132 133 log_context->version = 0; 134 log_context->log_fd = fd; 135 return 0; 136 } 137 138 139 kadm5_ret_t 140 kadm5_log_end (kadm5_server_context *context) 141 { 142 kadm5_log_context *log_context = &context->log_context; 143 int fd = log_context->log_fd; 144 145 flock (fd, LOCK_UN); 146 close(fd); 147 log_context->log_fd = -1; 148 return 0; 149 } 150 151 static kadm5_ret_t 152 kadm5_log_preamble (kadm5_server_context *context, 153 krb5_storage *sp, 154 enum kadm_ops op) 155 { 156 kadm5_log_context *log_context = &context->log_context; 157 kadm5_ret_t kadm_ret; 158 159 kadm_ret = kadm5_log_init (context); 160 if (kadm_ret) 161 return kadm_ret; 162 163 krb5_store_int32 (sp, ++log_context->version); 164 krb5_store_int32 (sp, time(NULL)); 165 krb5_store_int32 (sp, op); 166 return 0; 167 } 168 169 static kadm5_ret_t 170 kadm5_log_postamble (kadm5_log_context *context, 171 krb5_storage *sp) 172 { 173 krb5_store_int32 (sp, context->version); 174 return 0; 175 } 176 177 /* 178 * flush the log record in `sp'. 179 */ 180 181 static kadm5_ret_t 182 kadm5_log_flush (kadm5_log_context *log_context, 183 krb5_storage *sp) 184 { 185 krb5_data data; 186 size_t len; 187 int ret; 188 189 krb5_storage_to_data(sp, &data); 190 len = data.length; 191 ret = write (log_context->log_fd, data.data, len); 192 if (ret != len) { 193 krb5_data_free(&data); 194 return errno; 195 } 196 if (fsync (log_context->log_fd) < 0) { 197 krb5_data_free(&data); 198 return errno; 199 } 200 /* 201 * Try to send a signal to any running `ipropd-master' 202 */ 203 sendto (log_context->socket_fd, 204 (void *)&log_context->version, 205 sizeof(log_context->version), 206 0, 207 (struct sockaddr *)&log_context->socket_name, 208 sizeof(log_context->socket_name)); 209 210 krb5_data_free(&data); 211 return 0; 212 } 213 214 /* 215 * Add a `create' operation to the log. 216 */ 217 218 kadm5_ret_t 219 kadm5_log_create (kadm5_server_context *context, 220 hdb_entry *ent) 221 { 222 krb5_storage *sp; 223 kadm5_ret_t ret; 224 krb5_data value; 225 kadm5_log_context *log_context = &context->log_context; 226 227 sp = krb5_storage_emem(); 228 ret = hdb_entry2value (context->context, ent, &value); 229 if (ret) { 230 krb5_storage_free(sp); 231 return ret; 232 } 233 ret = kadm5_log_preamble (context, sp, kadm_create); 234 if (ret) { 235 krb5_data_free (&value); 236 krb5_storage_free(sp); 237 return ret; 238 } 239 krb5_store_int32 (sp, value.length); 240 sp->store(sp, value.data, value.length); 241 krb5_store_int32 (sp, value.length); 242 krb5_data_free (&value); 243 ret = kadm5_log_postamble (log_context, sp); 244 if (ret) { 245 krb5_storage_free (sp); 246 return ret; 247 } 248 ret = kadm5_log_flush (log_context, sp); 249 krb5_storage_free (sp); 250 if (ret) 251 return ret; 252 ret = kadm5_log_end (context); 253 return ret; 254 } 255 256 /* 257 * Read the data of a create log record from `sp' and change the 258 * database. 259 */ 260 261 kadm5_ret_t 262 kadm5_log_replay_create (kadm5_server_context *context, 263 u_int32_t ver, 264 u_int32_t len, 265 krb5_storage *sp) 266 { 267 krb5_error_code ret; 268 krb5_data data; 269 hdb_entry ent; 270 271 krb5_data_alloc (&data, len); 272 sp->fetch (sp, data.data, len); 273 ret = hdb_value2entry (context->context, &data, &ent); 274 krb5_data_free(&data); 275 if (ret) 276 return ret; 277 ret = context->db->store(context->context, context->db, 0, &ent); 278 hdb_free_entry (context->context, &ent); 279 return ret; 280 } 281 282 /* 283 * Add a `delete' operation to the log. 284 */ 285 286 kadm5_ret_t 287 kadm5_log_delete (kadm5_server_context *context, 288 krb5_principal princ) 289 { 290 krb5_storage *sp; 291 kadm5_ret_t ret; 292 off_t off; 293 off_t len; 294 kadm5_log_context *log_context = &context->log_context; 295 296 sp = krb5_storage_emem(); 297 ret = kadm5_log_preamble (context, sp, kadm_delete); 298 if (ret) { 299 krb5_storage_free(sp); 300 return ret; 301 } 302 krb5_store_int32 (sp, 0); 303 off = sp->seek (sp, 0, SEEK_CUR); 304 krb5_store_principal (sp, princ); 305 len = sp->seek (sp, 0, SEEK_CUR) - off; 306 sp->seek(sp, -(len + 4), SEEK_CUR); 307 krb5_store_int32 (sp, len); 308 sp->seek(sp, len, SEEK_CUR); 309 krb5_store_int32 (sp, len); 310 if (ret) { 311 krb5_storage_free (sp); 312 return ret; 313 } 314 ret = kadm5_log_postamble (log_context, sp); 315 if (ret) { 316 krb5_storage_free (sp); 317 return ret; 318 } 319 ret = kadm5_log_flush (log_context, sp); 320 krb5_storage_free (sp); 321 if (ret) 322 return ret; 323 ret = kadm5_log_end (context); 324 return ret; 325 } 326 327 /* 328 * Read a `delete' log operation from `sp' and apply it. 329 */ 330 331 kadm5_ret_t 332 kadm5_log_replay_delete (kadm5_server_context *context, 333 u_int32_t ver, 334 u_int32_t len, 335 krb5_storage *sp) 336 { 337 krb5_error_code ret; 338 hdb_entry ent; 339 340 krb5_ret_principal (sp, &ent.principal); 341 342 ret = context->db->remove(context->context, context->db, &ent); 343 krb5_free_principal (context->context, ent.principal); 344 return ret; 345 } 346 347 /* 348 * Add a `rename' operation to the log. 349 */ 350 351 kadm5_ret_t 352 kadm5_log_rename (kadm5_server_context *context, 353 krb5_principal source, 354 hdb_entry *ent) 355 { 356 krb5_storage *sp; 357 kadm5_ret_t ret; 358 off_t off; 359 off_t len; 360 krb5_data value; 361 kadm5_log_context *log_context = &context->log_context; 362 363 sp = krb5_storage_emem(); 364 ret = hdb_entry2value (context->context, ent, &value); 365 if (ret) { 366 krb5_storage_free(sp); 367 return ret; 368 } 369 ret = kadm5_log_preamble (context, sp, kadm_rename); 370 if (ret) { 371 krb5_storage_free(sp); 372 krb5_data_free (&value); 373 return ret; 374 } 375 krb5_store_int32 (sp, 0); 376 off = sp->seek (sp, 0, SEEK_CUR); 377 krb5_store_principal (sp, source); 378 sp->store(sp, value.data, value.length); 379 krb5_data_free (&value); 380 len = sp->seek (sp, 0, SEEK_CUR) - off; 381 382 sp->seek(sp, -(len + 4), SEEK_CUR); 383 krb5_store_int32 (sp, len); 384 sp->seek(sp, len, SEEK_CUR); 385 krb5_store_int32 (sp, len); 386 if (ret) { 387 krb5_storage_free (sp); 388 return ret; 389 } 390 ret = kadm5_log_postamble (log_context, sp); 391 if (ret) { 392 krb5_storage_free (sp); 393 return ret; 394 } 395 ret = kadm5_log_flush (log_context, sp); 396 krb5_storage_free (sp); 397 if (ret) 398 return ret; 399 ret = kadm5_log_end (context); 400 return ret; 401 } 402 403 /* 404 * Read a `rename' log operation from `sp' and apply it. 405 */ 406 407 kadm5_ret_t 408 kadm5_log_replay_rename (kadm5_server_context *context, 409 u_int32_t ver, 410 u_int32_t len, 411 krb5_storage *sp) 412 { 413 krb5_error_code ret; 414 krb5_principal source; 415 hdb_entry source_ent, target_ent; 416 krb5_data value; 417 off_t off; 418 size_t princ_len, data_len; 419 420 off = sp->seek(sp, 0, SEEK_CUR); 421 krb5_ret_principal (sp, &source); 422 princ_len = sp->seek(sp, 0, SEEK_CUR) - off; 423 data_len = len - princ_len; 424 krb5_data_alloc (&value, data_len); 425 sp->fetch (sp, value.data, data_len); 426 ret = hdb_value2entry (context->context, &value, &target_ent); 427 krb5_data_free(&value); 428 if (ret) { 429 krb5_free_principal (context->context, source); 430 return ret; 431 } 432 ret = context->db->store (context->context, context->db, 0, &target_ent); 433 hdb_free_entry (context->context, &target_ent); 434 if (ret) { 435 krb5_free_principal (context->context, source); 436 return ret; 437 } 438 source_ent.principal = source; 439 ret = context->db->remove (context->context, context->db, &source_ent); 440 krb5_free_principal (context->context, source); 441 return ret; 442 } 443 444 445 /* 446 * Add a `modify' operation to the log. 447 */ 448 449 kadm5_ret_t 450 kadm5_log_modify (kadm5_server_context *context, 451 hdb_entry *ent, 452 u_int32_t mask) 453 { 454 krb5_storage *sp; 455 kadm5_ret_t ret; 456 krb5_data value; 457 u_int32_t len; 458 kadm5_log_context *log_context = &context->log_context; 459 460 sp = krb5_storage_emem(); 461 ret = hdb_entry2value (context->context, ent, &value); 462 if (ret) { 463 krb5_storage_free(sp); 464 return ret; 465 } 466 ret = kadm5_log_preamble (context, sp, kadm_modify); 467 if (ret) { 468 krb5_data_free (&value); 469 krb5_storage_free(sp); 470 return ret; 471 } 472 len = value.length + 4; 473 krb5_store_int32 (sp, len); 474 krb5_store_int32 (sp, mask); 475 sp->store(sp, value.data, value.length); 476 krb5_data_free (&value); 477 krb5_store_int32 (sp, len); 478 if (ret) { 479 krb5_storage_free (sp); 480 return ret; 481 } 482 ret = kadm5_log_postamble (log_context, sp); 483 if (ret) { 484 krb5_storage_free (sp); 485 return ret; 486 } 487 ret = kadm5_log_flush (log_context, sp); 488 krb5_storage_free (sp); 489 if (ret) 490 return ret; 491 ret = kadm5_log_end (context); 492 return ret; 493 } 494 495 /* 496 * Read a `modify' log operation from `sp' and apply it. 497 */ 498 499 kadm5_ret_t 500 kadm5_log_replay_modify (kadm5_server_context *context, 501 u_int32_t ver, 502 u_int32_t len, 503 krb5_storage *sp) 504 { 505 krb5_error_code ret; 506 int32_t mask; 507 krb5_data value; 508 hdb_entry ent, log_ent; 509 510 krb5_ret_int32 (sp, &mask); 511 len -= 4; 512 krb5_data_alloc (&value, len); 513 sp->fetch (sp, value.data, len); 514 ret = hdb_value2entry (context->context, &value, &log_ent); 515 krb5_data_free(&value); 516 if (ret) 517 return ret; 518 ent.principal = log_ent.principal; 519 log_ent.principal = NULL; 520 ret = context->db->fetch(context->context, context->db, 521 HDB_F_DECRYPT, &ent); 522 if (ret) 523 return ret; 524 if (mask & KADM5_PRINC_EXPIRE_TIME) { 525 if (log_ent.valid_end == NULL) { 526 ent.valid_end = NULL; 527 } else { 528 if (ent.valid_end == NULL) 529 ent.valid_end = malloc(sizeof(*ent.valid_end)); 530 *ent.valid_end = *log_ent.valid_end; 531 } 532 } 533 if (mask & KADM5_PW_EXPIRATION) { 534 if (log_ent.pw_end == NULL) { 535 ent.pw_end = NULL; 536 } else { 537 if (ent.pw_end == NULL) 538 ent.pw_end = malloc(sizeof(*ent.pw_end)); 539 *ent.pw_end = *log_ent.pw_end; 540 } 541 } 542 if (mask & KADM5_LAST_PWD_CHANGE) { 543 abort (); /* XXX */ 544 } 545 if (mask & KADM5_ATTRIBUTES) { 546 ent.flags = log_ent.flags; 547 } 548 if (mask & KADM5_MAX_LIFE) { 549 if (log_ent.max_life == NULL) { 550 ent.max_life = NULL; 551 } else { 552 if (ent.max_life == NULL) 553 ent.max_life = malloc (sizeof(*ent.max_life)); 554 *ent.max_life = *log_ent.max_life; 555 } 556 } 557 if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) { 558 if (ent.modified_by == NULL) { 559 ent.modified_by = malloc(sizeof(*ent.modified_by)); 560 } else 561 free_Event(ent.modified_by); 562 copy_Event(log_ent.modified_by, ent.modified_by); 563 } 564 if (mask & KADM5_KVNO) { 565 ent.kvno = log_ent.kvno; 566 } 567 if (mask & KADM5_MKVNO) { 568 abort (); /* XXX */ 569 } 570 if (mask & KADM5_AUX_ATTRIBUTES) { 571 abort (); /* XXX */ 572 } 573 if (mask & KADM5_POLICY) { 574 abort (); /* XXX */ 575 } 576 if (mask & KADM5_POLICY_CLR) { 577 abort (); /* XXX */ 578 } 579 if (mask & KADM5_MAX_RLIFE) { 580 if (log_ent.max_renew == NULL) { 581 ent.max_renew = NULL; 582 } else { 583 if (ent.max_renew == NULL) 584 ent.max_renew = malloc (sizeof(*ent.max_renew)); 585 *ent.max_renew = *log_ent.max_renew; 586 } 587 } 588 if (mask & KADM5_LAST_SUCCESS) { 589 abort (); /* XXX */ 590 } 591 if (mask & KADM5_LAST_FAILED) { 592 abort (); /* XXX */ 593 } 594 if (mask & KADM5_FAIL_AUTH_COUNT) { 595 abort (); /* XXX */ 596 } 597 if (mask & KADM5_KEY_DATA) { 598 size_t len; 599 int i; 600 601 for (i = 0; i < ent.keys.len; ++i) 602 free_Key(&ent.keys.val[i]); 603 free (ent.keys.val); 604 605 len = log_ent.keys.len; 606 607 ent.keys.len = len; 608 ent.keys.val = malloc(len * sizeof(*ent.keys.val)); 609 for (i = 0; i < ent.keys.len; ++i) 610 copy_Key(&log_ent.keys.val[i], 611 &ent.keys.val[i]); 612 } 613 ret = context->db->store(context->context, context->db, 614 HDB_F_REPLACE, &ent); 615 hdb_free_entry (context->context, &ent); 616 hdb_free_entry (context->context, &log_ent); 617 return ret; 618 } 619 620 /* 621 * Add a `nop' operation to the log. 622 */ 623 624 kadm5_ret_t 625 kadm5_log_nop (kadm5_server_context *context) 626 { 627 krb5_storage *sp; 628 kadm5_ret_t ret; 629 kadm5_log_context *log_context = &context->log_context; 630 631 sp = krb5_storage_emem(); 632 ret = kadm5_log_preamble (context, sp, kadm_nop); 633 if (ret) { 634 krb5_storage_free (sp); 635 return ret; 636 } 637 krb5_store_int32 (sp, 0); 638 krb5_store_int32 (sp, 0); 639 ret = kadm5_log_postamble (log_context, sp); 640 if (ret) { 641 krb5_storage_free (sp); 642 return ret; 643 } 644 ret = kadm5_log_flush (log_context, sp); 645 krb5_storage_free (sp); 646 if (ret) 647 return ret; 648 ret = kadm5_log_end (context); 649 return ret; 650 } 651 652 /* 653 * Read a `nop' log operation from `sp' and apply it. 654 */ 655 656 kadm5_ret_t 657 kadm5_log_replay_nop (kadm5_server_context *context, 658 u_int32_t ver, 659 u_int32_t len, 660 krb5_storage *sp) 661 { 662 return 0; 663 } 664 665 /* 666 * Call `func' for each log record in the log in `context' 667 */ 668 669 kadm5_ret_t 670 kadm5_log_foreach (kadm5_server_context *context, 671 void (*func)(kadm5_server_context *server_context, 672 u_int32_t ver, 673 time_t timestamp, 674 enum kadm_ops op, 675 u_int32_t len, 676 krb5_storage *sp)) 677 { 678 int fd = context->log_context.log_fd; 679 krb5_storage *sp; 680 681 lseek (fd, 0, SEEK_SET); 682 sp = krb5_storage_from_fd (fd); 683 for (;;) { 684 int32_t ver, timestamp, op, len; 685 686 if(krb5_ret_int32 (sp, &ver) != 0) 687 break; 688 krb5_ret_int32 (sp, ×tamp); 689 krb5_ret_int32 (sp, &op); 690 krb5_ret_int32 (sp, &len); 691 (*func)(context, ver, timestamp, op, len, sp); 692 sp->seek(sp, 8, SEEK_CUR); 693 } 694 return 0; 695 } 696 697 /* 698 * Go to end of log. 699 */ 700 701 krb5_storage * 702 kadm5_log_goto_end (int fd) 703 { 704 krb5_storage *sp; 705 706 sp = krb5_storage_from_fd (fd); 707 sp->seek(sp, 0, SEEK_END); 708 return sp; 709 } 710 711 /* 712 * Return previous log entry. 713 */ 714 715 kadm5_ret_t 716 kadm5_log_previous (krb5_storage *sp, 717 u_int32_t *ver, 718 time_t *timestamp, 719 enum kadm_ops *op, 720 u_int32_t *len) 721 { 722 off_t off; 723 int32_t tmp; 724 725 sp->seek(sp, -8, SEEK_CUR); 726 krb5_ret_int32 (sp, &tmp); 727 *len = tmp; 728 krb5_ret_int32 (sp, &tmp); 729 *ver = tmp; 730 off = 24 + *len; 731 sp->seek(sp, -off, SEEK_CUR); 732 krb5_ret_int32 (sp, &tmp); 733 assert(tmp == *ver); 734 krb5_ret_int32 (sp, &tmp); 735 *timestamp = tmp; 736 krb5_ret_int32 (sp, &tmp); 737 *op = tmp; 738 krb5_ret_int32 (sp, &tmp); 739 assert(tmp == *len); 740 return 0; 741 } 742 743 /* 744 * Replay a record from the log 745 */ 746 747 kadm5_ret_t 748 kadm5_log_replay (kadm5_server_context *context, 749 enum kadm_ops op, 750 u_int32_t ver, 751 u_int32_t len, 752 krb5_storage *sp) 753 { 754 switch (op) { 755 case kadm_create : 756 return kadm5_log_replay_create (context, ver, len, sp); 757 case kadm_delete : 758 return kadm5_log_replay_delete (context, ver, len, sp); 759 case kadm_rename : 760 return kadm5_log_replay_rename (context, ver, len, sp); 761 case kadm_modify : 762 return kadm5_log_replay_modify (context, ver, len, sp); 763 case kadm_nop : 764 return kadm5_log_replay_nop (context, ver, len, sp); 765 default : 766 return KADM5_FAILURE; 767 } 768 } 769 770 /* 771 * truncate the log - i.e. create an empty file with just (nop vno + 2) 772 */ 773 774 kadm5_ret_t 775 kadm5_log_truncate (kadm5_server_context *server_context) 776 { 777 kadm5_ret_t ret; 778 u_int32_t vno; 779 780 ret = kadm5_log_init (server_context); 781 if (ret) 782 return ret; 783 784 ret = kadm5_log_get_version (server_context, &vno); 785 if (ret) 786 return ret; 787 788 ret = kadm5_log_reinit (server_context); 789 if (ret) 790 return ret; 791 792 ret = kadm5_log_set_version (server_context, vno + 1); 793 if (ret) 794 return ret; 795 796 ret = kadm5_log_nop (server_context); 797 if (ret) 798 return ret; 799 800 ret = kadm5_log_end (server_context); 801 if (ret) 802 return ret; 803 return 0; 804 805 } 806