xref: /titanic_51/usr/src/lib/krb5/kdb/kdb_log.c (revision 67c900400ffabaec1fd8a7ee6cea5e9beb39c3cb)
17c478bd9Sstevel@tonic-gate /*
254925bf6Swillf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
77c478bd9Sstevel@tonic-gate 
87c478bd9Sstevel@tonic-gate #include <sys/stat.h>
97c478bd9Sstevel@tonic-gate #include <sys/types.h>
107c478bd9Sstevel@tonic-gate #include <unistd.h>
117c478bd9Sstevel@tonic-gate #include <fcntl.h>
127c478bd9Sstevel@tonic-gate #include <sys/mman.h>
137c478bd9Sstevel@tonic-gate #include <k5-int.h>
147c478bd9Sstevel@tonic-gate #include <stdlib.h>
157c478bd9Sstevel@tonic-gate #include <limits.h>
167c478bd9Sstevel@tonic-gate #include <syslog.h>
177c478bd9Sstevel@tonic-gate #include "kdb_log.h"
187c478bd9Sstevel@tonic-gate 
197c478bd9Sstevel@tonic-gate /*
207c478bd9Sstevel@tonic-gate  * This modules includes all the necessary functions that create and
217c478bd9Sstevel@tonic-gate  * modify the Kerberos principal update and header logs.
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #define	getpagesize()	sysconf(_SC_PAGESIZE)
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate static int		pagesize = 0;
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #define	INIT_ULOG(ctx)	log_ctx = ctx->kdblog_context; \
297c478bd9Sstevel@tonic-gate 			ulog = log_ctx->ulog
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * Sync update entry to disk.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate krb5_error_code
347c478bd9Sstevel@tonic-gate ulog_sync_update(kdb_hlog_t *ulog, kdb_ent_header_t *upd)
357c478bd9Sstevel@tonic-gate {
367c478bd9Sstevel@tonic-gate 	ulong_t		start, end, size;
377c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate 	if (ulog == NULL)
407c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate 	if (!pagesize)
437c478bd9Sstevel@tonic-gate 		pagesize = getpagesize();
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate 	start = ((ulong_t)upd) & (~(pagesize-1));
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	end = (((ulong_t)upd) + ulog->kdb_block +
487c478bd9Sstevel@tonic-gate 	    (pagesize-1)) & (~(pagesize-1));
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	size = end - start;
517c478bd9Sstevel@tonic-gate 	if (retval = msync((caddr_t)start, size, MS_SYNC)) {
527c478bd9Sstevel@tonic-gate 		return (retval);
537c478bd9Sstevel@tonic-gate 	}
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	return (0);
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * Sync memory to disk for the update log header.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate void
627c478bd9Sstevel@tonic-gate ulog_sync_header(kdb_hlog_t *ulog)
637c478bd9Sstevel@tonic-gate {
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	if (!pagesize)
667c478bd9Sstevel@tonic-gate 		pagesize = getpagesize();
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	if (msync((caddr_t)ulog, pagesize, MS_SYNC)) {
697c478bd9Sstevel@tonic-gate 		/*
707c478bd9Sstevel@tonic-gate 		 * Couldn't sync to disk, let's panic
717c478bd9Sstevel@tonic-gate 		 */
727c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "ulog_sync_header: could not sync to disk");
737c478bd9Sstevel@tonic-gate 		abort();
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * Resizes the array elements.  We reinitialize the update log rather than
797c478bd9Sstevel@tonic-gate  * unrolling the the log and copying it over to a temporary log for obvious
807c478bd9Sstevel@tonic-gate  * performance reasons.  Slaves will subsequently do a full resync, but
817c478bd9Sstevel@tonic-gate  * the need for resizing should be very small.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate krb5_error_code
847c478bd9Sstevel@tonic-gate ulog_resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd, uint_t recsize)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	uint_t		new_block, new_size;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	if (ulog == NULL)
897c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	new_size = sizeof (kdb_hlog_t);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	new_block = (recsize / ULOG_BLOCK) + 1;
947c478bd9Sstevel@tonic-gate 	new_block *= ULOG_BLOCK;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	new_size += ulogentries * new_block;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (new_size <= MAXLOGLEN) {
997c478bd9Sstevel@tonic-gate 		/*
1007c478bd9Sstevel@tonic-gate 		 * Reinit log with new block size
1017c478bd9Sstevel@tonic-gate 		 */
1027c478bd9Sstevel@tonic-gate 		(void) memset(ulog, 0, sizeof (kdb_hlog_t));
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 		ulog->kdb_hmagic = KDB_HMAGIC;
1057c478bd9Sstevel@tonic-gate 		ulog->db_version_num = KDB_VERSION;
1067c478bd9Sstevel@tonic-gate 		ulog->kdb_state = KDB_STABLE;
1077c478bd9Sstevel@tonic-gate 		ulog->kdb_block = new_block;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 		ulog_sync_header(ulog);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		/*
1127c478bd9Sstevel@tonic-gate 		 * Time to expand log considering new block size
1137c478bd9Sstevel@tonic-gate 		 */
1147c478bd9Sstevel@tonic-gate 		if (lseek(ulogfd, new_size, SEEK_SET) == -1) {
1157c478bd9Sstevel@tonic-gate 			return (errno);
1167c478bd9Sstevel@tonic-gate 		}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 		if (write(ulogfd, "+", 1) != 1) {
1197c478bd9Sstevel@tonic-gate 			return (errno);
1207c478bd9Sstevel@tonic-gate 		}
1217c478bd9Sstevel@tonic-gate 	} else {
1227c478bd9Sstevel@tonic-gate 		/*
1237c478bd9Sstevel@tonic-gate 		 * Can't map into file larger than MAXLOGLEN
1247c478bd9Sstevel@tonic-gate 		 */
1257c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	return (0);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * Adds an entry to the update log.
1337c478bd9Sstevel@tonic-gate  * The layout of the update log looks like:
1347c478bd9Sstevel@tonic-gate  *
1357c478bd9Sstevel@tonic-gate  * header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate krb5_error_code
1387c478bd9Sstevel@tonic-gate ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	XDR		xdrs;
1417c478bd9Sstevel@tonic-gate 	kdbe_time_t	ktime;
1427c478bd9Sstevel@tonic-gate 	struct timeval	timestamp;
1437c478bd9Sstevel@tonic-gate 	kdb_ent_header_t *indx_log;
1447c478bd9Sstevel@tonic-gate 	uint_t		i, recsize;
1457c478bd9Sstevel@tonic-gate 	ulong_t		upd_size;
1467c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
1477c478bd9Sstevel@tonic-gate 	kdb_sno_t	cur_sno;
1487c478bd9Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
1497c478bd9Sstevel@tonic-gate 	kdb_hlog_t	*ulog = NULL;
1507c478bd9Sstevel@tonic-gate 	uint32_t	ulogentries;
1517c478bd9Sstevel@tonic-gate 	int		ulogfd;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	INIT_ULOG(context);
1547c478bd9Sstevel@tonic-gate 	ulogentries = log_ctx->ulogentries;
1557c478bd9Sstevel@tonic-gate 	ulogfd = log_ctx->ulogfd;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	if (upd == NULL)
1587c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&timestamp, NULL);
1617c478bd9Sstevel@tonic-gate 	ktime.seconds = timestamp.tv_sec;
1627c478bd9Sstevel@tonic-gate 	ktime.useconds = timestamp.tv_usec;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	recsize = sizeof (kdb_ent_header_t) + upd_size;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	if (recsize > ulog->kdb_block) {
1697c478bd9Sstevel@tonic-gate 		if (retval = ulog_resize(ulog, ulogentries, ulogfd, recsize)) {
1707c478bd9Sstevel@tonic-gate 			/* Resize element array failed */
1717c478bd9Sstevel@tonic-gate 			return (retval);
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	cur_sno = ulog->kdb_last_sno;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	/*
1787c478bd9Sstevel@tonic-gate 	 * We need to overflow our sno, replicas will do full
1797c478bd9Sstevel@tonic-gate 	 * resyncs once they see their sno > than the masters.
1807c478bd9Sstevel@tonic-gate 	 */
1817c478bd9Sstevel@tonic-gate 	if (cur_sno == ULONG_MAX)
1827c478bd9Sstevel@tonic-gate 		cur_sno = 1;
1837c478bd9Sstevel@tonic-gate 	else
1847c478bd9Sstevel@tonic-gate 		cur_sno++;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	/*
1877c478bd9Sstevel@tonic-gate 	 * We squirrel this away for finish_update() to index
1887c478bd9Sstevel@tonic-gate 	 */
1897c478bd9Sstevel@tonic-gate 	upd->kdb_entry_sno = cur_sno;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	i = (cur_sno - 1) % ulogentries;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	(void) memset(indx_log, 0, ulog->kdb_block);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	indx_log->kdb_umagic = KDB_UMAGIC;
1987c478bd9Sstevel@tonic-gate 	indx_log->kdb_entry_size = upd_size;
1997c478bd9Sstevel@tonic-gate 	indx_log->kdb_entry_sno = cur_sno;
2007c478bd9Sstevel@tonic-gate 	indx_log->kdb_time = upd->kdb_time = ktime;
2017c478bd9Sstevel@tonic-gate 	indx_log->kdb_commit = upd->kdb_commit = FALSE;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	ulog->kdb_state = KDB_UNSTABLE;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, (char *)indx_log->entry_data,
2067c478bd9Sstevel@tonic-gate 	    indx_log->kdb_entry_size, XDR_ENCODE);
2077c478bd9Sstevel@tonic-gate 	if (!xdr_kdb_incr_update_t(&xdrs, upd))
2087c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_CONV);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (retval = ulog_sync_update(ulog, indx_log))
2117c478bd9Sstevel@tonic-gate 		return (retval);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	if (ulog->kdb_num < ulogentries)
2147c478bd9Sstevel@tonic-gate 		ulog->kdb_num++;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	ulog->kdb_last_sno = cur_sno;
2177c478bd9Sstevel@tonic-gate 	ulog->kdb_last_time = ktime;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * Since this is a circular array, once we circled, kdb_first_sno is
2217c478bd9Sstevel@tonic-gate 	 * always kdb_entry_sno + 1.
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate 	if (cur_sno > ulogentries) {
2247c478bd9Sstevel@tonic-gate 		i = upd->kdb_entry_sno % ulogentries;
2257c478bd9Sstevel@tonic-gate 		indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
2267c478bd9Sstevel@tonic-gate 		ulog->kdb_first_sno = indx_log->kdb_entry_sno;
2277c478bd9Sstevel@tonic-gate 		ulog->kdb_first_time = indx_log->kdb_time;
2287c478bd9Sstevel@tonic-gate 	} else if (cur_sno == 1) {
2297c478bd9Sstevel@tonic-gate 		ulog->kdb_first_sno = 1;
2307c478bd9Sstevel@tonic-gate 		ulog->kdb_first_time = indx_log->kdb_time;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	ulog_sync_header(ulog);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	return (0);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * Mark the log entry as committed and sync the memory mapped log
2407c478bd9Sstevel@tonic-gate  * to file.
2417c478bd9Sstevel@tonic-gate  */
2427c478bd9Sstevel@tonic-gate krb5_error_code
2437c478bd9Sstevel@tonic-gate ulog_finish_update(krb5_context context, kdb_incr_update_t *upd)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	krb5_error_code		retval;
2467c478bd9Sstevel@tonic-gate 	kdb_ent_header_t	*indx_log;
2477c478bd9Sstevel@tonic-gate 	uint_t			i;
2487c478bd9Sstevel@tonic-gate 	kdb_log_context		*log_ctx;
2497c478bd9Sstevel@tonic-gate 	kdb_hlog_t		*ulog = NULL;
2507c478bd9Sstevel@tonic-gate 	uint32_t		ulogentries;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	INIT_ULOG(context);
2537c478bd9Sstevel@tonic-gate 	ulogentries = log_ctx->ulogentries;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	i = (upd->kdb_entry_sno - 1) % ulogentries;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	indx_log->kdb_commit = TRUE;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	ulog->kdb_state = KDB_STABLE;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if (retval = ulog_sync_update(ulog, indx_log))
2647c478bd9Sstevel@tonic-gate 		return (retval);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	ulog_sync_header(ulog);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	return (0);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * Set the header log details on the slave and sync it to file.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate void
2757c478bd9Sstevel@tonic-gate ulog_finish_update_slave(kdb_hlog_t *ulog, kdb_last_t lastentry)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	ulog->kdb_last_sno = lastentry.last_sno;
2797c478bd9Sstevel@tonic-gate 	ulog->kdb_last_time = lastentry.last_time;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	ulog_sync_header(ulog);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  * Delete an entry to the update log.
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate krb5_error_code
2887c478bd9Sstevel@tonic-gate ulog_delete_update(krb5_context context, kdb_incr_update_t *upd)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	upd->kdb_deleted = TRUE;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	return (ulog_add_update(context, upd));
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * Used by the slave or master (during ulog_check) to update it's hash db from
2987c478bd9Sstevel@tonic-gate  * the incr update log.
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate krb5_error_code
3017c478bd9Sstevel@tonic-gate ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	krb5_db_entry		*entry = NULL;
3047c478bd9Sstevel@tonic-gate 	kdb_incr_update_t	*upd = NULL, *fupd;
3057c478bd9Sstevel@tonic-gate 	int			i, no_of_updates;
3067c478bd9Sstevel@tonic-gate 	krb5_error_code		retval;
3077c478bd9Sstevel@tonic-gate 	krb5_principal		dbprinc = NULL;
3087c478bd9Sstevel@tonic-gate 	kdb_last_t		errlast;
3097c478bd9Sstevel@tonic-gate 	char			*dbprincstr = NULL;
3107c478bd9Sstevel@tonic-gate 	kdb_log_context		*log_ctx;
3117c478bd9Sstevel@tonic-gate 	kdb_hlog_t		*ulog = NULL;
312*67c90040Ssemery 	bool_t			fini = FALSE;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	INIT_ULOG(context);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	no_of_updates = incr_ret->updates.kdb_ulog_t_len;
3177c478bd9Sstevel@tonic-gate 	upd = incr_ret->updates.kdb_ulog_t_val;
3187c478bd9Sstevel@tonic-gate 	fupd = upd;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/*
32154925bf6Swillf 	 * We reset last_sno and last_time to 0, if krb5_db_put_principal
32254925bf6Swillf 	 * or krb5_db_delete_principal fail.
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	errlast.last_sno = (unsigned int)0;
3257c478bd9Sstevel@tonic-gate 	errlast.last_time.seconds = (unsigned int)0;
3267c478bd9Sstevel@tonic-gate 	errlast.last_time.useconds = (unsigned int)0;
3277c478bd9Sstevel@tonic-gate 
328*67c90040Ssemery 	if (krb5_db_inited(context)) {
329*67c90040Ssemery 		retval = krb5_db_open(context, NULL,
330*67c90040Ssemery 		    KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
331*67c90040Ssemery 		if (retval != 0)
3327c478bd9Sstevel@tonic-gate 			goto cleanup;
333*67c90040Ssemery 		fini = TRUE;
334*67c90040Ssemery 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	for (i = 0; i < no_of_updates; i++) {
3377c478bd9Sstevel@tonic-gate 		int nentry = 1;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		if (!upd->kdb_commit)
3407c478bd9Sstevel@tonic-gate 			continue;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 		if (upd->kdb_deleted) {
3437c478bd9Sstevel@tonic-gate 			dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len
3447c478bd9Sstevel@tonic-gate 			    + 1) * sizeof (char));
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 			if (dbprincstr == NULL) {
3477c478bd9Sstevel@tonic-gate 				retval = ENOMEM;
3487c478bd9Sstevel@tonic-gate 				goto cleanup;
3497c478bd9Sstevel@tonic-gate 			}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 			(void) strlcpy(dbprincstr,
3527c478bd9Sstevel@tonic-gate 			    (char *)upd->kdb_princ_name.utf8str_t_val,
3537c478bd9Sstevel@tonic-gate 			    (upd->kdb_princ_name.utf8str_t_len + 1));
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 			if (retval = krb5_parse_name(context, dbprincstr,
3567c478bd9Sstevel@tonic-gate 			    &dbprinc)) {
3577c478bd9Sstevel@tonic-gate 				goto cleanup;
3587c478bd9Sstevel@tonic-gate 			}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 			if (dbprincstr)
3617c478bd9Sstevel@tonic-gate 				free(dbprincstr);
3627c478bd9Sstevel@tonic-gate 
36354925bf6Swillf 			retval = krb5_db_delete_principal(context,
3647c478bd9Sstevel@tonic-gate 			    dbprinc, &nentry);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 			if (dbprinc)
3677c478bd9Sstevel@tonic-gate 				krb5_free_principal(context, dbprinc);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 			if (retval)
3707c478bd9Sstevel@tonic-gate 				goto cleanup;
3717c478bd9Sstevel@tonic-gate 		} else {
3727c478bd9Sstevel@tonic-gate 			entry = (krb5_db_entry *)malloc(sizeof (krb5_db_entry));
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 			if (!entry) {
3757c478bd9Sstevel@tonic-gate 				retval = errno;
3767c478bd9Sstevel@tonic-gate 				goto cleanup;
3777c478bd9Sstevel@tonic-gate 			}
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 			(void) memset(entry, 0, sizeof (krb5_db_entry));
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 			if (retval = ulog_conv_2dbentry(context, entry, upd, 1))
3827c478bd9Sstevel@tonic-gate 				goto cleanup;
3837c478bd9Sstevel@tonic-gate 
38454925bf6Swillf 			retval = krb5_db_put_principal(context, entry,
3857c478bd9Sstevel@tonic-gate 			    &nentry);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 			if (entry) {
3887c478bd9Sstevel@tonic-gate 				krb5_db_free_principal(context, entry, nentry);
3897c478bd9Sstevel@tonic-gate 				free(entry);
3907c478bd9Sstevel@tonic-gate 				entry = NULL;
3917c478bd9Sstevel@tonic-gate 			}
3927c478bd9Sstevel@tonic-gate 			if (retval)
3937c478bd9Sstevel@tonic-gate 				goto cleanup;
3947c478bd9Sstevel@tonic-gate 		}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		upd++;
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate cleanup:
4007c478bd9Sstevel@tonic-gate 	if (fupd)
4017c478bd9Sstevel@tonic-gate 		ulog_free_entries(fupd, no_of_updates);
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
4047c478bd9Sstevel@tonic-gate 		if (retval)
4057c478bd9Sstevel@tonic-gate 			ulog_finish_update_slave(ulog, errlast);
4067c478bd9Sstevel@tonic-gate 		else
4077c478bd9Sstevel@tonic-gate 			ulog_finish_update_slave(ulog, incr_ret->lastentry);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
410*67c90040Ssemery 	if (fini == TRUE)
411*67c90040Ssemery 		krb5_db_fini(context);
412*67c90040Ssemery 
4137c478bd9Sstevel@tonic-gate 	return (retval);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * Validate the log file and resync any uncommitted update entries
4187c478bd9Sstevel@tonic-gate  * to the principal database.
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate krb5_error_code
4217c478bd9Sstevel@tonic-gate ulog_check(krb5_context context, kdb_hlog_t *ulog)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	XDR			xdrs;
4247c478bd9Sstevel@tonic-gate 	krb5_error_code		retval = 0;
4257c478bd9Sstevel@tonic-gate 	int			i;
4267c478bd9Sstevel@tonic-gate 	kdb_ent_header_t	*indx_log;
4277c478bd9Sstevel@tonic-gate 	kdb_incr_update_t	*upd = NULL;
4287c478bd9Sstevel@tonic-gate 	kdb_incr_result_t	*incr_ret = NULL;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	ulog->kdb_state = KDB_STABLE;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	for (i = 0; i < ulog->kdb_num; i++) {
4337c478bd9Sstevel@tonic-gate 		indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		if (indx_log->kdb_umagic != KDB_UMAGIC) {
4367c478bd9Sstevel@tonic-gate 			/*
4377c478bd9Sstevel@tonic-gate 			 * Update entry corrupted we should scream and die
4387c478bd9Sstevel@tonic-gate 			 */
4397c478bd9Sstevel@tonic-gate 			ulog->kdb_state = KDB_CORRUPT;
4407c478bd9Sstevel@tonic-gate 			retval = KRB5_LOG_CORRUPT;
4417c478bd9Sstevel@tonic-gate 			break;
4427c478bd9Sstevel@tonic-gate 		}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 		if (indx_log->kdb_commit == FALSE) {
4457c478bd9Sstevel@tonic-gate 			ulog->kdb_state = KDB_UNSTABLE;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 			incr_ret = (kdb_incr_result_t *)
4487c478bd9Sstevel@tonic-gate 			    malloc(sizeof (kdb_incr_result_t));
4497c478bd9Sstevel@tonic-gate 			if (incr_ret == NULL) {
4507c478bd9Sstevel@tonic-gate 				retval = errno;
4517c478bd9Sstevel@tonic-gate 				goto error;
4527c478bd9Sstevel@tonic-gate 			}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 			upd = (kdb_incr_update_t *)
4557c478bd9Sstevel@tonic-gate 			    malloc(sizeof (kdb_incr_update_t));
4567c478bd9Sstevel@tonic-gate 			if (upd == NULL) {
4577c478bd9Sstevel@tonic-gate 				retval = errno;
4587c478bd9Sstevel@tonic-gate 				goto error;
4597c478bd9Sstevel@tonic-gate 			}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 			(void) memset(upd, 0, sizeof (kdb_incr_update_t));
4627c478bd9Sstevel@tonic-gate 			xdrmem_create(&xdrs, (char *)indx_log->entry_data,
4637c478bd9Sstevel@tonic-gate 			    indx_log->kdb_entry_size, XDR_DECODE);
4647c478bd9Sstevel@tonic-gate 			if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
4657c478bd9Sstevel@tonic-gate 				retval = KRB5_LOG_CONV;
4667c478bd9Sstevel@tonic-gate 				goto error;
4677c478bd9Sstevel@tonic-gate 			}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 			incr_ret->updates.kdb_ulog_t_len = 1;
4707c478bd9Sstevel@tonic-gate 			incr_ret->updates.kdb_ulog_t_val = upd;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 			upd->kdb_commit = TRUE;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 			/*
4757c478bd9Sstevel@tonic-gate 			 * We don't want to readd this update and just use the
4767c478bd9Sstevel@tonic-gate 			 * existing update to be propagated later on
4777c478bd9Sstevel@tonic-gate 			 */
4787c478bd9Sstevel@tonic-gate 			ulog_set_role(context, IPROP_NULL);
4797c478bd9Sstevel@tonic-gate 			retval = ulog_replay(context, incr_ret);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 			/*
4827c478bd9Sstevel@tonic-gate 			 * upd was freed by ulog_replay, we NULL
4837c478bd9Sstevel@tonic-gate 			 * the pointer in case we subsequently break from loop.
4847c478bd9Sstevel@tonic-gate 			 */
4857c478bd9Sstevel@tonic-gate 			upd = NULL;
4867c478bd9Sstevel@tonic-gate 			if (incr_ret) {
4877c478bd9Sstevel@tonic-gate 				free(incr_ret);
4887c478bd9Sstevel@tonic-gate 				incr_ret = NULL;
4897c478bd9Sstevel@tonic-gate 			}
4907c478bd9Sstevel@tonic-gate 			ulog_set_role(context, IPROP_MASTER);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 			if (retval)
4937c478bd9Sstevel@tonic-gate 				goto error;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 			/*
4967c478bd9Sstevel@tonic-gate 			 * We flag this as committed since this was
4977c478bd9Sstevel@tonic-gate 			 * the last entry before kadmind crashed, ergo
4987c478bd9Sstevel@tonic-gate 			 * the slaves have not seen this update before
4997c478bd9Sstevel@tonic-gate 			 */
5007c478bd9Sstevel@tonic-gate 			indx_log->kdb_commit = TRUE;
5017c478bd9Sstevel@tonic-gate 			retval = ulog_sync_update(ulog, indx_log);
5027c478bd9Sstevel@tonic-gate 			if (retval)
5037c478bd9Sstevel@tonic-gate 				goto error;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 			ulog->kdb_state = KDB_STABLE;
5067c478bd9Sstevel@tonic-gate 		}
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate error:
5107c478bd9Sstevel@tonic-gate 	if (upd)
5117c478bd9Sstevel@tonic-gate 		ulog_free_entries(upd, 1);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (incr_ret)
5147c478bd9Sstevel@tonic-gate 		free(incr_ret);
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	ulog_sync_header(ulog);
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	return (retval);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate  * Map the log file to memory for performance and simplicity.
5237c478bd9Sstevel@tonic-gate  *
5247c478bd9Sstevel@tonic-gate  * Called by: if iprop_enabled then ulog_map();
5257c478bd9Sstevel@tonic-gate  * Assumes that the caller will terminate on ulog_map, hence munmap and
5267c478bd9Sstevel@tonic-gate  * closing of the fd are implicitly performed by the caller.
5277c478bd9Sstevel@tonic-gate  * Returns 0 on success else failure.
5287c478bd9Sstevel@tonic-gate  */
5297c478bd9Sstevel@tonic-gate krb5_error_code
5307c478bd9Sstevel@tonic-gate ulog_map(krb5_context context, kadm5_config_params *params, int caller)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	struct stat	st;
5337c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
5347c478bd9Sstevel@tonic-gate 	uint32_t	ulog_filesize;
5357c478bd9Sstevel@tonic-gate 	char		logname[MAX_FILENAME];
5367c478bd9Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
5377c478bd9Sstevel@tonic-gate 	kdb_hlog_t	*ulog = NULL;
5387c478bd9Sstevel@tonic-gate 	uint32_t	ulogentries;
5397c478bd9Sstevel@tonic-gate 	int		ulogfd = -1;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	if ((caller == FKADMIND) || (caller == FKCOMMAND))
5427c478bd9Sstevel@tonic-gate 		ulogentries = params->iprop_ulogsize;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	ulog_filesize = sizeof (kdb_hlog_t);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (strlcpy(logname, params->dbname, MAX_FILENAME) >= MAX_FILENAME)
5477c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
5487c478bd9Sstevel@tonic-gate 	if (strlcat(logname, ".ulog", MAX_FILENAME) >= MAX_FILENAME)
5497c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_ERROR);
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (stat(logname, &st) == -1) {
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 		if (caller == FKPROPLOG) {
5547c478bd9Sstevel@tonic-gate 			/*
5557c478bd9Sstevel@tonic-gate 			 * File doesn't exist so we exit with kproplog
5567c478bd9Sstevel@tonic-gate 			 */
5577c478bd9Sstevel@tonic-gate 			return (errno);
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		if ((ulogfd = open(logname, O_RDWR+O_CREAT, 0600)) == -1) {
5617c478bd9Sstevel@tonic-gate 			return (errno);
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		if (lseek(ulogfd, 0L, SEEK_CUR) == -1) {
5657c478bd9Sstevel@tonic-gate 			return (errno);
5667c478bd9Sstevel@tonic-gate 		}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 		if ((caller == FKADMIND) || (caller == FKCOMMAND))
5697c478bd9Sstevel@tonic-gate 			ulog_filesize += ulogentries * ULOG_BLOCK;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 		if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) {
5727c478bd9Sstevel@tonic-gate 			return (errno);
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		if (write(ulogfd, "+", 1) != 1) {
5767c478bd9Sstevel@tonic-gate 			return (errno);
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	} else {
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		if ((ulogfd = open(logname, O_RDWR, 0600)) == -1) {
5827c478bd9Sstevel@tonic-gate 			/*
5837c478bd9Sstevel@tonic-gate 			 * Can't open existing log file
5847c478bd9Sstevel@tonic-gate 			 */
5857c478bd9Sstevel@tonic-gate 			return (errno);
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	if (caller == FKPROPLOG) {
5907c478bd9Sstevel@tonic-gate 		fstat(ulogfd, &st);
5917c478bd9Sstevel@tonic-gate 		ulog_filesize = st.st_size;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 		ulog = (kdb_hlog_t *)mmap(0, ulog_filesize,
5947c478bd9Sstevel@tonic-gate 		    PROT_READ+PROT_WRITE, MAP_PRIVATE, ulogfd, 0);
5957c478bd9Sstevel@tonic-gate 	} else {
5967c478bd9Sstevel@tonic-gate 		/*
5977c478bd9Sstevel@tonic-gate 		 * else kadmind, kpropd, & kcommands should udpate stores
5987c478bd9Sstevel@tonic-gate 		 */
5997c478bd9Sstevel@tonic-gate 		ulog = (kdb_hlog_t *)mmap(0, MAXLOGLEN,
6007c478bd9Sstevel@tonic-gate 		    PROT_READ+PROT_WRITE, MAP_SHARED, ulogfd, 0);
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	if ((int)(ulog) == -1) {
6047c478bd9Sstevel@tonic-gate 		/*
6057c478bd9Sstevel@tonic-gate 		 * Can't map update log file to memory
6067c478bd9Sstevel@tonic-gate 		 */
6077c478bd9Sstevel@tonic-gate 		return (errno);
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	if (!context->kdblog_context) {
6117c478bd9Sstevel@tonic-gate 		if (!(log_ctx = malloc(sizeof (kdb_log_context))))
6127c478bd9Sstevel@tonic-gate 			return (errno);
6137c478bd9Sstevel@tonic-gate 		context->kdblog_context = (void *)log_ctx;
6147c478bd9Sstevel@tonic-gate 	} else
6157c478bd9Sstevel@tonic-gate 		log_ctx = context->kdblog_context;
6167c478bd9Sstevel@tonic-gate 	log_ctx->ulog = ulog;
6177c478bd9Sstevel@tonic-gate 	log_ctx->ulogentries = ulogentries;
6187c478bd9Sstevel@tonic-gate 	log_ctx->ulogfd = ulogfd;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (ulog->kdb_hmagic != KDB_HMAGIC) {
6217c478bd9Sstevel@tonic-gate 		if (ulog->kdb_hmagic == 0) {
6227c478bd9Sstevel@tonic-gate 			/*
6237c478bd9Sstevel@tonic-gate 			 * New update log
6247c478bd9Sstevel@tonic-gate 			 */
6257c478bd9Sstevel@tonic-gate 			(void) memset(ulog, 0, sizeof (kdb_hlog_t));
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 			ulog->kdb_hmagic = KDB_HMAGIC;
6287c478bd9Sstevel@tonic-gate 			ulog->db_version_num = KDB_VERSION;
6297c478bd9Sstevel@tonic-gate 			ulog->kdb_state = KDB_STABLE;
6307c478bd9Sstevel@tonic-gate 			ulog->kdb_block = ULOG_BLOCK;
6317c478bd9Sstevel@tonic-gate 			if (!(caller == FKPROPLOG))
6327c478bd9Sstevel@tonic-gate 				ulog_sync_header(ulog);
6337c478bd9Sstevel@tonic-gate 		} else {
6347c478bd9Sstevel@tonic-gate 			return (KRB5_LOG_CORRUPT);
6357c478bd9Sstevel@tonic-gate 		}
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (caller == FKADMIND) {
6397c478bd9Sstevel@tonic-gate 		switch (ulog->kdb_state) {
6407c478bd9Sstevel@tonic-gate 			case KDB_STABLE:
6417c478bd9Sstevel@tonic-gate 			case KDB_UNSTABLE:
6427c478bd9Sstevel@tonic-gate 				/*
6437c478bd9Sstevel@tonic-gate 				 * Log is currently un/stable, check anyway
6447c478bd9Sstevel@tonic-gate 				 */
6457c478bd9Sstevel@tonic-gate 				retval = ulog_check(context, ulog);
6467c478bd9Sstevel@tonic-gate 				if (retval == KRB5_LOG_CORRUPT) {
6477c478bd9Sstevel@tonic-gate 					return (retval);
6487c478bd9Sstevel@tonic-gate 				}
6497c478bd9Sstevel@tonic-gate 				break;
6507c478bd9Sstevel@tonic-gate 			case KDB_CORRUPT:
6517c478bd9Sstevel@tonic-gate 				return (KRB5_LOG_CORRUPT);
6527c478bd9Sstevel@tonic-gate 			default:
6537c478bd9Sstevel@tonic-gate 				/*
6547c478bd9Sstevel@tonic-gate 				 * Invalid db state
6557c478bd9Sstevel@tonic-gate 				 */
6567c478bd9Sstevel@tonic-gate 				return (KRB5_LOG_ERROR);
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 	} else if ((caller == FKPROPLOG) || (caller == FKPROPD)) {
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * kproplog and kpropd don't need to do anything else
6617c478bd9Sstevel@tonic-gate 		 */
6627c478bd9Sstevel@tonic-gate 		return (0);
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/*
6667c478bd9Sstevel@tonic-gate 	 * Reinit ulog if the log is being truncated or expanded after
6677c478bd9Sstevel@tonic-gate 	 * we have circled.
6687c478bd9Sstevel@tonic-gate 	 */
6697c478bd9Sstevel@tonic-gate 	if (ulog->kdb_num != ulogentries) {
6707c478bd9Sstevel@tonic-gate 		if ((ulog->kdb_num != 0) &&
6717c478bd9Sstevel@tonic-gate 		    ((ulog->kdb_last_sno > ulog->kdb_num) ||
6727c478bd9Sstevel@tonic-gate 		    (ulog->kdb_num > ulogentries))) {
6737c478bd9Sstevel@tonic-gate 			(void) memset(ulog, 0, sizeof (kdb_hlog_t));
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 			ulog->kdb_hmagic = KDB_HMAGIC;
6767c478bd9Sstevel@tonic-gate 			ulog->db_version_num = KDB_VERSION;
6777c478bd9Sstevel@tonic-gate 			ulog->kdb_state = KDB_STABLE;
6787c478bd9Sstevel@tonic-gate 			ulog->kdb_block = ULOG_BLOCK;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 			ulog_sync_header(ulog);
6817c478bd9Sstevel@tonic-gate 		}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		/*
6847c478bd9Sstevel@tonic-gate 		 * Expand ulog if we have specified a greater size
6857c478bd9Sstevel@tonic-gate 		 */
6867c478bd9Sstevel@tonic-gate 		if (ulog->kdb_num < ulogentries) {
6877c478bd9Sstevel@tonic-gate 			ulog_filesize += ulogentries * ulog->kdb_block;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 			if (lseek(ulogfd, ulog_filesize, SEEK_SET) == -1) {
6907c478bd9Sstevel@tonic-gate 				return (errno);
6917c478bd9Sstevel@tonic-gate 			}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 			if (write(ulogfd, "+", 1) != 1) {
6947c478bd9Sstevel@tonic-gate 				return (errno);
6957c478bd9Sstevel@tonic-gate 			}
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	return (0);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate  * Get the last set of updates seen, (last+1) to n is returned.
7047c478bd9Sstevel@tonic-gate  */
7057c478bd9Sstevel@tonic-gate krb5_error_code
7067c478bd9Sstevel@tonic-gate ulog_get_entries(
7077c478bd9Sstevel@tonic-gate 	krb5_context context,		/* input - krb5 lib config */
7087c478bd9Sstevel@tonic-gate 	kdb_last_t last,		/* input - slave's last sno */
7097c478bd9Sstevel@tonic-gate 	kdb_incr_result_t *ulog_handle)	/* output - incr result for slave */
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate 	XDR			xdrs;
7127c478bd9Sstevel@tonic-gate 	kdb_ent_header_t	*indx_log;
7137c478bd9Sstevel@tonic-gate 	kdb_incr_update_t	*upd;
7147c478bd9Sstevel@tonic-gate 	uint_t			indx, count, tdiff;
7157c478bd9Sstevel@tonic-gate 	uint32_t		sno;
7167c478bd9Sstevel@tonic-gate 	krb5_error_code		retval;
7177c478bd9Sstevel@tonic-gate 	struct timeval		timestamp;
7187c478bd9Sstevel@tonic-gate 	kdb_log_context		*log_ctx;
7197c478bd9Sstevel@tonic-gate 	kdb_hlog_t		*ulog = NULL;
7207c478bd9Sstevel@tonic-gate 	uint32_t		ulogentries;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	INIT_ULOG(context);
7237c478bd9Sstevel@tonic-gate 	ulogentries = log_ctx->ulogentries;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/*
7267c478bd9Sstevel@tonic-gate 	 * Check to make sure we don't have a corrupt ulog first.
7277c478bd9Sstevel@tonic-gate 	 */
7287c478bd9Sstevel@tonic-gate 	if (ulog->kdb_state == KDB_CORRUPT) {
7297c478bd9Sstevel@tonic-gate 		ulog_handle->ret = UPDATE_ERROR;
7307c478bd9Sstevel@tonic-gate 		return (KRB5_LOG_CORRUPT);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	gettimeofday(&timestamp, NULL);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;
7367c478bd9Sstevel@tonic-gate 	if (tdiff <= ULOG_IDLE_TIME) {
7377c478bd9Sstevel@tonic-gate 		ulog_handle->ret = UPDATE_BUSY;
7387c478bd9Sstevel@tonic-gate 		return (0);
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	/*
7427c478bd9Sstevel@tonic-gate 	 * We need to lock out other processes here, such as kadmin.local,
7437c478bd9Sstevel@tonic-gate 	 * since we are looking at the last_sno and looking up updates.  So
7447c478bd9Sstevel@tonic-gate 	 * we can share with other readers.
7457c478bd9Sstevel@tonic-gate 	 */
7467c478bd9Sstevel@tonic-gate 	retval = krb5_db_lock(context, KRB5_LOCKMODE_SHARED);
7477c478bd9Sstevel@tonic-gate 	if (retval)
7487c478bd9Sstevel@tonic-gate 		return (retval);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	/*
7517c478bd9Sstevel@tonic-gate 	 * We may have overflowed the update log or we shrunk the log, or
7527c478bd9Sstevel@tonic-gate 	 * the client's ulog has just been created.
7537c478bd9Sstevel@tonic-gate 	 */
7547c478bd9Sstevel@tonic-gate 	if ((last.last_sno > ulog->kdb_last_sno) ||
7557c478bd9Sstevel@tonic-gate 	    (last.last_sno < ulog->kdb_first_sno) ||
7567c478bd9Sstevel@tonic-gate 	    (last.last_sno == 0)) {
7577c478bd9Sstevel@tonic-gate 		ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
7587c478bd9Sstevel@tonic-gate 		(void) krb5_db_unlock(context);
7597c478bd9Sstevel@tonic-gate 		ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
7607c478bd9Sstevel@tonic-gate 		return (0);
7617c478bd9Sstevel@tonic-gate 	} else if (last.last_sno <= ulog->kdb_last_sno) {
7627c478bd9Sstevel@tonic-gate 		sno = last.last_sno;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 		indx = (sno - 1) % ulogentries;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 		indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 		/*
7697c478bd9Sstevel@tonic-gate 		 * Validate the time stamp just to make sure it was the same sno
7707c478bd9Sstevel@tonic-gate 		 */
7717c478bd9Sstevel@tonic-gate 		if ((indx_log->kdb_time.seconds == last.last_time.seconds) &&
7727c478bd9Sstevel@tonic-gate 		    (indx_log->kdb_time.useconds == last.last_time.useconds)) {
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 			/*
7757c478bd9Sstevel@tonic-gate 			 * If we have the same sno we return success
7767c478bd9Sstevel@tonic-gate 			 */
7777c478bd9Sstevel@tonic-gate 			if (last.last_sno == ulog->kdb_last_sno) {
7787c478bd9Sstevel@tonic-gate 				(void) krb5_db_unlock(context);
7797c478bd9Sstevel@tonic-gate 				ulog_handle->ret = UPDATE_NIL;
7807c478bd9Sstevel@tonic-gate 				return (0);
7817c478bd9Sstevel@tonic-gate 			}
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 			count = ulog->kdb_last_sno - sno;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 			ulog_handle->updates.kdb_ulog_t_val =
7867c478bd9Sstevel@tonic-gate 			    (kdb_incr_update_t *)malloc(
7877c478bd9Sstevel@tonic-gate 			    sizeof (kdb_incr_update_t) * count);
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 			upd = ulog_handle->updates.kdb_ulog_t_val;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 			if (upd == NULL) {
7927c478bd9Sstevel@tonic-gate 				(void) krb5_db_unlock(context);
7937c478bd9Sstevel@tonic-gate 				ulog_handle->ret = UPDATE_ERROR;
7947c478bd9Sstevel@tonic-gate 				return (errno);
7957c478bd9Sstevel@tonic-gate 			}
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 			while (sno < ulog->kdb_last_sno) {
7987c478bd9Sstevel@tonic-gate 				indx = sno % ulogentries;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 				indx_log = (kdb_ent_header_t *)
8017c478bd9Sstevel@tonic-gate 				    INDEX(ulog, indx);
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 				(void) memset(upd, 0,
8047c478bd9Sstevel@tonic-gate 				    sizeof (kdb_incr_update_t));
8057c478bd9Sstevel@tonic-gate 				xdrmem_create(&xdrs,
8067c478bd9Sstevel@tonic-gate 				    (char *)indx_log->entry_data,
8077c478bd9Sstevel@tonic-gate 				    indx_log->kdb_entry_size, XDR_DECODE);
8087c478bd9Sstevel@tonic-gate 				if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
8097c478bd9Sstevel@tonic-gate 					(void) krb5_db_unlock(context);
8107c478bd9Sstevel@tonic-gate 					ulog_handle->ret = UPDATE_ERROR;
8117c478bd9Sstevel@tonic-gate 					return (KRB5_LOG_CONV);
8127c478bd9Sstevel@tonic-gate 				}
8137c478bd9Sstevel@tonic-gate 				/*
8147c478bd9Sstevel@tonic-gate 				 * Mark commitment since we didn't
8157c478bd9Sstevel@tonic-gate 				 * want to decode and encode the
8167c478bd9Sstevel@tonic-gate 				 * incr update record the first time.
8177c478bd9Sstevel@tonic-gate 				 */
8187c478bd9Sstevel@tonic-gate 				upd->kdb_commit = indx_log->kdb_commit;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 				upd++;
8217c478bd9Sstevel@tonic-gate 				sno++;
8227c478bd9Sstevel@tonic-gate 			} /* while */
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 			ulog_handle->updates.kdb_ulog_t_len = count;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 			ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
8277c478bd9Sstevel@tonic-gate 			ulog_handle->lastentry.last_time.seconds =
8287c478bd9Sstevel@tonic-gate 			    ulog->kdb_last_time.seconds;
8297c478bd9Sstevel@tonic-gate 			ulog_handle->lastentry.last_time.useconds =
8307c478bd9Sstevel@tonic-gate 			    ulog->kdb_last_time.useconds;
8317c478bd9Sstevel@tonic-gate 			ulog_handle->ret = UPDATE_OK;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 			(void) krb5_db_unlock(context);
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 			return (0);
8367c478bd9Sstevel@tonic-gate 		} else {
8377c478bd9Sstevel@tonic-gate 			/*
8387c478bd9Sstevel@tonic-gate 			 * We have time stamp mismatch or we no longer have
8397c478bd9Sstevel@tonic-gate 			 * the slave's last sno, so we brute force it
8407c478bd9Sstevel@tonic-gate 			 */
8417c478bd9Sstevel@tonic-gate 			(void) krb5_db_unlock(context);
8427c478bd9Sstevel@tonic-gate 			ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 			return (0);
8457c478bd9Sstevel@tonic-gate 		}
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/*
8497c478bd9Sstevel@tonic-gate 	 * Should never get here, return error
8507c478bd9Sstevel@tonic-gate 	 */
8517c478bd9Sstevel@tonic-gate 	ulog_handle->ret = UPDATE_ERROR;
8527c478bd9Sstevel@tonic-gate 	return (KRB5_LOG_ERROR);
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate krb5_error_code
8567c478bd9Sstevel@tonic-gate ulog_set_role(krb5_context ctx, iprop_role role)
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	if (!ctx->kdblog_context) {
8617c478bd9Sstevel@tonic-gate 		if (!(log_ctx = malloc(sizeof (kdb_log_context))))
8627c478bd9Sstevel@tonic-gate 			return (errno);
8637c478bd9Sstevel@tonic-gate 		ctx->kdblog_context = (void *)log_ctx;
8647c478bd9Sstevel@tonic-gate 	} else
8657c478bd9Sstevel@tonic-gate 		log_ctx = ctx->kdblog_context;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	log_ctx->iproprole = role;
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	return (0);
8707c478bd9Sstevel@tonic-gate }
871