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
ulog_sync_update(kdb_hlog_t * ulog,kdb_ent_header_t * upd)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
ulog_sync_header(kdb_hlog_t * ulog)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
ulog_resize(kdb_hlog_t * ulog,uint32_t ulogentries,int ulogfd,uint_t recsize)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
ulog_add_update(krb5_context context,kdb_incr_update_t * upd)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
ulog_finish_update(krb5_context context,kdb_incr_update_t * upd)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
ulog_finish_update_slave(kdb_hlog_t * ulog,kdb_last_t lastentry)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
ulog_delete_update(krb5_context context,kdb_incr_update_t * upd)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
ulog_replay(krb5_context context,kdb_incr_result_t * incr_ret)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
ulog_check(krb5_context context,kdb_hlog_t * ulog)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
ulog_map(krb5_context context,kadm5_config_params * params,int caller)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
ulog_get_entries(krb5_context context,kdb_last_t last,kdb_incr_result_t * ulog_handle)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
ulog_set_role(krb5_context ctx,iprop_role role)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