1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 #include <sys/stat.h> 9 #include <sys/types.h> 10 #include <unistd.h> 11 #include <fcntl.h> 12 #include <sys/mman.h> 13 #include <k5-int.h> 14 #include <stdlib.h> 15 #include <limits.h> 16 #include <syslog.h> 17 #include "kdb_log.h" 18 19 /* 20 * This modules includes all the necessary functions that create and 21 * modify the Kerberos principal update and header logs. 22 */ 23 24 #define getpagesize() sysconf(_SC_PAGESIZE) 25 26 static int pagesize = 0; 27 28 #define INIT_ULOG(ctx) log_ctx = ctx->kdblog_context; \ 29 ulog = log_ctx->ulog 30 /* 31 * Sync update entry to disk. 32 */ 33 krb5_error_code 34 ulog_sync_update(kdb_hlog_t *ulog, kdb_ent_header_t *upd) 35 { 36 ulong_t start, end, size; 37 krb5_error_code retval; 38 39 if (ulog == NULL) 40 return (KRB5_LOG_ERROR); 41 42 if (!pagesize) 43 pagesize = getpagesize(); 44 45 start = ((ulong_t)upd) & (~(pagesize-1)); 46 47 end = (((ulong_t)upd) + ulog->kdb_block + 48 (pagesize-1)) & (~(pagesize-1)); 49 50 size = end - start; 51 if (retval = msync((caddr_t)start, size, MS_SYNC)) { 52 return (retval); 53 } 54 55 return (0); 56 } 57 58 /* 59 * Sync memory to disk for the update log header. 60 */ 61 void 62 ulog_sync_header(kdb_hlog_t *ulog) 63 { 64 65 if (!pagesize) 66 pagesize = getpagesize(); 67 68 if (msync((caddr_t)ulog, pagesize, MS_SYNC)) { 69 /* 70 * Couldn't sync to disk, let's panic 71 */ 72 syslog(LOG_ERR, "ulog_sync_header: could not sync to disk"); 73 abort(); 74 } 75 } 76 77 /* 78 * Resizes the array elements. We reinitialize the update log rather than 79 * unrolling the the log and copying it over to a temporary log for obvious 80 * performance reasons. Slaves will subsequently do a full resync, but 81 * the need for resizing should be very small. 82 */ 83 krb5_error_code 84 ulog_resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd, uint_t recsize) 85 { 86 uint_t new_block, new_size; 87 88 if (ulog == NULL) 89 return (KRB5_LOG_ERROR); 90 91 new_size = sizeof (kdb_hlog_t); 92 93 new_block = (recsize / ULOG_BLOCK) + 1; 94 new_block *= ULOG_BLOCK; 95 96 new_size += ulogentries * new_block; 97 98 if (new_size <= MAXLOGLEN) { 99 /* 100 * Reinit log with new block size 101 */ 102 (void) memset(ulog, 0, sizeof (kdb_hlog_t)); 103 104 ulog->kdb_hmagic = KDB_HMAGIC; 105 ulog->db_version_num = KDB_VERSION; 106 ulog->kdb_state = KDB_STABLE; 107 ulog->kdb_block = new_block; 108 109 ulog_sync_header(ulog); 110 111 /* 112 * Time to expand log considering new block size 113 */ 114 if (lseek(ulogfd, new_size, SEEK_SET) == -1) { 115 return (errno); 116 } 117 118 if (write(ulogfd, "+", 1) != 1) { 119 return (errno); 120 } 121 } else { 122 /* 123 * Can't map into file larger than MAXLOGLEN 124 */ 125 return (KRB5_LOG_ERROR); 126 } 127 128 return (0); 129 } 130 131 /* 132 * Adds an entry to the update log. 133 * The layout of the update log looks like: 134 * 135 * header log -> [ update header -> xdr(kdb_incr_update_t) ], ... 136 */ 137 krb5_error_code 138 ulog_add_update(krb5_context context, kdb_incr_update_t *upd) 139 { 140 XDR xdrs; 141 kdbe_time_t ktime; 142 struct timeval timestamp; 143 kdb_ent_header_t *indx_log; 144 uint_t i, recsize; 145 ulong_t upd_size; 146 krb5_error_code retval; 147 kdb_sno_t cur_sno; 148 kdb_log_context *log_ctx; 149 kdb_hlog_t *ulog = NULL; 150 uint32_t ulogentries; 151 int ulogfd; 152 153 INIT_ULOG(context); 154 ulogentries = log_ctx->ulogentries; 155 ulogfd = log_ctx->ulogfd; 156 157 if (upd == NULL) 158 return (KRB5_LOG_ERROR); 159 160 (void) gettimeofday(×tamp, NULL); 161 ktime.seconds = timestamp.tv_sec; 162 ktime.useconds = timestamp.tv_usec; 163 164 upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd); 165 166 recsize = sizeof (kdb_ent_header_t) + upd_size; 167 168 if (recsize > ulog->kdb_block) { 169 if (retval = ulog_resize(ulog, ulogentries, ulogfd, recsize)) { 170 /* Resize element array failed */ 171 return (retval); 172 } 173 } 174 175 cur_sno = ulog->kdb_last_sno; 176 177 /* 178 * We need to overflow our sno, replicas will do full 179 * resyncs once they see their sno > than the masters. 180 */ 181 if (cur_sno == ULONG_MAX) 182 cur_sno = 1; 183 else 184 cur_sno++; 185 186 /* 187 * We squirrel this away for finish_update() to index 188 */ 189 upd->kdb_entry_sno = cur_sno; 190 191 i = (cur_sno - 1) % ulogentries; 192 193 indx_log = (kdb_ent_header_t *)INDEX(ulog, i); 194 195 (void) memset(indx_log, 0, ulog->kdb_block); 196 197 indx_log->kdb_umagic = KDB_UMAGIC; 198 indx_log->kdb_entry_size = upd_size; 199 indx_log->kdb_entry_sno = cur_sno; 200 indx_log->kdb_time = upd->kdb_time = ktime; 201 indx_log->kdb_commit = upd->kdb_commit = FALSE; 202 203 ulog->kdb_state = KDB_UNSTABLE; 204 205 xdrmem_create(&xdrs, (char *)indx_log->entry_data, 206 indx_log->kdb_entry_size, XDR_ENCODE); 207 if (!xdr_kdb_incr_update_t(&xdrs, upd)) 208 return (KRB5_LOG_CONV); 209 210 if (retval = ulog_sync_update(ulog, indx_log)) 211 return (retval); 212 213 if (ulog->kdb_num < ulogentries) 214 ulog->kdb_num++; 215 216 ulog->kdb_last_sno = cur_sno; 217 ulog->kdb_last_time = ktime; 218 219 /* 220 * Since this is a circular array, once we circled, kdb_first_sno is 221 * always kdb_entry_sno + 1. 222 */ 223 if (cur_sno > ulogentries) { 224 i = upd->kdb_entry_sno % ulogentries; 225 indx_log = (kdb_ent_header_t *)INDEX(ulog, i); 226 ulog->kdb_first_sno = indx_log->kdb_entry_sno; 227 ulog->kdb_first_time = indx_log->kdb_time; 228 } else if (cur_sno == 1) { 229 ulog->kdb_first_sno = 1; 230 ulog->kdb_first_time = indx_log->kdb_time; 231 } 232 233 ulog_sync_header(ulog); 234 235 return (0); 236 } 237 238 /* 239 * Mark the log entry as committed and sync the memory mapped log 240 * to file. 241 */ 242 krb5_error_code 243 ulog_finish_update(krb5_context context, kdb_incr_update_t *upd) 244 { 245 krb5_error_code retval; 246 kdb_ent_header_t *indx_log; 247 uint_t i; 248 kdb_log_context *log_ctx; 249 kdb_hlog_t *ulog = NULL; 250 uint32_t ulogentries; 251 252 INIT_ULOG(context); 253 ulogentries = log_ctx->ulogentries; 254 255 i = (upd->kdb_entry_sno - 1) % ulogentries; 256 257 indx_log = (kdb_ent_header_t *)INDEX(ulog, i); 258 259 indx_log->kdb_commit = TRUE; 260 261 ulog->kdb_state = KDB_STABLE; 262 263 if (retval = ulog_sync_update(ulog, indx_log)) 264 return (retval); 265 266 ulog_sync_header(ulog); 267 268 return (0); 269 } 270 271 /* 272 * Set the header log details on the slave and sync it to file. 273 */ 274 void 275 ulog_finish_update_slave(kdb_hlog_t *ulog, kdb_last_t lastentry) 276 { 277 278 ulog->kdb_last_sno = lastentry.last_sno; 279 ulog->kdb_last_time = lastentry.last_time; 280 281 ulog_sync_header(ulog); 282 } 283 284 /* 285 * Delete an entry to the update log. 286 */ 287 krb5_error_code 288 ulog_delete_update(krb5_context context, kdb_incr_update_t *upd) 289 { 290 291 upd->kdb_deleted = TRUE; 292 293 return (ulog_add_update(context, upd)); 294 } 295 296 /* 297 * Used by the slave or master (during ulog_check) to update it's hash db from 298 * the incr update log. 299 */ 300 krb5_error_code 301 ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret) 302 { 303 krb5_db_entry *entry = NULL; 304 kdb_incr_update_t *upd = NULL, *fupd; 305 int i, no_of_updates; 306 krb5_error_code retval; 307 krb5_principal dbprinc = NULL; 308 kdb_last_t errlast; 309 char *dbprincstr = NULL; 310 kdb_log_context *log_ctx; 311 kdb_hlog_t *ulog = NULL; 312 313 INIT_ULOG(context); 314 315 no_of_updates = incr_ret->updates.kdb_ulog_t_len; 316 upd = incr_ret->updates.kdb_ulog_t_val; 317 fupd = upd; 318 319 /* 320 * We reset last_sno and last_time to 0, if krb5_db_put_principal 321 * or krb5_db_delete_principal fail. 322 */ 323 errlast.last_sno = (unsigned int)0; 324 errlast.last_time.seconds = (unsigned int)0; 325 errlast.last_time.useconds = (unsigned int)0; 326 327 if ((retval = krb5_db_inited(context))) 328 goto cleanup; 329 330 for (i = 0; i < no_of_updates; i++) { 331 int nentry = 1; 332 333 if (!upd->kdb_commit) 334 continue; 335 336 if (upd->kdb_deleted) { 337 dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len 338 + 1) * sizeof (char)); 339 340 if (dbprincstr == NULL) { 341 retval = ENOMEM; 342 goto cleanup; 343 } 344 345 (void) strlcpy(dbprincstr, 346 (char *)upd->kdb_princ_name.utf8str_t_val, 347 (upd->kdb_princ_name.utf8str_t_len + 1)); 348 349 if (retval = krb5_parse_name(context, dbprincstr, 350 &dbprinc)) { 351 goto cleanup; 352 } 353 354 if (dbprincstr) 355 free(dbprincstr); 356 357 retval = krb5_db_delete_principal(context, 358 dbprinc, &nentry); 359 360 if (dbprinc) 361 krb5_free_principal(context, dbprinc); 362 363 if (retval) 364 goto cleanup; 365 } else { 366 entry = (krb5_db_entry *)malloc(sizeof (krb5_db_entry)); 367 368 if (!entry) { 369 retval = errno; 370 goto cleanup; 371 } 372 373 (void) memset(entry, 0, sizeof (krb5_db_entry)); 374 375 if (retval = ulog_conv_2dbentry(context, entry, upd, 1)) 376 goto cleanup; 377 378 retval = krb5_db_put_principal(context, entry, 379 &nentry); 380 381 if (entry) { 382 krb5_db_free_principal(context, entry, nentry); 383 free(entry); 384 entry = NULL; 385 } 386 if (retval) 387 goto cleanup; 388 } 389 390 upd++; 391 } 392 393 cleanup: 394 if (fupd) 395 ulog_free_entries(fupd, no_of_updates); 396 397 if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) { 398 if (retval) 399 ulog_finish_update_slave(ulog, errlast); 400 else 401 ulog_finish_update_slave(ulog, incr_ret->lastentry); 402 } 403 404 return (retval); 405 } 406 407 /* 408 * Validate the log file and resync any uncommitted update entries 409 * to the principal database. 410 */ 411 krb5_error_code 412 ulog_check(krb5_context context, kdb_hlog_t *ulog) 413 { 414 XDR xdrs; 415 krb5_error_code retval = 0; 416 int i; 417 kdb_ent_header_t *indx_log; 418 kdb_incr_update_t *upd = NULL; 419 kdb_incr_result_t *incr_ret = NULL; 420 421 ulog->kdb_state = KDB_STABLE; 422 423 for (i = 0; i < ulog->kdb_num; i++) { 424 indx_log = (kdb_ent_header_t *)INDEX(ulog, i); 425 426 if (indx_log->kdb_umagic != KDB_UMAGIC) { 427 /* 428 * Update entry corrupted we should scream and die 429 */ 430 ulog->kdb_state = KDB_CORRUPT; 431 retval = KRB5_LOG_CORRUPT; 432 break; 433 } 434 435 if (indx_log->kdb_commit == FALSE) { 436 ulog->kdb_state = KDB_UNSTABLE; 437 438 incr_ret = (kdb_incr_result_t *) 439 malloc(sizeof (kdb_incr_result_t)); 440 if (incr_ret == NULL) { 441 retval = errno; 442 goto error; 443 } 444 445 upd = (kdb_incr_update_t *) 446 malloc(sizeof (kdb_incr_update_t)); 447 if (upd == NULL) { 448 retval = errno; 449 goto error; 450 } 451 452 (void) memset(upd, 0, sizeof (kdb_incr_update_t)); 453 xdrmem_create(&xdrs, (char *)indx_log->entry_data, 454 indx_log->kdb_entry_size, XDR_DECODE); 455 if (!xdr_kdb_incr_update_t(&xdrs, upd)) { 456 retval = KRB5_LOG_CONV; 457 goto error; 458 } 459 460 incr_ret->updates.kdb_ulog_t_len = 1; 461 incr_ret->updates.kdb_ulog_t_val = upd; 462 463 upd->kdb_commit = TRUE; 464 465 /* 466 * We don't want to readd this update and just use the 467 * existing update to be propagated later on 468 */ 469 ulog_set_role(context, IPROP_NULL); 470 retval = ulog_replay(context, incr_ret); 471 472 /* 473 * upd was freed by ulog_replay, we NULL 474 * the pointer in case we subsequently break from loop. 475 */ 476 upd = NULL; 477 if (incr_ret) { 478 free(incr_ret); 479 incr_ret = NULL; 480 } 481 ulog_set_role(context, IPROP_MASTER); 482 483 if (retval) 484 goto error; 485 486 /* 487 * We flag this as committed since this was 488 * the last entry before kadmind crashed, ergo 489 * the slaves have not seen this update before 490 */ 491 indx_log->kdb_commit = TRUE; 492 retval = ulog_sync_update(ulog, indx_log); 493 if (retval) 494 goto error; 495 496 ulog->kdb_state = KDB_STABLE; 497 } 498 } 499 500 error: 501 if (upd) 502 ulog_free_entries(upd, 1); 503 504 if (incr_ret) 505 free(incr_ret); 506 507 ulog_sync_header(ulog); 508 509 return (retval); 510 } 511 512 /* 513 * Map the log file to memory for performance and simplicity. 514 * 515 * Called by: if iprop_enabled then ulog_map(); 516 * Assumes that the caller will terminate on ulog_map, hence munmap and 517 * closing of the fd are implicitly performed by the caller. 518 * Returns 0 on success else failure. 519 */ 520 krb5_error_code 521 ulog_map(krb5_context context, kadm5_config_params *params, int caller) 522 { 523 struct stat st; 524 krb5_error_code retval; 525 uint32_t ulog_filesize; 526 char logname[MAX_FILENAME]; 527 kdb_log_context *log_ctx; 528 kdb_hlog_t *ulog = NULL; 529 uint32_t ulogentries; 530 int ulogfd = -1; 531 532 if ((caller == FKADMIND) || (caller == FKCOMMAND)) 533 ulogentries = params->iprop_ulogsize; 534 535 ulog_filesize = sizeof (kdb_hlog_t); 536 537 if (strlcpy(logname, params->dbname, MAX_FILENAME) >= MAX_FILENAME) 538 return (KRB5_LOG_ERROR); 539 if (strlcat(logname, ".ulog", MAX_FILENAME) >= MAX_FILENAME) 540 return (KRB5_LOG_ERROR); 541 542 if (stat(logname, &st) == -1) { 543 544 if (caller == FKPROPLOG) { 545 /* 546 * File doesn't exist so we exit with kproplog 547 */ 548 return (errno); 549 } 550 551 if ((ulogfd = open(logname, O_RDWR+O_CREAT, 0600)) == -1) { 552 return (errno); 553 } 554 555 if (lseek(ulogfd, 0L, SEEK_CUR) == -1) { 556 return (errno); 557 } 558 559 if ((caller == FKADMIND) || (caller == FKCOMMAND)) 560 ulog_filesize += ulogentries * ULOG_BLOCK; 561 562 if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) { 563 return (errno); 564 } 565 566 if (write(ulogfd, "+", 1) != 1) { 567 return (errno); 568 } 569 570 } else { 571 572 if ((ulogfd = open(logname, O_RDWR, 0600)) == -1) { 573 /* 574 * Can't open existing log file 575 */ 576 return (errno); 577 } 578 } 579 580 if (caller == FKPROPLOG) { 581 fstat(ulogfd, &st); 582 ulog_filesize = st.st_size; 583 584 ulog = (kdb_hlog_t *)mmap(0, ulog_filesize, 585 PROT_READ+PROT_WRITE, MAP_PRIVATE, ulogfd, 0); 586 } else { 587 /* 588 * else kadmind, kpropd, & kcommands should udpate stores 589 */ 590 ulog = (kdb_hlog_t *)mmap(0, MAXLOGLEN, 591 PROT_READ+PROT_WRITE, MAP_SHARED, ulogfd, 0); 592 } 593 594 if ((int)(ulog) == -1) { 595 /* 596 * Can't map update log file to memory 597 */ 598 return (errno); 599 } 600 601 if (!context->kdblog_context) { 602 if (!(log_ctx = malloc(sizeof (kdb_log_context)))) 603 return (errno); 604 context->kdblog_context = (void *)log_ctx; 605 } else 606 log_ctx = context->kdblog_context; 607 log_ctx->ulog = ulog; 608 log_ctx->ulogentries = ulogentries; 609 log_ctx->ulogfd = ulogfd; 610 611 if (ulog->kdb_hmagic != KDB_HMAGIC) { 612 if (ulog->kdb_hmagic == 0) { 613 /* 614 * New update log 615 */ 616 (void) memset(ulog, 0, sizeof (kdb_hlog_t)); 617 618 ulog->kdb_hmagic = KDB_HMAGIC; 619 ulog->db_version_num = KDB_VERSION; 620 ulog->kdb_state = KDB_STABLE; 621 ulog->kdb_block = ULOG_BLOCK; 622 if (!(caller == FKPROPLOG)) 623 ulog_sync_header(ulog); 624 } else { 625 return (KRB5_LOG_CORRUPT); 626 } 627 } 628 629 if (caller == FKADMIND) { 630 switch (ulog->kdb_state) { 631 case KDB_STABLE: 632 case KDB_UNSTABLE: 633 /* 634 * Log is currently un/stable, check anyway 635 */ 636 retval = ulog_check(context, ulog); 637 if (retval == KRB5_LOG_CORRUPT) { 638 return (retval); 639 } 640 break; 641 case KDB_CORRUPT: 642 return (KRB5_LOG_CORRUPT); 643 default: 644 /* 645 * Invalid db state 646 */ 647 return (KRB5_LOG_ERROR); 648 } 649 } else if ((caller == FKPROPLOG) || (caller == FKPROPD)) { 650 /* 651 * kproplog and kpropd don't need to do anything else 652 */ 653 return (0); 654 } 655 656 /* 657 * Reinit ulog if the log is being truncated or expanded after 658 * we have circled. 659 */ 660 if (ulog->kdb_num != ulogentries) { 661 if ((ulog->kdb_num != 0) && 662 ((ulog->kdb_last_sno > ulog->kdb_num) || 663 (ulog->kdb_num > ulogentries))) { 664 (void) memset(ulog, 0, sizeof (kdb_hlog_t)); 665 666 ulog->kdb_hmagic = KDB_HMAGIC; 667 ulog->db_version_num = KDB_VERSION; 668 ulog->kdb_state = KDB_STABLE; 669 ulog->kdb_block = ULOG_BLOCK; 670 671 ulog_sync_header(ulog); 672 } 673 674 /* 675 * Expand ulog if we have specified a greater size 676 */ 677 if (ulog->kdb_num < ulogentries) { 678 ulog_filesize += ulogentries * ulog->kdb_block; 679 680 if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) { 681 return (errno); 682 } 683 684 if (write(ulogfd, "+", 1) != 1) { 685 return (errno); 686 } 687 } 688 } 689 690 return (0); 691 } 692 693 /* 694 * Get the last set of updates seen, (last+1) to n is returned. 695 */ 696 krb5_error_code 697 ulog_get_entries( 698 krb5_context context, /* input - krb5 lib config */ 699 kdb_last_t last, /* input - slave's last sno */ 700 kdb_incr_result_t *ulog_handle) /* output - incr result for slave */ 701 { 702 XDR xdrs; 703 kdb_ent_header_t *indx_log; 704 kdb_incr_update_t *upd; 705 uint_t indx, count, tdiff; 706 uint32_t sno; 707 krb5_error_code retval; 708 struct timeval timestamp; 709 kdb_log_context *log_ctx; 710 kdb_hlog_t *ulog = NULL; 711 uint32_t ulogentries; 712 713 INIT_ULOG(context); 714 ulogentries = log_ctx->ulogentries; 715 716 /* 717 * Check to make sure we don't have a corrupt ulog first. 718 */ 719 if (ulog->kdb_state == KDB_CORRUPT) { 720 ulog_handle->ret = UPDATE_ERROR; 721 return (KRB5_LOG_CORRUPT); 722 } 723 724 gettimeofday(×tamp, NULL); 725 726 tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds; 727 if (tdiff <= ULOG_IDLE_TIME) { 728 ulog_handle->ret = UPDATE_BUSY; 729 return (0); 730 } 731 732 /* 733 * We need to lock out other processes here, such as kadmin.local, 734 * since we are looking at the last_sno and looking up updates. So 735 * we can share with other readers. 736 */ 737 retval = krb5_db_lock(context, KRB5_LOCKMODE_SHARED); 738 if (retval) 739 return (retval); 740 741 /* 742 * We may have overflowed the update log or we shrunk the log, or 743 * the client's ulog has just been created. 744 */ 745 if ((last.last_sno > ulog->kdb_last_sno) || 746 (last.last_sno < ulog->kdb_first_sno) || 747 (last.last_sno == 0)) { 748 ulog_handle->lastentry.last_sno = ulog->kdb_last_sno; 749 (void) krb5_db_unlock(context); 750 ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED; 751 return (0); 752 } else if (last.last_sno <= ulog->kdb_last_sno) { 753 sno = last.last_sno; 754 755 indx = (sno - 1) % ulogentries; 756 757 indx_log = (kdb_ent_header_t *)INDEX(ulog, indx); 758 759 /* 760 * Validate the time stamp just to make sure it was the same sno 761 */ 762 if ((indx_log->kdb_time.seconds == last.last_time.seconds) && 763 (indx_log->kdb_time.useconds == last.last_time.useconds)) { 764 765 /* 766 * If we have the same sno we return success 767 */ 768 if (last.last_sno == ulog->kdb_last_sno) { 769 (void) krb5_db_unlock(context); 770 ulog_handle->ret = UPDATE_NIL; 771 return (0); 772 } 773 774 count = ulog->kdb_last_sno - sno; 775 776 ulog_handle->updates.kdb_ulog_t_val = 777 (kdb_incr_update_t *)malloc( 778 sizeof (kdb_incr_update_t) * count); 779 780 upd = ulog_handle->updates.kdb_ulog_t_val; 781 782 if (upd == NULL) { 783 (void) krb5_db_unlock(context); 784 ulog_handle->ret = UPDATE_ERROR; 785 return (errno); 786 } 787 788 while (sno < ulog->kdb_last_sno) { 789 indx = sno % ulogentries; 790 791 indx_log = (kdb_ent_header_t *) 792 INDEX(ulog, indx); 793 794 (void) memset(upd, 0, 795 sizeof (kdb_incr_update_t)); 796 xdrmem_create(&xdrs, 797 (char *)indx_log->entry_data, 798 indx_log->kdb_entry_size, XDR_DECODE); 799 if (!xdr_kdb_incr_update_t(&xdrs, upd)) { 800 (void) krb5_db_unlock(context); 801 ulog_handle->ret = UPDATE_ERROR; 802 return (KRB5_LOG_CONV); 803 } 804 /* 805 * Mark commitment since we didn't 806 * want to decode and encode the 807 * incr update record the first time. 808 */ 809 upd->kdb_commit = indx_log->kdb_commit; 810 811 upd++; 812 sno++; 813 } /* while */ 814 815 ulog_handle->updates.kdb_ulog_t_len = count; 816 817 ulog_handle->lastentry.last_sno = ulog->kdb_last_sno; 818 ulog_handle->lastentry.last_time.seconds = 819 ulog->kdb_last_time.seconds; 820 ulog_handle->lastentry.last_time.useconds = 821 ulog->kdb_last_time.useconds; 822 ulog_handle->ret = UPDATE_OK; 823 824 (void) krb5_db_unlock(context); 825 826 return (0); 827 } else { 828 /* 829 * We have time stamp mismatch or we no longer have 830 * the slave's last sno, so we brute force it 831 */ 832 (void) krb5_db_unlock(context); 833 ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED; 834 835 return (0); 836 } 837 } 838 839 /* 840 * Should never get here, return error 841 */ 842 ulog_handle->ret = UPDATE_ERROR; 843 return (KRB5_LOG_ERROR); 844 } 845 846 krb5_error_code 847 ulog_set_role(krb5_context ctx, iprop_role role) 848 { 849 kdb_log_context *log_ctx; 850 851 if (!ctx->kdblog_context) { 852 if (!(log_ctx = malloc(sizeof (kdb_log_context)))) 853 return (errno); 854 ctx->kdblog_context = (void *)log_ctx; 855 } else 856 log_ctx = ctx->kdblog_context; 857 858 log_ctx->iproprole = role; 859 860 return (0); 861 } 862