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 bool_t fini = FALSE; 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_db_put_principal 322 * or krb5_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 (krb5_db_inited(context)) { 329 retval = krb5_db_open(context, NULL, 330 KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN); 331 if (retval != 0) 332 goto cleanup; 333 fini = TRUE; 334 } 335 336 for (i = 0; i < no_of_updates; i++) { 337 int nentry = 1; 338 339 if (!upd->kdb_commit) 340 continue; 341 342 if (upd->kdb_deleted) { 343 dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len 344 + 1) * sizeof (char)); 345 346 if (dbprincstr == NULL) { 347 retval = ENOMEM; 348 goto cleanup; 349 } 350 351 (void) strlcpy(dbprincstr, 352 (char *)upd->kdb_princ_name.utf8str_t_val, 353 (upd->kdb_princ_name.utf8str_t_len + 1)); 354 355 if (retval = krb5_parse_name(context, dbprincstr, 356 &dbprinc)) { 357 goto cleanup; 358 } 359 360 if (dbprincstr) 361 free(dbprincstr); 362 363 retval = krb5_db_delete_principal(context, 364 dbprinc, &nentry); 365 366 if (dbprinc) 367 krb5_free_principal(context, dbprinc); 368 369 if (retval) 370 goto cleanup; 371 } else { 372 entry = (krb5_db_entry *)malloc(sizeof (krb5_db_entry)); 373 374 if (!entry) { 375 retval = errno; 376 goto cleanup; 377 } 378 379 (void) memset(entry, 0, sizeof (krb5_db_entry)); 380 381 if (retval = ulog_conv_2dbentry(context, entry, upd, 1)) 382 goto cleanup; 383 384 retval = krb5_db_put_principal(context, entry, 385 &nentry); 386 387 if (entry) { 388 krb5_db_free_principal(context, entry, nentry); 389 free(entry); 390 entry = NULL; 391 } 392 if (retval) 393 goto cleanup; 394 } 395 396 upd++; 397 } 398 399 cleanup: 400 if (fupd) 401 ulog_free_entries(fupd, no_of_updates); 402 403 if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) { 404 if (retval) 405 ulog_finish_update_slave(ulog, errlast); 406 else 407 ulog_finish_update_slave(ulog, incr_ret->lastentry); 408 } 409 410 if (fini == TRUE) 411 krb5_db_fini(context); 412 413 return (retval); 414 } 415 416 /* 417 * Validate the log file and resync any uncommitted update entries 418 * to the principal database. 419 */ 420 krb5_error_code 421 ulog_check(krb5_context context, kdb_hlog_t *ulog) 422 { 423 XDR xdrs; 424 krb5_error_code retval = 0; 425 int i; 426 kdb_ent_header_t *indx_log; 427 kdb_incr_update_t *upd = NULL; 428 kdb_incr_result_t *incr_ret = NULL; 429 430 ulog->kdb_state = KDB_STABLE; 431 432 for (i = 0; i < ulog->kdb_num; i++) { 433 indx_log = (kdb_ent_header_t *)INDEX(ulog, i); 434 435 if (indx_log->kdb_umagic != KDB_UMAGIC) { 436 /* 437 * Update entry corrupted we should scream and die 438 */ 439 ulog->kdb_state = KDB_CORRUPT; 440 retval = KRB5_LOG_CORRUPT; 441 break; 442 } 443 444 if (indx_log->kdb_commit == FALSE) { 445 ulog->kdb_state = KDB_UNSTABLE; 446 447 incr_ret = (kdb_incr_result_t *) 448 malloc(sizeof (kdb_incr_result_t)); 449 if (incr_ret == NULL) { 450 retval = errno; 451 goto error; 452 } 453 454 upd = (kdb_incr_update_t *) 455 malloc(sizeof (kdb_incr_update_t)); 456 if (upd == NULL) { 457 retval = errno; 458 goto error; 459 } 460 461 (void) memset(upd, 0, sizeof (kdb_incr_update_t)); 462 xdrmem_create(&xdrs, (char *)indx_log->entry_data, 463 indx_log->kdb_entry_size, XDR_DECODE); 464 if (!xdr_kdb_incr_update_t(&xdrs, upd)) { 465 retval = KRB5_LOG_CONV; 466 goto error; 467 } 468 469 incr_ret->updates.kdb_ulog_t_len = 1; 470 incr_ret->updates.kdb_ulog_t_val = upd; 471 472 upd->kdb_commit = TRUE; 473 474 /* 475 * We don't want to readd this update and just use the 476 * existing update to be propagated later on 477 */ 478 ulog_set_role(context, IPROP_NULL); 479 retval = ulog_replay(context, incr_ret); 480 481 /* 482 * upd was freed by ulog_replay, we NULL 483 * the pointer in case we subsequently break from loop. 484 */ 485 upd = NULL; 486 if (incr_ret) { 487 free(incr_ret); 488 incr_ret = NULL; 489 } 490 ulog_set_role(context, IPROP_MASTER); 491 492 if (retval) 493 goto error; 494 495 /* 496 * We flag this as committed since this was 497 * the last entry before kadmind crashed, ergo 498 * the slaves have not seen this update before 499 */ 500 indx_log->kdb_commit = TRUE; 501 retval = ulog_sync_update(ulog, indx_log); 502 if (retval) 503 goto error; 504 505 ulog->kdb_state = KDB_STABLE; 506 } 507 } 508 509 error: 510 if (upd) 511 ulog_free_entries(upd, 1); 512 513 if (incr_ret) 514 free(incr_ret); 515 516 ulog_sync_header(ulog); 517 518 return (retval); 519 } 520 521 /* 522 * Map the log file to memory for performance and simplicity. 523 * 524 * Called by: if iprop_enabled then ulog_map(); 525 * Assumes that the caller will terminate on ulog_map, hence munmap and 526 * closing of the fd are implicitly performed by the caller. 527 * Returns 0 on success else failure. 528 */ 529 krb5_error_code 530 ulog_map(krb5_context context, kadm5_config_params *params, int caller) 531 { 532 struct stat st; 533 krb5_error_code retval; 534 uint32_t ulog_filesize; 535 char logname[MAX_FILENAME]; 536 kdb_log_context *log_ctx; 537 kdb_hlog_t *ulog = NULL; 538 uint32_t ulogentries; 539 int ulogfd = -1; 540 541 if ((caller == FKADMIND) || (caller == FKCOMMAND)) 542 ulogentries = params->iprop_ulogsize; 543 544 ulog_filesize = sizeof (kdb_hlog_t); 545 546 if (strlcpy(logname, params->dbname, MAX_FILENAME) >= MAX_FILENAME) 547 return (KRB5_LOG_ERROR); 548 if (strlcat(logname, ".ulog", MAX_FILENAME) >= MAX_FILENAME) 549 return (KRB5_LOG_ERROR); 550 551 if (stat(logname, &st) == -1) { 552 553 if (caller == FKPROPLOG) { 554 /* 555 * File doesn't exist so we exit with kproplog 556 */ 557 return (errno); 558 } 559 560 if ((ulogfd = open(logname, O_RDWR+O_CREAT, 0600)) == -1) { 561 return (errno); 562 } 563 564 if (lseek(ulogfd, 0L, SEEK_CUR) == -1) { 565 return (errno); 566 } 567 568 if ((caller == FKADMIND) || (caller == FKCOMMAND)) 569 ulog_filesize += ulogentries * ULOG_BLOCK; 570 571 if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) { 572 return (errno); 573 } 574 575 if (write(ulogfd, "+", 1) != 1) { 576 return (errno); 577 } 578 579 } else { 580 581 if ((ulogfd = open(logname, O_RDWR, 0600)) == -1) { 582 /* 583 * Can't open existing log file 584 */ 585 return (errno); 586 } 587 } 588 589 if (caller == FKPROPLOG) { 590 fstat(ulogfd, &st); 591 ulog_filesize = st.st_size; 592 593 ulog = (kdb_hlog_t *)mmap(0, ulog_filesize, 594 PROT_READ+PROT_WRITE, MAP_PRIVATE, ulogfd, 0); 595 } else { 596 /* 597 * else kadmind, kpropd, & kcommands should udpate stores 598 */ 599 ulog = (kdb_hlog_t *)mmap(0, MAXLOGLEN, 600 PROT_READ+PROT_WRITE, MAP_SHARED, ulogfd, 0); 601 } 602 603 if ((int)(ulog) == -1) { 604 /* 605 * Can't map update log file to memory 606 */ 607 return (errno); 608 } 609 610 if (!context->kdblog_context) { 611 if (!(log_ctx = malloc(sizeof (kdb_log_context)))) 612 return (errno); 613 context->kdblog_context = (void *)log_ctx; 614 } else 615 log_ctx = context->kdblog_context; 616 log_ctx->ulog = ulog; 617 log_ctx->ulogentries = ulogentries; 618 log_ctx->ulogfd = ulogfd; 619 620 if (ulog->kdb_hmagic != KDB_HMAGIC) { 621 if (ulog->kdb_hmagic == 0) { 622 /* 623 * New update log 624 */ 625 (void) memset(ulog, 0, sizeof (kdb_hlog_t)); 626 627 ulog->kdb_hmagic = KDB_HMAGIC; 628 ulog->db_version_num = KDB_VERSION; 629 ulog->kdb_state = KDB_STABLE; 630 ulog->kdb_block = ULOG_BLOCK; 631 if (!(caller == FKPROPLOG)) 632 ulog_sync_header(ulog); 633 } else { 634 return (KRB5_LOG_CORRUPT); 635 } 636 } 637 638 if (caller == FKADMIND) { 639 switch (ulog->kdb_state) { 640 case KDB_STABLE: 641 case KDB_UNSTABLE: 642 /* 643 * Log is currently un/stable, check anyway 644 */ 645 retval = ulog_check(context, ulog); 646 if (retval == KRB5_LOG_CORRUPT) { 647 return (retval); 648 } 649 break; 650 case KDB_CORRUPT: 651 return (KRB5_LOG_CORRUPT); 652 default: 653 /* 654 * Invalid db state 655 */ 656 return (KRB5_LOG_ERROR); 657 } 658 } else if ((caller == FKPROPLOG) || (caller == FKPROPD)) { 659 /* 660 * kproplog and kpropd don't need to do anything else 661 */ 662 return (0); 663 } 664 665 /* 666 * Reinit ulog if the log is being truncated or expanded after 667 * we have circled. 668 */ 669 if (ulog->kdb_num != ulogentries) { 670 if ((ulog->kdb_num != 0) && 671 ((ulog->kdb_last_sno > ulog->kdb_num) || 672 (ulog->kdb_num > ulogentries))) { 673 (void) memset(ulog, 0, sizeof (kdb_hlog_t)); 674 675 ulog->kdb_hmagic = KDB_HMAGIC; 676 ulog->db_version_num = KDB_VERSION; 677 ulog->kdb_state = KDB_STABLE; 678 ulog->kdb_block = ULOG_BLOCK; 679 680 ulog_sync_header(ulog); 681 } 682 683 /* 684 * Expand ulog if we have specified a greater size 685 */ 686 if (ulog->kdb_num < ulogentries) { 687 ulog_filesize += ulogentries * ulog->kdb_block; 688 689 if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) { 690 return (errno); 691 } 692 693 if (write(ulogfd, "+", 1) != 1) { 694 return (errno); 695 } 696 } 697 } 698 699 return (0); 700 } 701 702 /* 703 * Get the last set of updates seen, (last+1) to n is returned. 704 */ 705 krb5_error_code 706 ulog_get_entries( 707 krb5_context context, /* input - krb5 lib config */ 708 kdb_last_t last, /* input - slave's last sno */ 709 kdb_incr_result_t *ulog_handle) /* output - incr result for slave */ 710 { 711 XDR xdrs; 712 kdb_ent_header_t *indx_log; 713 kdb_incr_update_t *upd; 714 uint_t indx, count, tdiff; 715 uint32_t sno; 716 krb5_error_code retval; 717 struct timeval timestamp; 718 kdb_log_context *log_ctx; 719 kdb_hlog_t *ulog = NULL; 720 uint32_t ulogentries; 721 722 INIT_ULOG(context); 723 ulogentries = log_ctx->ulogentries; 724 725 /* 726 * Check to make sure we don't have a corrupt ulog first. 727 */ 728 if (ulog->kdb_state == KDB_CORRUPT) { 729 ulog_handle->ret = UPDATE_ERROR; 730 return (KRB5_LOG_CORRUPT); 731 } 732 733 gettimeofday(×tamp, NULL); 734 735 tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds; 736 if (tdiff <= ULOG_IDLE_TIME) { 737 ulog_handle->ret = UPDATE_BUSY; 738 return (0); 739 } 740 741 /* 742 * We need to lock out other processes here, such as kadmin.local, 743 * since we are looking at the last_sno and looking up updates. So 744 * we can share with other readers. 745 */ 746 retval = krb5_db_lock(context, KRB5_LOCKMODE_SHARED); 747 if (retval) 748 return (retval); 749 750 /* 751 * We may have overflowed the update log or we shrunk the log, or 752 * the client's ulog has just been created. 753 */ 754 if ((last.last_sno > ulog->kdb_last_sno) || 755 (last.last_sno < ulog->kdb_first_sno) || 756 (last.last_sno == 0)) { 757 ulog_handle->lastentry.last_sno = ulog->kdb_last_sno; 758 (void) krb5_db_unlock(context); 759 ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED; 760 return (0); 761 } else if (last.last_sno <= ulog->kdb_last_sno) { 762 sno = last.last_sno; 763 764 indx = (sno - 1) % ulogentries; 765 766 indx_log = (kdb_ent_header_t *)INDEX(ulog, indx); 767 768 /* 769 * Validate the time stamp just to make sure it was the same sno 770 */ 771 if ((indx_log->kdb_time.seconds == last.last_time.seconds) && 772 (indx_log->kdb_time.useconds == last.last_time.useconds)) { 773 774 /* 775 * If we have the same sno we return success 776 */ 777 if (last.last_sno == ulog->kdb_last_sno) { 778 (void) krb5_db_unlock(context); 779 ulog_handle->ret = UPDATE_NIL; 780 return (0); 781 } 782 783 count = ulog->kdb_last_sno - sno; 784 785 ulog_handle->updates.kdb_ulog_t_val = 786 (kdb_incr_update_t *)malloc( 787 sizeof (kdb_incr_update_t) * count); 788 789 upd = ulog_handle->updates.kdb_ulog_t_val; 790 791 if (upd == NULL) { 792 (void) krb5_db_unlock(context); 793 ulog_handle->ret = UPDATE_ERROR; 794 return (errno); 795 } 796 797 while (sno < ulog->kdb_last_sno) { 798 indx = sno % ulogentries; 799 800 indx_log = (kdb_ent_header_t *) 801 INDEX(ulog, indx); 802 803 (void) memset(upd, 0, 804 sizeof (kdb_incr_update_t)); 805 xdrmem_create(&xdrs, 806 (char *)indx_log->entry_data, 807 indx_log->kdb_entry_size, XDR_DECODE); 808 if (!xdr_kdb_incr_update_t(&xdrs, upd)) { 809 (void) krb5_db_unlock(context); 810 ulog_handle->ret = UPDATE_ERROR; 811 return (KRB5_LOG_CONV); 812 } 813 /* 814 * Mark commitment since we didn't 815 * want to decode and encode the 816 * incr update record the first time. 817 */ 818 upd->kdb_commit = indx_log->kdb_commit; 819 820 upd++; 821 sno++; 822 } /* while */ 823 824 ulog_handle->updates.kdb_ulog_t_len = count; 825 826 ulog_handle->lastentry.last_sno = ulog->kdb_last_sno; 827 ulog_handle->lastentry.last_time.seconds = 828 ulog->kdb_last_time.seconds; 829 ulog_handle->lastentry.last_time.useconds = 830 ulog->kdb_last_time.useconds; 831 ulog_handle->ret = UPDATE_OK; 832 833 (void) krb5_db_unlock(context); 834 835 return (0); 836 } else { 837 /* 838 * We have time stamp mismatch or we no longer have 839 * the slave's last sno, so we brute force it 840 */ 841 (void) krb5_db_unlock(context); 842 ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED; 843 844 return (0); 845 } 846 } 847 848 /* 849 * Should never get here, return error 850 */ 851 ulog_handle->ret = UPDATE_ERROR; 852 return (KRB5_LOG_ERROR); 853 } 854 855 krb5_error_code 856 ulog_set_role(krb5_context ctx, iprop_role role) 857 { 858 kdb_log_context *log_ctx; 859 860 if (!ctx->kdblog_context) { 861 if (!(log_ctx = malloc(sizeof (kdb_log_context)))) 862 return (errno); 863 ctx->kdblog_context = (void *)log_ctx; 864 } else 865 log_ctx = ctx->kdblog_context; 866 867 log_ctx->iproprole = role; 868 869 return (0); 870 } 871