xref: /onnv-gate/usr/src/lib/krb5/kdb/kdb_log.c (revision 5201:e97cfd888955)
10Sstevel@tonic-gate /*
24960Swillf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate 
80Sstevel@tonic-gate #include <sys/stat.h>
90Sstevel@tonic-gate #include <sys/types.h>
100Sstevel@tonic-gate #include <unistd.h>
110Sstevel@tonic-gate #include <fcntl.h>
120Sstevel@tonic-gate #include <sys/mman.h>
130Sstevel@tonic-gate #include <k5-int.h>
140Sstevel@tonic-gate #include <stdlib.h>
150Sstevel@tonic-gate #include <limits.h>
160Sstevel@tonic-gate #include <syslog.h>
170Sstevel@tonic-gate #include "kdb_log.h"
180Sstevel@tonic-gate 
190Sstevel@tonic-gate /*
200Sstevel@tonic-gate  * This modules includes all the necessary functions that create and
210Sstevel@tonic-gate  * modify the Kerberos principal update and header logs.
220Sstevel@tonic-gate  */
230Sstevel@tonic-gate 
240Sstevel@tonic-gate #define	getpagesize()	sysconf(_SC_PAGESIZE)
250Sstevel@tonic-gate 
260Sstevel@tonic-gate static int		pagesize = 0;
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #define	INIT_ULOG(ctx)	log_ctx = ctx->kdblog_context; \
290Sstevel@tonic-gate 			ulog = log_ctx->ulog
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * Sync update entry to disk.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate krb5_error_code
ulog_sync_update(kdb_hlog_t * ulog,kdb_ent_header_t * upd)340Sstevel@tonic-gate ulog_sync_update(kdb_hlog_t *ulog, kdb_ent_header_t *upd)
350Sstevel@tonic-gate {
360Sstevel@tonic-gate 	ulong_t		start, end, size;
370Sstevel@tonic-gate 	krb5_error_code	retval;
380Sstevel@tonic-gate 
390Sstevel@tonic-gate 	if (ulog == NULL)
400Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
410Sstevel@tonic-gate 
420Sstevel@tonic-gate 	if (!pagesize)
430Sstevel@tonic-gate 		pagesize = getpagesize();
440Sstevel@tonic-gate 
450Sstevel@tonic-gate 	start = ((ulong_t)upd) & (~(pagesize-1));
460Sstevel@tonic-gate 
470Sstevel@tonic-gate 	end = (((ulong_t)upd) + ulog->kdb_block +
484960Swillf 	    (pagesize-1)) & (~(pagesize-1));
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	size = end - start;
510Sstevel@tonic-gate 	if (retval = msync((caddr_t)start, size, MS_SYNC)) {
520Sstevel@tonic-gate 		return (retval);
530Sstevel@tonic-gate 	}
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	return (0);
560Sstevel@tonic-gate }
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * Sync memory to disk for the update log header.
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate void
ulog_sync_header(kdb_hlog_t * ulog)620Sstevel@tonic-gate ulog_sync_header(kdb_hlog_t *ulog)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	if (!pagesize)
660Sstevel@tonic-gate 		pagesize = getpagesize();
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	if (msync((caddr_t)ulog, pagesize, MS_SYNC)) {
690Sstevel@tonic-gate 		/*
700Sstevel@tonic-gate 		 * Couldn't sync to disk, let's panic
710Sstevel@tonic-gate 		 */
720Sstevel@tonic-gate 		syslog(LOG_ERR, "ulog_sync_header: could not sync to disk");
730Sstevel@tonic-gate 		abort();
740Sstevel@tonic-gate 	}
750Sstevel@tonic-gate }
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  * Resizes the array elements.  We reinitialize the update log rather than
790Sstevel@tonic-gate  * unrolling the the log and copying it over to a temporary log for obvious
800Sstevel@tonic-gate  * performance reasons.  Slaves will subsequently do a full resync, but
810Sstevel@tonic-gate  * the need for resizing should be very small.
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate krb5_error_code
ulog_resize(kdb_hlog_t * ulog,uint32_t ulogentries,int ulogfd,uint_t recsize)840Sstevel@tonic-gate ulog_resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd, uint_t recsize)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	uint_t		new_block, new_size;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	if (ulog == NULL)
890Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	new_size = sizeof (kdb_hlog_t);
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	new_block = (recsize / ULOG_BLOCK) + 1;
940Sstevel@tonic-gate 	new_block *= ULOG_BLOCK;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	new_size += ulogentries * new_block;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	if (new_size <= MAXLOGLEN) {
990Sstevel@tonic-gate 		/*
1000Sstevel@tonic-gate 		 * Reinit log with new block size
1010Sstevel@tonic-gate 		 */
1020Sstevel@tonic-gate 		(void) memset(ulog, 0, sizeof (kdb_hlog_t));
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 		ulog->kdb_hmagic = KDB_HMAGIC;
1050Sstevel@tonic-gate 		ulog->db_version_num = KDB_VERSION;
1060Sstevel@tonic-gate 		ulog->kdb_state = KDB_STABLE;
1070Sstevel@tonic-gate 		ulog->kdb_block = new_block;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 		ulog_sync_header(ulog);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 		/*
1120Sstevel@tonic-gate 		 * Time to expand log considering new block size
1130Sstevel@tonic-gate 		 */
1140Sstevel@tonic-gate 		if (lseek(ulogfd, new_size, SEEK_SET) == -1) {
1150Sstevel@tonic-gate 			return (errno);
1160Sstevel@tonic-gate 		}
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 		if (write(ulogfd, "+", 1) != 1) {
1190Sstevel@tonic-gate 			return (errno);
1200Sstevel@tonic-gate 		}
1210Sstevel@tonic-gate 	} else {
1220Sstevel@tonic-gate 		/*
1230Sstevel@tonic-gate 		 * Can't map into file larger than MAXLOGLEN
1240Sstevel@tonic-gate 		 */
1250Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	return (0);
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*
1320Sstevel@tonic-gate  * Adds an entry to the update log.
1330Sstevel@tonic-gate  * The layout of the update log looks like:
1340Sstevel@tonic-gate  *
1350Sstevel@tonic-gate  * header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate krb5_error_code
ulog_add_update(krb5_context context,kdb_incr_update_t * upd)1380Sstevel@tonic-gate ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate 	XDR		xdrs;
1410Sstevel@tonic-gate 	kdbe_time_t	ktime;
1420Sstevel@tonic-gate 	struct timeval	timestamp;
1430Sstevel@tonic-gate 	kdb_ent_header_t *indx_log;
1440Sstevel@tonic-gate 	uint_t		i, recsize;
1450Sstevel@tonic-gate 	ulong_t		upd_size;
1460Sstevel@tonic-gate 	krb5_error_code	retval;
1470Sstevel@tonic-gate 	kdb_sno_t	cur_sno;
1480Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
1490Sstevel@tonic-gate 	kdb_hlog_t	*ulog = NULL;
1500Sstevel@tonic-gate 	uint32_t	ulogentries;
1510Sstevel@tonic-gate 	int		ulogfd;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	INIT_ULOG(context);
1540Sstevel@tonic-gate 	ulogentries = log_ctx->ulogentries;
1550Sstevel@tonic-gate 	ulogfd = log_ctx->ulogfd;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	if (upd == NULL)
1580Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	(void) gettimeofday(&timestamp, NULL);
1610Sstevel@tonic-gate 	ktime.seconds = timestamp.tv_sec;
1620Sstevel@tonic-gate 	ktime.useconds = timestamp.tv_usec;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	recsize = sizeof (kdb_ent_header_t) + upd_size;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	if (recsize > ulog->kdb_block) {
1690Sstevel@tonic-gate 		if (retval = ulog_resize(ulog, ulogentries, ulogfd, recsize)) {
1700Sstevel@tonic-gate 			/* Resize element array failed */
1710Sstevel@tonic-gate 			return (retval);
1720Sstevel@tonic-gate 		}
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	cur_sno = ulog->kdb_last_sno;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	/*
1780Sstevel@tonic-gate 	 * We need to overflow our sno, replicas will do full
1790Sstevel@tonic-gate 	 * resyncs once they see their sno > than the masters.
1800Sstevel@tonic-gate 	 */
1810Sstevel@tonic-gate 	if (cur_sno == ULONG_MAX)
1820Sstevel@tonic-gate 		cur_sno = 1;
1830Sstevel@tonic-gate 	else
1840Sstevel@tonic-gate 		cur_sno++;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	/*
1870Sstevel@tonic-gate 	 * We squirrel this away for finish_update() to index
1880Sstevel@tonic-gate 	 */
1890Sstevel@tonic-gate 	upd->kdb_entry_sno = cur_sno;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	i = (cur_sno - 1) % ulogentries;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	(void) memset(indx_log, 0, ulog->kdb_block);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	indx_log->kdb_umagic = KDB_UMAGIC;
1980Sstevel@tonic-gate 	indx_log->kdb_entry_size = upd_size;
1990Sstevel@tonic-gate 	indx_log->kdb_entry_sno = cur_sno;
2000Sstevel@tonic-gate 	indx_log->kdb_time = upd->kdb_time = ktime;
2010Sstevel@tonic-gate 	indx_log->kdb_commit = upd->kdb_commit = FALSE;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	ulog->kdb_state = KDB_UNSTABLE;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	xdrmem_create(&xdrs, (char *)indx_log->entry_data,
2060Sstevel@tonic-gate 	    indx_log->kdb_entry_size, XDR_ENCODE);
2070Sstevel@tonic-gate 	if (!xdr_kdb_incr_update_t(&xdrs, upd))
2080Sstevel@tonic-gate 		return (KRB5_LOG_CONV);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	if (retval = ulog_sync_update(ulog, indx_log))
2110Sstevel@tonic-gate 		return (retval);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if (ulog->kdb_num < ulogentries)
2140Sstevel@tonic-gate 		ulog->kdb_num++;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	ulog->kdb_last_sno = cur_sno;
2170Sstevel@tonic-gate 	ulog->kdb_last_time = ktime;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * Since this is a circular array, once we circled, kdb_first_sno is
2210Sstevel@tonic-gate 	 * always kdb_entry_sno + 1.
2220Sstevel@tonic-gate 	 */
2230Sstevel@tonic-gate 	if (cur_sno > ulogentries) {
2240Sstevel@tonic-gate 		i = upd->kdb_entry_sno % ulogentries;
2250Sstevel@tonic-gate 		indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
2260Sstevel@tonic-gate 		ulog->kdb_first_sno = indx_log->kdb_entry_sno;
2270Sstevel@tonic-gate 		ulog->kdb_first_time = indx_log->kdb_time;
2280Sstevel@tonic-gate 	} else if (cur_sno == 1) {
2290Sstevel@tonic-gate 		ulog->kdb_first_sno = 1;
2300Sstevel@tonic-gate 		ulog->kdb_first_time = indx_log->kdb_time;
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	ulog_sync_header(ulog);
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return (0);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate  * Mark the log entry as committed and sync the memory mapped log
2400Sstevel@tonic-gate  * to file.
2410Sstevel@tonic-gate  */
2420Sstevel@tonic-gate krb5_error_code
ulog_finish_update(krb5_context context,kdb_incr_update_t * upd)2430Sstevel@tonic-gate ulog_finish_update(krb5_context context, kdb_incr_update_t *upd)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate 	krb5_error_code		retval;
2460Sstevel@tonic-gate 	kdb_ent_header_t	*indx_log;
2470Sstevel@tonic-gate 	uint_t			i;
2480Sstevel@tonic-gate 	kdb_log_context		*log_ctx;
2490Sstevel@tonic-gate 	kdb_hlog_t		*ulog = NULL;
2500Sstevel@tonic-gate 	uint32_t		ulogentries;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	INIT_ULOG(context);
2530Sstevel@tonic-gate 	ulogentries = log_ctx->ulogentries;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	i = (upd->kdb_entry_sno - 1) % ulogentries;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	indx_log->kdb_commit = TRUE;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	ulog->kdb_state = KDB_STABLE;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	if (retval = ulog_sync_update(ulog, indx_log))
2640Sstevel@tonic-gate 		return (retval);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	ulog_sync_header(ulog);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	return (0);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate  * Set the header log details on the slave and sync it to file.
2730Sstevel@tonic-gate  */
2740Sstevel@tonic-gate void
ulog_finish_update_slave(kdb_hlog_t * ulog,kdb_last_t lastentry)2750Sstevel@tonic-gate ulog_finish_update_slave(kdb_hlog_t *ulog, kdb_last_t lastentry)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	ulog->kdb_last_sno = lastentry.last_sno;
2790Sstevel@tonic-gate 	ulog->kdb_last_time = lastentry.last_time;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	ulog_sync_header(ulog);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate  * Delete an entry to the update log.
2860Sstevel@tonic-gate  */
2870Sstevel@tonic-gate krb5_error_code
ulog_delete_update(krb5_context context,kdb_incr_update_t * upd)2880Sstevel@tonic-gate ulog_delete_update(krb5_context context, kdb_incr_update_t *upd)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	upd->kdb_deleted = TRUE;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	return (ulog_add_update(context, upd));
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * Used by the slave or master (during ulog_check) to update it's hash db from
2980Sstevel@tonic-gate  * the incr update log.
2990Sstevel@tonic-gate  */
3000Sstevel@tonic-gate krb5_error_code
ulog_replay(krb5_context context,kdb_incr_result_t * incr_ret)3010Sstevel@tonic-gate ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate 	krb5_db_entry		*entry = NULL;
3040Sstevel@tonic-gate 	kdb_incr_update_t	*upd = NULL, *fupd;
3050Sstevel@tonic-gate 	int			i, no_of_updates;
3060Sstevel@tonic-gate 	krb5_error_code		retval;
3070Sstevel@tonic-gate 	krb5_principal		dbprinc = NULL;
3080Sstevel@tonic-gate 	kdb_last_t		errlast;
3090Sstevel@tonic-gate 	char			*dbprincstr = NULL;
3100Sstevel@tonic-gate 	kdb_log_context		*log_ctx;
3110Sstevel@tonic-gate 	kdb_hlog_t		*ulog = NULL;
312*5201Ssemery 	bool_t			fini = FALSE;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	INIT_ULOG(context);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	no_of_updates = incr_ret->updates.kdb_ulog_t_len;
3170Sstevel@tonic-gate 	upd = incr_ret->updates.kdb_ulog_t_val;
3180Sstevel@tonic-gate 	fupd = upd;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	/*
3214960Swillf 	 * We reset last_sno and last_time to 0, if krb5_db_put_principal
3224960Swillf 	 * or krb5_db_delete_principal fail.
3230Sstevel@tonic-gate 	 */
3240Sstevel@tonic-gate 	errlast.last_sno = (unsigned int)0;
3250Sstevel@tonic-gate 	errlast.last_time.seconds = (unsigned int)0;
3260Sstevel@tonic-gate 	errlast.last_time.useconds = (unsigned int)0;
3270Sstevel@tonic-gate 
328*5201Ssemery 	if (krb5_db_inited(context)) {
329*5201Ssemery 		retval = krb5_db_open(context, NULL,
330*5201Ssemery 		    KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
331*5201Ssemery 		if (retval != 0)
332*5201Ssemery 			goto cleanup;
333*5201Ssemery 		fini = TRUE;
334*5201Ssemery 	}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	for (i = 0; i < no_of_updates; i++) {
3370Sstevel@tonic-gate 		int nentry = 1;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		if (!upd->kdb_commit)
3400Sstevel@tonic-gate 			continue;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 		if (upd->kdb_deleted) {
3430Sstevel@tonic-gate 			dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len
3440Sstevel@tonic-gate 			    + 1) * sizeof (char));
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 			if (dbprincstr == NULL) {
3470Sstevel@tonic-gate 				retval = ENOMEM;
3480Sstevel@tonic-gate 				goto cleanup;
3490Sstevel@tonic-gate 			}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 			(void) strlcpy(dbprincstr,
3520Sstevel@tonic-gate 			    (char *)upd->kdb_princ_name.utf8str_t_val,
3530Sstevel@tonic-gate 			    (upd->kdb_princ_name.utf8str_t_len + 1));
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 			if (retval = krb5_parse_name(context, dbprincstr,
3560Sstevel@tonic-gate 			    &dbprinc)) {
3570Sstevel@tonic-gate 				goto cleanup;
3580Sstevel@tonic-gate 			}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 			if (dbprincstr)
3610Sstevel@tonic-gate 				free(dbprincstr);
3620Sstevel@tonic-gate 
3634960Swillf 			retval = krb5_db_delete_principal(context,
3640Sstevel@tonic-gate 			    dbprinc, &nentry);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 			if (dbprinc)
3670Sstevel@tonic-gate 				krb5_free_principal(context, dbprinc);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 			if (retval)
3700Sstevel@tonic-gate 				goto cleanup;
3710Sstevel@tonic-gate 		} else {
3720Sstevel@tonic-gate 			entry = (krb5_db_entry *)malloc(sizeof (krb5_db_entry));
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 			if (!entry) {
3750Sstevel@tonic-gate 				retval = errno;
3760Sstevel@tonic-gate 				goto cleanup;
3770Sstevel@tonic-gate 			}
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 			(void) memset(entry, 0, sizeof (krb5_db_entry));
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 			if (retval = ulog_conv_2dbentry(context, entry, upd, 1))
3820Sstevel@tonic-gate 				goto cleanup;
3830Sstevel@tonic-gate 
3844960Swillf 			retval = krb5_db_put_principal(context, entry,
3850Sstevel@tonic-gate 			    &nentry);
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 			if (entry) {
3880Sstevel@tonic-gate 				krb5_db_free_principal(context, entry, nentry);
3890Sstevel@tonic-gate 				free(entry);
3900Sstevel@tonic-gate 				entry = NULL;
3910Sstevel@tonic-gate 			}
3920Sstevel@tonic-gate 			if (retval)
3930Sstevel@tonic-gate 				goto cleanup;
3940Sstevel@tonic-gate 		}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		upd++;
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate cleanup:
4000Sstevel@tonic-gate 	if (fupd)
4010Sstevel@tonic-gate 		ulog_free_entries(fupd, no_of_updates);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
4040Sstevel@tonic-gate 		if (retval)
4050Sstevel@tonic-gate 			ulog_finish_update_slave(ulog, errlast);
4060Sstevel@tonic-gate 		else
4070Sstevel@tonic-gate 			ulog_finish_update_slave(ulog, incr_ret->lastentry);
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
410*5201Ssemery 	if (fini == TRUE)
411*5201Ssemery 		krb5_db_fini(context);
412*5201Ssemery 
4130Sstevel@tonic-gate 	return (retval);
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate  * Validate the log file and resync any uncommitted update entries
4180Sstevel@tonic-gate  * to the principal database.
4190Sstevel@tonic-gate  */
4200Sstevel@tonic-gate krb5_error_code
ulog_check(krb5_context context,kdb_hlog_t * ulog)4210Sstevel@tonic-gate ulog_check(krb5_context context, kdb_hlog_t *ulog)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	XDR			xdrs;
4240Sstevel@tonic-gate 	krb5_error_code		retval = 0;
4250Sstevel@tonic-gate 	int			i;
4260Sstevel@tonic-gate 	kdb_ent_header_t	*indx_log;
4270Sstevel@tonic-gate 	kdb_incr_update_t	*upd = NULL;
4280Sstevel@tonic-gate 	kdb_incr_result_t	*incr_ret = NULL;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	ulog->kdb_state = KDB_STABLE;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	for (i = 0; i < ulog->kdb_num; i++) {
4330Sstevel@tonic-gate 		indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		if (indx_log->kdb_umagic != KDB_UMAGIC) {
4360Sstevel@tonic-gate 			/*
4370Sstevel@tonic-gate 			 * Update entry corrupted we should scream and die
4380Sstevel@tonic-gate 			 */
4390Sstevel@tonic-gate 			ulog->kdb_state = KDB_CORRUPT;
4400Sstevel@tonic-gate 			retval = KRB5_LOG_CORRUPT;
4410Sstevel@tonic-gate 			break;
4420Sstevel@tonic-gate 		}
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 		if (indx_log->kdb_commit == FALSE) {
4450Sstevel@tonic-gate 			ulog->kdb_state = KDB_UNSTABLE;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 			incr_ret = (kdb_incr_result_t *)
4480Sstevel@tonic-gate 			    malloc(sizeof (kdb_incr_result_t));
4490Sstevel@tonic-gate 			if (incr_ret == NULL) {
4500Sstevel@tonic-gate 				retval = errno;
4510Sstevel@tonic-gate 				goto error;
4520Sstevel@tonic-gate 			}
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 			upd = (kdb_incr_update_t *)
4550Sstevel@tonic-gate 			    malloc(sizeof (kdb_incr_update_t));
4560Sstevel@tonic-gate 			if (upd == NULL) {
4570Sstevel@tonic-gate 				retval = errno;
4580Sstevel@tonic-gate 				goto error;
4590Sstevel@tonic-gate 			}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 			(void) memset(upd, 0, sizeof (kdb_incr_update_t));
4620Sstevel@tonic-gate 			xdrmem_create(&xdrs, (char *)indx_log->entry_data,
4630Sstevel@tonic-gate 			    indx_log->kdb_entry_size, XDR_DECODE);
4640Sstevel@tonic-gate 			if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
4650Sstevel@tonic-gate 				retval = KRB5_LOG_CONV;
4660Sstevel@tonic-gate 				goto error;
4670Sstevel@tonic-gate 			}
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 			incr_ret->updates.kdb_ulog_t_len = 1;
4700Sstevel@tonic-gate 			incr_ret->updates.kdb_ulog_t_val = upd;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 			upd->kdb_commit = TRUE;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 			/*
4750Sstevel@tonic-gate 			 * We don't want to readd this update and just use the
4760Sstevel@tonic-gate 			 * existing update to be propagated later on
4770Sstevel@tonic-gate 			 */
4780Sstevel@tonic-gate 			ulog_set_role(context, IPROP_NULL);
4790Sstevel@tonic-gate 			retval = ulog_replay(context, incr_ret);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 			/*
4820Sstevel@tonic-gate 			 * upd was freed by ulog_replay, we NULL
4830Sstevel@tonic-gate 			 * the pointer in case we subsequently break from loop.
4840Sstevel@tonic-gate 			 */
4850Sstevel@tonic-gate 			upd = NULL;
4860Sstevel@tonic-gate 			if (incr_ret) {
4870Sstevel@tonic-gate 				free(incr_ret);
4880Sstevel@tonic-gate 				incr_ret = NULL;
4890Sstevel@tonic-gate 			}
4900Sstevel@tonic-gate 			ulog_set_role(context, IPROP_MASTER);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 			if (retval)
4930Sstevel@tonic-gate 				goto error;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 			/*
4960Sstevel@tonic-gate 			 * We flag this as committed since this was
4970Sstevel@tonic-gate 			 * the last entry before kadmind crashed, ergo
4980Sstevel@tonic-gate 			 * the slaves have not seen this update before
4990Sstevel@tonic-gate 			 */
5000Sstevel@tonic-gate 			indx_log->kdb_commit = TRUE;
5010Sstevel@tonic-gate 			retval = ulog_sync_update(ulog, indx_log);
5020Sstevel@tonic-gate 			if (retval)
5030Sstevel@tonic-gate 				goto error;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 			ulog->kdb_state = KDB_STABLE;
5060Sstevel@tonic-gate 		}
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate error:
5100Sstevel@tonic-gate 	if (upd)
5110Sstevel@tonic-gate 		ulog_free_entries(upd, 1);
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	if (incr_ret)
5140Sstevel@tonic-gate 		free(incr_ret);
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	ulog_sync_header(ulog);
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	return (retval);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate /*
5220Sstevel@tonic-gate  * Map the log file to memory for performance and simplicity.
5230Sstevel@tonic-gate  *
5240Sstevel@tonic-gate  * Called by: if iprop_enabled then ulog_map();
5250Sstevel@tonic-gate  * Assumes that the caller will terminate on ulog_map, hence munmap and
5260Sstevel@tonic-gate  * closing of the fd are implicitly performed by the caller.
5270Sstevel@tonic-gate  * Returns 0 on success else failure.
5280Sstevel@tonic-gate  */
5290Sstevel@tonic-gate krb5_error_code
ulog_map(krb5_context context,kadm5_config_params * params,int caller)5300Sstevel@tonic-gate ulog_map(krb5_context context, kadm5_config_params *params, int caller)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	struct stat	st;
5330Sstevel@tonic-gate 	krb5_error_code	retval;
5340Sstevel@tonic-gate 	uint32_t	ulog_filesize;
5350Sstevel@tonic-gate 	char		logname[MAX_FILENAME];
5360Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
5370Sstevel@tonic-gate 	kdb_hlog_t	*ulog = NULL;
5380Sstevel@tonic-gate 	uint32_t	ulogentries;
5390Sstevel@tonic-gate 	int		ulogfd = -1;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	if ((caller == FKADMIND) || (caller == FKCOMMAND))
5420Sstevel@tonic-gate 		ulogentries = params->iprop_ulogsize;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	ulog_filesize = sizeof (kdb_hlog_t);
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	if (strlcpy(logname, params->dbname, MAX_FILENAME) >= MAX_FILENAME)
5470Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
5480Sstevel@tonic-gate 	if (strlcat(logname, ".ulog", MAX_FILENAME) >= MAX_FILENAME)
5490Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	if (stat(logname, &st) == -1) {
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 		if (caller == FKPROPLOG) {
5540Sstevel@tonic-gate 			/*
5550Sstevel@tonic-gate 			 * File doesn't exist so we exit with kproplog
5560Sstevel@tonic-gate 			 */
5570Sstevel@tonic-gate 			return (errno);
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 		if ((ulogfd = open(logname, O_RDWR+O_CREAT, 0600)) == -1) {
5610Sstevel@tonic-gate 			return (errno);
5620Sstevel@tonic-gate 		}
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 		if (lseek(ulogfd, 0L, SEEK_CUR) == -1) {
5650Sstevel@tonic-gate 			return (errno);
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 		if ((caller == FKADMIND) || (caller == FKCOMMAND))
5690Sstevel@tonic-gate 			ulog_filesize += ulogentries * ULOG_BLOCK;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 		if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) {
5720Sstevel@tonic-gate 			return (errno);
5730Sstevel@tonic-gate 		}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		if (write(ulogfd, "+", 1) != 1) {
5760Sstevel@tonic-gate 			return (errno);
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	} else {
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 		if ((ulogfd = open(logname, O_RDWR, 0600)) == -1) {
5820Sstevel@tonic-gate 			/*
5830Sstevel@tonic-gate 			 * Can't open existing log file
5840Sstevel@tonic-gate 			 */
5850Sstevel@tonic-gate 			return (errno);
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	if (caller == FKPROPLOG) {
5900Sstevel@tonic-gate 		fstat(ulogfd, &st);
5910Sstevel@tonic-gate 		ulog_filesize = st.st_size;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		ulog = (kdb_hlog_t *)mmap(0, ulog_filesize,
5944960Swillf 		    PROT_READ+PROT_WRITE, MAP_PRIVATE, ulogfd, 0);
5950Sstevel@tonic-gate 	} else {
5960Sstevel@tonic-gate 		/*
5970Sstevel@tonic-gate 		 * else kadmind, kpropd, & kcommands should udpate stores
5980Sstevel@tonic-gate 		 */
5990Sstevel@tonic-gate 		ulog = (kdb_hlog_t *)mmap(0, MAXLOGLEN,
6004960Swillf 		    PROT_READ+PROT_WRITE, MAP_SHARED, ulogfd, 0);
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if ((int)(ulog) == -1) {
6040Sstevel@tonic-gate 		/*
6050Sstevel@tonic-gate 		 * Can't map update log file to memory
6060Sstevel@tonic-gate 		 */
6070Sstevel@tonic-gate 		return (errno);
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (!context->kdblog_context) {
6110Sstevel@tonic-gate 		if (!(log_ctx = malloc(sizeof (kdb_log_context))))
6120Sstevel@tonic-gate 			return (errno);
6130Sstevel@tonic-gate 		context->kdblog_context = (void *)log_ctx;
6140Sstevel@tonic-gate 	} else
6150Sstevel@tonic-gate 		log_ctx = context->kdblog_context;
6160Sstevel@tonic-gate 	log_ctx->ulog = ulog;
6170Sstevel@tonic-gate 	log_ctx->ulogentries = ulogentries;
6180Sstevel@tonic-gate 	log_ctx->ulogfd = ulogfd;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (ulog->kdb_hmagic != KDB_HMAGIC) {
6210Sstevel@tonic-gate 		if (ulog->kdb_hmagic == 0) {
6220Sstevel@tonic-gate 			/*
6230Sstevel@tonic-gate 			 * New update log
6240Sstevel@tonic-gate 			 */
6250Sstevel@tonic-gate 			(void) memset(ulog, 0, sizeof (kdb_hlog_t));
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 			ulog->kdb_hmagic = KDB_HMAGIC;
6280Sstevel@tonic-gate 			ulog->db_version_num = KDB_VERSION;
6290Sstevel@tonic-gate 			ulog->kdb_state = KDB_STABLE;
6300Sstevel@tonic-gate 			ulog->kdb_block = ULOG_BLOCK;
6310Sstevel@tonic-gate 			if (!(caller == FKPROPLOG))
6320Sstevel@tonic-gate 				ulog_sync_header(ulog);
6330Sstevel@tonic-gate 		} else {
6340Sstevel@tonic-gate 			return (KRB5_LOG_CORRUPT);
6350Sstevel@tonic-gate 		}
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	if (caller == FKADMIND) {
6390Sstevel@tonic-gate 		switch (ulog->kdb_state) {
6400Sstevel@tonic-gate 			case KDB_STABLE:
6410Sstevel@tonic-gate 			case KDB_UNSTABLE:
6420Sstevel@tonic-gate 				/*
6430Sstevel@tonic-gate 				 * Log is currently un/stable, check anyway
6440Sstevel@tonic-gate 				 */
6450Sstevel@tonic-gate 				retval = ulog_check(context, ulog);
6460Sstevel@tonic-gate 				if (retval == KRB5_LOG_CORRUPT) {
6470Sstevel@tonic-gate 					return (retval);
6480Sstevel@tonic-gate 				}
6490Sstevel@tonic-gate 				break;
6500Sstevel@tonic-gate 			case KDB_CORRUPT:
6510Sstevel@tonic-gate 				return (KRB5_LOG_CORRUPT);
6520Sstevel@tonic-gate 			default:
6530Sstevel@tonic-gate 				/*
6540Sstevel@tonic-gate 				 * Invalid db state
6550Sstevel@tonic-gate 				 */
6560Sstevel@tonic-gate 				return (KRB5_LOG_ERROR);
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 	} else if ((caller == FKPROPLOG) || (caller == FKPROPD)) {
6590Sstevel@tonic-gate 		/*
6600Sstevel@tonic-gate 		 * kproplog and kpropd don't need to do anything else
6610Sstevel@tonic-gate 		 */
6620Sstevel@tonic-gate 		return (0);
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	/*
6660Sstevel@tonic-gate 	 * Reinit ulog if the log is being truncated or expanded after
6670Sstevel@tonic-gate 	 * we have circled.
6680Sstevel@tonic-gate 	 */
6690Sstevel@tonic-gate 	if (ulog->kdb_num != ulogentries) {
6700Sstevel@tonic-gate 		if ((ulog->kdb_num != 0) &&
6710Sstevel@tonic-gate 		    ((ulog->kdb_last_sno > ulog->kdb_num) ||
6720Sstevel@tonic-gate 		    (ulog->kdb_num > ulogentries))) {
6730Sstevel@tonic-gate 			(void) memset(ulog, 0, sizeof (kdb_hlog_t));
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 			ulog->kdb_hmagic = KDB_HMAGIC;
6760Sstevel@tonic-gate 			ulog->db_version_num = KDB_VERSION;
6770Sstevel@tonic-gate 			ulog->kdb_state = KDB_STABLE;
6780Sstevel@tonic-gate 			ulog->kdb_block = ULOG_BLOCK;
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 			ulog_sync_header(ulog);
6810Sstevel@tonic-gate 		}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 		/*
6840Sstevel@tonic-gate 		 * Expand ulog if we have specified a greater size
6850Sstevel@tonic-gate 		 */
6860Sstevel@tonic-gate 		if (ulog->kdb_num < ulogentries) {
6870Sstevel@tonic-gate 			ulog_filesize += ulogentries * ulog->kdb_block;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 			if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) {
6900Sstevel@tonic-gate 				return (errno);
6910Sstevel@tonic-gate 			}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 			if (write(ulogfd, "+", 1) != 1) {
6940Sstevel@tonic-gate 				return (errno);
6950Sstevel@tonic-gate 			}
6960Sstevel@tonic-gate 		}
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	return (0);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate /*
7030Sstevel@tonic-gate  * Get the last set of updates seen, (last+1) to n is returned.
7040Sstevel@tonic-gate  */
7050Sstevel@tonic-gate krb5_error_code
ulog_get_entries(krb5_context context,kdb_last_t last,kdb_incr_result_t * ulog_handle)7060Sstevel@tonic-gate ulog_get_entries(
7070Sstevel@tonic-gate 	krb5_context context,		/* input - krb5 lib config */
7080Sstevel@tonic-gate 	kdb_last_t last,		/* input - slave's last sno */
7090Sstevel@tonic-gate 	kdb_incr_result_t *ulog_handle)	/* output - incr result for slave */
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	XDR			xdrs;
7120Sstevel@tonic-gate 	kdb_ent_header_t	*indx_log;
7130Sstevel@tonic-gate 	kdb_incr_update_t	*upd;
7140Sstevel@tonic-gate 	uint_t			indx, count, tdiff;
7150Sstevel@tonic-gate 	uint32_t		sno;
7160Sstevel@tonic-gate 	krb5_error_code		retval;
7170Sstevel@tonic-gate 	struct timeval		timestamp;
7180Sstevel@tonic-gate 	kdb_log_context		*log_ctx;
7190Sstevel@tonic-gate 	kdb_hlog_t		*ulog = NULL;
7200Sstevel@tonic-gate 	uint32_t		ulogentries;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	INIT_ULOG(context);
7230Sstevel@tonic-gate 	ulogentries = log_ctx->ulogentries;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	/*
7260Sstevel@tonic-gate 	 * Check to make sure we don't have a corrupt ulog first.
7270Sstevel@tonic-gate 	 */
7280Sstevel@tonic-gate 	if (ulog->kdb_state == KDB_CORRUPT) {
7290Sstevel@tonic-gate 		ulog_handle->ret = UPDATE_ERROR;
7300Sstevel@tonic-gate 		return (KRB5_LOG_CORRUPT);
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	gettimeofday(&timestamp, NULL);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;
7360Sstevel@tonic-gate 	if (tdiff <= ULOG_IDLE_TIME) {
7370Sstevel@tonic-gate 		ulog_handle->ret = UPDATE_BUSY;
7380Sstevel@tonic-gate 		return (0);
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	/*
7420Sstevel@tonic-gate 	 * We need to lock out other processes here, such as kadmin.local,
7430Sstevel@tonic-gate 	 * since we are looking at the last_sno and looking up updates.  So
7440Sstevel@tonic-gate 	 * we can share with other readers.
7450Sstevel@tonic-gate 	 */
7460Sstevel@tonic-gate 	retval = krb5_db_lock(context, KRB5_LOCKMODE_SHARED);
7470Sstevel@tonic-gate 	if (retval)
7480Sstevel@tonic-gate 		return (retval);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/*
7510Sstevel@tonic-gate 	 * We may have overflowed the update log or we shrunk the log, or
7520Sstevel@tonic-gate 	 * the client's ulog has just been created.
7530Sstevel@tonic-gate 	 */
7540Sstevel@tonic-gate 	if ((last.last_sno > ulog->kdb_last_sno) ||
7550Sstevel@tonic-gate 	    (last.last_sno < ulog->kdb_first_sno) ||
7560Sstevel@tonic-gate 	    (last.last_sno == 0)) {
7570Sstevel@tonic-gate 		ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
7580Sstevel@tonic-gate 		(void) krb5_db_unlock(context);
7590Sstevel@tonic-gate 		ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
7600Sstevel@tonic-gate 		return (0);
7610Sstevel@tonic-gate 	} else if (last.last_sno <= ulog->kdb_last_sno) {
7620Sstevel@tonic-gate 		sno = last.last_sno;
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 		indx = (sno - 1) % ulogentries;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		/*
7690Sstevel@tonic-gate 		 * Validate the time stamp just to make sure it was the same sno
7700Sstevel@tonic-gate 		 */
7710Sstevel@tonic-gate 		if ((indx_log->kdb_time.seconds == last.last_time.seconds) &&
7720Sstevel@tonic-gate 		    (indx_log->kdb_time.useconds == last.last_time.useconds)) {
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 			/*
7750Sstevel@tonic-gate 			 * If we have the same sno we return success
7760Sstevel@tonic-gate 			 */
7770Sstevel@tonic-gate 			if (last.last_sno == ulog->kdb_last_sno) {
7780Sstevel@tonic-gate 				(void) krb5_db_unlock(context);
7790Sstevel@tonic-gate 				ulog_handle->ret = UPDATE_NIL;
7800Sstevel@tonic-gate 				return (0);
7810Sstevel@tonic-gate 			}
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 			count = ulog->kdb_last_sno - sno;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 			ulog_handle->updates.kdb_ulog_t_val =
7860Sstevel@tonic-gate 			    (kdb_incr_update_t *)malloc(
7870Sstevel@tonic-gate 			    sizeof (kdb_incr_update_t) * count);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 			upd = ulog_handle->updates.kdb_ulog_t_val;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 			if (upd == NULL) {
7920Sstevel@tonic-gate 				(void) krb5_db_unlock(context);
7930Sstevel@tonic-gate 				ulog_handle->ret = UPDATE_ERROR;
7940Sstevel@tonic-gate 				return (errno);
7950Sstevel@tonic-gate 			}
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 			while (sno < ulog->kdb_last_sno) {
7980Sstevel@tonic-gate 				indx = sno % ulogentries;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 				indx_log = (kdb_ent_header_t *)
8010Sstevel@tonic-gate 				    INDEX(ulog, indx);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 				(void) memset(upd, 0,
8040Sstevel@tonic-gate 				    sizeof (kdb_incr_update_t));
8050Sstevel@tonic-gate 				xdrmem_create(&xdrs,
8060Sstevel@tonic-gate 				    (char *)indx_log->entry_data,
8070Sstevel@tonic-gate 				    indx_log->kdb_entry_size, XDR_DECODE);
8080Sstevel@tonic-gate 				if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
8090Sstevel@tonic-gate 					(void) krb5_db_unlock(context);
8100Sstevel@tonic-gate 					ulog_handle->ret = UPDATE_ERROR;
8110Sstevel@tonic-gate 					return (KRB5_LOG_CONV);
8120Sstevel@tonic-gate 				}
8130Sstevel@tonic-gate 				/*
8140Sstevel@tonic-gate 				 * Mark commitment since we didn't
8150Sstevel@tonic-gate 				 * want to decode and encode the
8160Sstevel@tonic-gate 				 * incr update record the first time.
8170Sstevel@tonic-gate 				 */
8180Sstevel@tonic-gate 				upd->kdb_commit = indx_log->kdb_commit;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 				upd++;
8210Sstevel@tonic-gate 				sno++;
8220Sstevel@tonic-gate 			} /* while */
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 			ulog_handle->updates.kdb_ulog_t_len = count;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 			ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
8270Sstevel@tonic-gate 			ulog_handle->lastentry.last_time.seconds =
8280Sstevel@tonic-gate 			    ulog->kdb_last_time.seconds;
8290Sstevel@tonic-gate 			ulog_handle->lastentry.last_time.useconds =
8300Sstevel@tonic-gate 			    ulog->kdb_last_time.useconds;
8310Sstevel@tonic-gate 			ulog_handle->ret = UPDATE_OK;
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 			(void) krb5_db_unlock(context);
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 			return (0);
8360Sstevel@tonic-gate 		} else {
8370Sstevel@tonic-gate 			/*
8380Sstevel@tonic-gate 			 * We have time stamp mismatch or we no longer have
8390Sstevel@tonic-gate 			 * the slave's last sno, so we brute force it
8400Sstevel@tonic-gate 			 */
8410Sstevel@tonic-gate 			(void) krb5_db_unlock(context);
8420Sstevel@tonic-gate 			ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 			return (0);
8450Sstevel@tonic-gate 		}
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/*
8490Sstevel@tonic-gate 	 * Should never get here, return error
8500Sstevel@tonic-gate 	 */
8510Sstevel@tonic-gate 	ulog_handle->ret = UPDATE_ERROR;
8520Sstevel@tonic-gate 	return (KRB5_LOG_ERROR);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate krb5_error_code
ulog_set_role(krb5_context ctx,iprop_role role)8560Sstevel@tonic-gate ulog_set_role(krb5_context ctx, iprop_role role)
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	if (!ctx->kdblog_context) {
8610Sstevel@tonic-gate 		if (!(log_ctx = malloc(sizeof (kdb_log_context))))
8620Sstevel@tonic-gate 			return (errno);
8630Sstevel@tonic-gate 		ctx->kdblog_context = (void *)log_ctx;
8640Sstevel@tonic-gate 	} else
8650Sstevel@tonic-gate 		log_ctx = ctx->kdblog_context;
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	log_ctx->iproprole = role;
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	return (0);
8700Sstevel@tonic-gate }
871