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