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