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