xref: /freebsd/crypto/krb5/src/lib/kdb/kdb_log.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
4*7f2fe78bSCy Schubert  * Use is subject to license terms.
5*7f2fe78bSCy Schubert  */
6*7f2fe78bSCy Schubert 
7*7f2fe78bSCy Schubert #include <sys/stat.h>
8*7f2fe78bSCy Schubert #include <sys/types.h>
9*7f2fe78bSCy Schubert #include <unistd.h>
10*7f2fe78bSCy Schubert #include <fcntl.h>
11*7f2fe78bSCy Schubert #include <sys/mman.h>
12*7f2fe78bSCy Schubert #include <k5-int.h>
13*7f2fe78bSCy Schubert #include <stdlib.h>
14*7f2fe78bSCy Schubert #include <limits.h>
15*7f2fe78bSCy Schubert #include <syslog.h>
16*7f2fe78bSCy Schubert #include "kdb5.h"
17*7f2fe78bSCy Schubert #include "kdb_log.h"
18*7f2fe78bSCy Schubert #include "kdb5int.h"
19*7f2fe78bSCy Schubert 
20*7f2fe78bSCy Schubert #ifndef MAP_FAILED
21*7f2fe78bSCy Schubert #define MAP_FAILED ((void *)-1)
22*7f2fe78bSCy Schubert #endif
23*7f2fe78bSCy Schubert 
24*7f2fe78bSCy Schubert /* This module includes all the necessary functions that create and modify the
25*7f2fe78bSCy Schubert  * Kerberos principal update and header logs. */
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert #define getpagesize() sysconf(_SC_PAGESIZE)
28*7f2fe78bSCy Schubert 
29*7f2fe78bSCy Schubert static int pagesize = 0;
30*7f2fe78bSCy Schubert 
31*7f2fe78bSCy Schubert #define INIT_ULOG(ctx)                          \
32*7f2fe78bSCy Schubert     log_ctx = ctx->kdblog_context;              \
33*7f2fe78bSCy Schubert     assert(log_ctx != NULL);                    \
34*7f2fe78bSCy Schubert     ulog = log_ctx->ulog;                       \
35*7f2fe78bSCy Schubert     assert(ulog != NULL)
36*7f2fe78bSCy Schubert 
37*7f2fe78bSCy Schubert /* Initialize context->kdblog_context if it does not yet exist, and return it.
38*7f2fe78bSCy Schubert  * Return NULL on allocation failure. */
39*7f2fe78bSCy Schubert static kdb_log_context *
create_log_context(krb5_context context)40*7f2fe78bSCy Schubert create_log_context(krb5_context context)
41*7f2fe78bSCy Schubert {
42*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
43*7f2fe78bSCy Schubert 
44*7f2fe78bSCy Schubert     if (context->kdblog_context != NULL)
45*7f2fe78bSCy Schubert         return context->kdblog_context;
46*7f2fe78bSCy Schubert     log_ctx = calloc(1, sizeof(*log_ctx));
47*7f2fe78bSCy Schubert     if (log_ctx == NULL)
48*7f2fe78bSCy Schubert         return NULL;
49*7f2fe78bSCy Schubert     log_ctx->ulogfd = -1;
50*7f2fe78bSCy Schubert     context->kdblog_context = log_ctx;
51*7f2fe78bSCy Schubert     return log_ctx;
52*7f2fe78bSCy Schubert }
53*7f2fe78bSCy Schubert 
54*7f2fe78bSCy Schubert static inline krb5_boolean
time_equal(const kdbe_time_t * a,const kdbe_time_t * b)55*7f2fe78bSCy Schubert time_equal(const kdbe_time_t *a, const kdbe_time_t *b)
56*7f2fe78bSCy Schubert {
57*7f2fe78bSCy Schubert     return a->seconds == b->seconds && a->useconds == b->useconds;
58*7f2fe78bSCy Schubert }
59*7f2fe78bSCy Schubert 
60*7f2fe78bSCy Schubert static void
time_current(kdbe_time_t * out)61*7f2fe78bSCy Schubert time_current(kdbe_time_t *out)
62*7f2fe78bSCy Schubert {
63*7f2fe78bSCy Schubert     struct timeval timestamp;
64*7f2fe78bSCy Schubert 
65*7f2fe78bSCy Schubert     (void)gettimeofday(&timestamp, NULL);
66*7f2fe78bSCy Schubert     out->seconds = timestamp.tv_sec;
67*7f2fe78bSCy Schubert     out->useconds = timestamp.tv_usec;
68*7f2fe78bSCy Schubert }
69*7f2fe78bSCy Schubert 
70*7f2fe78bSCy Schubert /* Sync update entry to disk. */
71*7f2fe78bSCy Schubert static void
sync_update(kdb_hlog_t * ulog,kdb_ent_header_t * upd)72*7f2fe78bSCy Schubert sync_update(kdb_hlog_t *ulog, kdb_ent_header_t *upd)
73*7f2fe78bSCy Schubert {
74*7f2fe78bSCy Schubert     unsigned long start, end, size;
75*7f2fe78bSCy Schubert 
76*7f2fe78bSCy Schubert     if (!pagesize)
77*7f2fe78bSCy Schubert         pagesize = getpagesize();
78*7f2fe78bSCy Schubert 
79*7f2fe78bSCy Schubert     start = (unsigned long)upd & ~(pagesize - 1);
80*7f2fe78bSCy Schubert 
81*7f2fe78bSCy Schubert     end = ((unsigned long)upd + ulog->kdb_block + (pagesize - 1)) &
82*7f2fe78bSCy Schubert         ~(pagesize - 1);
83*7f2fe78bSCy Schubert 
84*7f2fe78bSCy Schubert     size = end - start;
85*7f2fe78bSCy Schubert     if (msync((caddr_t)start, size, MS_SYNC)) {
86*7f2fe78bSCy Schubert         /* Couldn't sync to disk, let's panic. */
87*7f2fe78bSCy Schubert         syslog(LOG_ERR, _("could not sync ulog update to disk"));
88*7f2fe78bSCy Schubert         abort();
89*7f2fe78bSCy Schubert     }
90*7f2fe78bSCy Schubert }
91*7f2fe78bSCy Schubert 
92*7f2fe78bSCy Schubert /* Sync memory to disk for the update log header. */
93*7f2fe78bSCy Schubert static void
sync_header(kdb_hlog_t * ulog)94*7f2fe78bSCy Schubert sync_header(kdb_hlog_t *ulog)
95*7f2fe78bSCy Schubert {
96*7f2fe78bSCy Schubert     if (!pagesize)
97*7f2fe78bSCy Schubert         pagesize = getpagesize();
98*7f2fe78bSCy Schubert 
99*7f2fe78bSCy Schubert     if (msync((caddr_t)ulog, pagesize, MS_SYNC)) {
100*7f2fe78bSCy Schubert         /* Couldn't sync to disk, let's panic. */
101*7f2fe78bSCy Schubert         syslog(LOG_ERR, _("could not sync ulog header to disk"));
102*7f2fe78bSCy Schubert         abort();
103*7f2fe78bSCy Schubert     }
104*7f2fe78bSCy Schubert }
105*7f2fe78bSCy Schubert 
106*7f2fe78bSCy Schubert /* Return true if the ulog entry for sno matches sno and timestamp. */
107*7f2fe78bSCy Schubert static krb5_boolean
check_sno(kdb_log_context * log_ctx,kdb_sno_t sno,const kdbe_time_t * timestamp)108*7f2fe78bSCy Schubert check_sno(kdb_log_context *log_ctx, kdb_sno_t sno,
109*7f2fe78bSCy Schubert           const kdbe_time_t *timestamp)
110*7f2fe78bSCy Schubert {
111*7f2fe78bSCy Schubert     unsigned int indx = (sno - 1) % log_ctx->ulogentries;
112*7f2fe78bSCy Schubert     kdb_ent_header_t *ent = INDEX(log_ctx->ulog, indx);
113*7f2fe78bSCy Schubert 
114*7f2fe78bSCy Schubert     return ent->kdb_entry_sno == sno && time_equal(&ent->kdb_time, timestamp);
115*7f2fe78bSCy Schubert }
116*7f2fe78bSCy Schubert 
117*7f2fe78bSCy Schubert /*
118*7f2fe78bSCy Schubert  * Check last against our ulog and determine whether it is up to date
119*7f2fe78bSCy Schubert  * (UPDATE_NIL), so far out of date that a full dump is required
120*7f2fe78bSCy Schubert  * (UPDATE_FULL_RESYNC_NEEDED), or okay to update with ulog entries
121*7f2fe78bSCy Schubert  * (UPDATE_OK).
122*7f2fe78bSCy Schubert  */
123*7f2fe78bSCy Schubert static update_status_t
get_sno_status(kdb_log_context * log_ctx,const kdb_last_t * last)124*7f2fe78bSCy Schubert get_sno_status(kdb_log_context *log_ctx, const kdb_last_t *last)
125*7f2fe78bSCy Schubert {
126*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = log_ctx->ulog;
127*7f2fe78bSCy Schubert 
128*7f2fe78bSCy Schubert     /* If last matches the ulog's last serial number and time exactly, it are
129*7f2fe78bSCy Schubert      * up to date even if the ulog is empty. */
130*7f2fe78bSCy Schubert     if (last->last_sno == ulog->kdb_last_sno &&
131*7f2fe78bSCy Schubert         time_equal(&last->last_time, &ulog->kdb_last_time))
132*7f2fe78bSCy Schubert         return UPDATE_NIL;
133*7f2fe78bSCy Schubert 
134*7f2fe78bSCy Schubert     /* If our ulog is empty or does not contain last_sno, a full resync is
135*7f2fe78bSCy Schubert      * required. */
136*7f2fe78bSCy Schubert     if (ulog->kdb_num == 0 || last->last_sno > ulog->kdb_last_sno ||
137*7f2fe78bSCy Schubert         last->last_sno < ulog->kdb_first_sno)
138*7f2fe78bSCy Schubert         return UPDATE_FULL_RESYNC_NEEDED;
139*7f2fe78bSCy Schubert 
140*7f2fe78bSCy Schubert     /* If the timestamp in our ulog entry does not match last, then sno was
141*7f2fe78bSCy Schubert      * reused and a full resync is required. */
142*7f2fe78bSCy Schubert     if (!check_sno(log_ctx, last->last_sno, &last->last_time))
143*7f2fe78bSCy Schubert         return UPDATE_FULL_RESYNC_NEEDED;
144*7f2fe78bSCy Schubert 
145*7f2fe78bSCy Schubert     /* last is not fully up to date, but can be updated using our ulog. */
146*7f2fe78bSCy Schubert     return UPDATE_OK;
147*7f2fe78bSCy Schubert }
148*7f2fe78bSCy Schubert 
149*7f2fe78bSCy Schubert /* Extend update log file. */
150*7f2fe78bSCy Schubert static krb5_error_code
extend_file_to(int fd,unsigned int new_size)151*7f2fe78bSCy Schubert extend_file_to(int fd, unsigned int new_size)
152*7f2fe78bSCy Schubert {
153*7f2fe78bSCy Schubert     off_t current_offset;
154*7f2fe78bSCy Schubert     static const char zero[512];
155*7f2fe78bSCy Schubert     ssize_t wrote_size;
156*7f2fe78bSCy Schubert     size_t write_size;
157*7f2fe78bSCy Schubert 
158*7f2fe78bSCy Schubert     current_offset = lseek(fd, 0, SEEK_END);
159*7f2fe78bSCy Schubert     if (current_offset < 0)
160*7f2fe78bSCy Schubert         return errno;
161*7f2fe78bSCy Schubert     if (new_size > INT_MAX)
162*7f2fe78bSCy Schubert         return EINVAL;
163*7f2fe78bSCy Schubert     while (current_offset < (off_t)new_size) {
164*7f2fe78bSCy Schubert         write_size = new_size - current_offset;
165*7f2fe78bSCy Schubert         if (write_size > 512)
166*7f2fe78bSCy Schubert             write_size = 512;
167*7f2fe78bSCy Schubert         wrote_size = write(fd, zero, write_size);
168*7f2fe78bSCy Schubert         if (wrote_size < 0)
169*7f2fe78bSCy Schubert             return errno;
170*7f2fe78bSCy Schubert         if (wrote_size == 0)
171*7f2fe78bSCy Schubert             return EINVAL;
172*7f2fe78bSCy Schubert         current_offset += wrote_size;
173*7f2fe78bSCy Schubert         write_size = new_size - current_offset;
174*7f2fe78bSCy Schubert     }
175*7f2fe78bSCy Schubert     return 0;
176*7f2fe78bSCy Schubert }
177*7f2fe78bSCy Schubert 
178*7f2fe78bSCy Schubert /*
179*7f2fe78bSCy Schubert  * Resize the array elements.  We reinitialize the update log rather than
180*7f2fe78bSCy Schubert  * unrolling the the log and copying it over to a temporary log for obvious
181*7f2fe78bSCy Schubert  * performance reasons.  Replicas will subsequently do a full resync, but the
182*7f2fe78bSCy Schubert  * need for resizing should be very small.
183*7f2fe78bSCy Schubert  */
184*7f2fe78bSCy Schubert static krb5_error_code
resize(kdb_hlog_t * ulog,uint32_t ulogentries,int ulogfd,unsigned int recsize)185*7f2fe78bSCy Schubert resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd,
186*7f2fe78bSCy Schubert        unsigned int recsize)
187*7f2fe78bSCy Schubert {
188*7f2fe78bSCy Schubert     unsigned int new_block, new_size;
189*7f2fe78bSCy Schubert 
190*7f2fe78bSCy Schubert     if (ulog == NULL)
191*7f2fe78bSCy Schubert         return KRB5_LOG_ERROR;
192*7f2fe78bSCy Schubert 
193*7f2fe78bSCy Schubert     new_size = sizeof(kdb_hlog_t);
194*7f2fe78bSCy Schubert     new_block = (recsize / ULOG_BLOCK) + 1;
195*7f2fe78bSCy Schubert     new_block *= ULOG_BLOCK;
196*7f2fe78bSCy Schubert     new_size += ulogentries * new_block;
197*7f2fe78bSCy Schubert 
198*7f2fe78bSCy Schubert     if (new_size > MAXLOGLEN)
199*7f2fe78bSCy Schubert         return KRB5_LOG_ERROR;
200*7f2fe78bSCy Schubert 
201*7f2fe78bSCy Schubert     /* Reinit log with new block size. */
202*7f2fe78bSCy Schubert     memset(ulog, 0, sizeof(*ulog));
203*7f2fe78bSCy Schubert     ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
204*7f2fe78bSCy Schubert     ulog->db_version_num = KDB_VERSION;
205*7f2fe78bSCy Schubert     ulog->kdb_state = KDB_STABLE;
206*7f2fe78bSCy Schubert     ulog->kdb_block = new_block;
207*7f2fe78bSCy Schubert     sync_header(ulog);
208*7f2fe78bSCy Schubert 
209*7f2fe78bSCy Schubert     /* Expand log considering new block size. */
210*7f2fe78bSCy Schubert     return extend_file_to(ulogfd, new_size);
211*7f2fe78bSCy Schubert }
212*7f2fe78bSCy Schubert 
213*7f2fe78bSCy Schubert /* Set the ulog to contain only a dummy entry with the given serial number and
214*7f2fe78bSCy Schubert  * timestamp. */
215*7f2fe78bSCy Schubert static void
set_dummy(kdb_log_context * log_ctx,kdb_sno_t sno,const kdbe_time_t * kdb_time)216*7f2fe78bSCy Schubert set_dummy(kdb_log_context *log_ctx, kdb_sno_t sno, const kdbe_time_t *kdb_time)
217*7f2fe78bSCy Schubert {
218*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = log_ctx->ulog;
219*7f2fe78bSCy Schubert     kdb_ent_header_t *ent = INDEX(ulog, (sno - 1) % log_ctx->ulogentries);
220*7f2fe78bSCy Schubert 
221*7f2fe78bSCy Schubert     memset(ent, 0, sizeof(*ent));
222*7f2fe78bSCy Schubert     ent->kdb_umagic = KDB_ULOG_MAGIC;
223*7f2fe78bSCy Schubert     ent->kdb_entry_sno = sno;
224*7f2fe78bSCy Schubert     ent->kdb_time = *kdb_time;
225*7f2fe78bSCy Schubert     sync_update(ulog, ent);
226*7f2fe78bSCy Schubert 
227*7f2fe78bSCy Schubert     ulog->kdb_num = 1;
228*7f2fe78bSCy Schubert     ulog->kdb_first_sno = ulog->kdb_last_sno = sno;
229*7f2fe78bSCy Schubert     ulog->kdb_first_time = ulog->kdb_last_time = *kdb_time;
230*7f2fe78bSCy Schubert }
231*7f2fe78bSCy Schubert 
232*7f2fe78bSCy Schubert /* Reinitialize the ulog header, starting from sno 1 with the current time. */
233*7f2fe78bSCy Schubert static void
reset_ulog(kdb_log_context * log_ctx)234*7f2fe78bSCy Schubert reset_ulog(kdb_log_context *log_ctx)
235*7f2fe78bSCy Schubert {
236*7f2fe78bSCy Schubert     kdbe_time_t kdb_time;
237*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = log_ctx->ulog;
238*7f2fe78bSCy Schubert 
239*7f2fe78bSCy Schubert     memset(ulog, 0, sizeof(*ulog));
240*7f2fe78bSCy Schubert     ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
241*7f2fe78bSCy Schubert     ulog->db_version_num = KDB_VERSION;
242*7f2fe78bSCy Schubert     ulog->kdb_block = ULOG_BLOCK;
243*7f2fe78bSCy Schubert 
244*7f2fe78bSCy Schubert     /* Create a dummy entry to remember the timestamp for downstreams. */
245*7f2fe78bSCy Schubert     time_current(&kdb_time);
246*7f2fe78bSCy Schubert     set_dummy(log_ctx, 1, &kdb_time);
247*7f2fe78bSCy Schubert     ulog->kdb_state = KDB_STABLE;
248*7f2fe78bSCy Schubert     sync_header(ulog);
249*7f2fe78bSCy Schubert }
250*7f2fe78bSCy Schubert 
251*7f2fe78bSCy Schubert /*
252*7f2fe78bSCy Schubert  * If any database operations will be invoked while the ulog lock is held, the
253*7f2fe78bSCy Schubert  * caller must explicitly lock the database before locking the ulog, or
254*7f2fe78bSCy Schubert  * deadlock may result.
255*7f2fe78bSCy Schubert  */
256*7f2fe78bSCy Schubert static krb5_error_code
lock_ulog(krb5_context context,int mode)257*7f2fe78bSCy Schubert lock_ulog(krb5_context context, int mode)
258*7f2fe78bSCy Schubert {
259*7f2fe78bSCy Schubert     kdb_log_context *log_ctx = NULL;
260*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = NULL;
261*7f2fe78bSCy Schubert 
262*7f2fe78bSCy Schubert     INIT_ULOG(context);
263*7f2fe78bSCy Schubert     return krb5_lock_file(context, log_ctx->ulogfd, mode);
264*7f2fe78bSCy Schubert }
265*7f2fe78bSCy Schubert 
266*7f2fe78bSCy Schubert static void
unlock_ulog(krb5_context context)267*7f2fe78bSCy Schubert unlock_ulog(krb5_context context)
268*7f2fe78bSCy Schubert {
269*7f2fe78bSCy Schubert     (void)lock_ulog(context, KRB5_LOCKMODE_UNLOCK);
270*7f2fe78bSCy Schubert }
271*7f2fe78bSCy Schubert 
272*7f2fe78bSCy Schubert /*
273*7f2fe78bSCy Schubert  * Add an update to the log.  The update's kdb_entry_sno and kdb_time fields
274*7f2fe78bSCy Schubert  * must already be set.  The layout of the update log looks like:
275*7f2fe78bSCy Schubert  *
276*7f2fe78bSCy Schubert  * header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
277*7f2fe78bSCy Schubert  */
278*7f2fe78bSCy Schubert static krb5_error_code
store_update(kdb_log_context * log_ctx,kdb_incr_update_t * upd)279*7f2fe78bSCy Schubert store_update(kdb_log_context *log_ctx, kdb_incr_update_t *upd)
280*7f2fe78bSCy Schubert {
281*7f2fe78bSCy Schubert     XDR xdrs;
282*7f2fe78bSCy Schubert     kdb_ent_header_t *indx_log;
283*7f2fe78bSCy Schubert     unsigned int i, recsize;
284*7f2fe78bSCy Schubert     unsigned long upd_size;
285*7f2fe78bSCy Schubert     krb5_error_code retval;
286*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = log_ctx->ulog;
287*7f2fe78bSCy Schubert     uint32_t ulogentries = log_ctx->ulogentries;
288*7f2fe78bSCy Schubert 
289*7f2fe78bSCy Schubert     upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);
290*7f2fe78bSCy Schubert 
291*7f2fe78bSCy Schubert     recsize = sizeof(kdb_ent_header_t) + upd_size;
292*7f2fe78bSCy Schubert 
293*7f2fe78bSCy Schubert     if (recsize > ulog->kdb_block) {
294*7f2fe78bSCy Schubert         retval = resize(ulog, ulogentries, log_ctx->ulogfd, recsize);
295*7f2fe78bSCy Schubert         if (retval)
296*7f2fe78bSCy Schubert             return retval;
297*7f2fe78bSCy Schubert     }
298*7f2fe78bSCy Schubert 
299*7f2fe78bSCy Schubert     ulog->kdb_state = KDB_UNSTABLE;
300*7f2fe78bSCy Schubert 
301*7f2fe78bSCy Schubert     i = (upd->kdb_entry_sno - 1) % ulogentries;
302*7f2fe78bSCy Schubert     indx_log = INDEX(ulog, i);
303*7f2fe78bSCy Schubert 
304*7f2fe78bSCy Schubert     memset(indx_log, 0, ulog->kdb_block);
305*7f2fe78bSCy Schubert     indx_log->kdb_umagic = KDB_ULOG_MAGIC;
306*7f2fe78bSCy Schubert     indx_log->kdb_entry_size = upd_size;
307*7f2fe78bSCy Schubert     indx_log->kdb_entry_sno = upd->kdb_entry_sno;
308*7f2fe78bSCy Schubert     indx_log->kdb_time = upd->kdb_time;
309*7f2fe78bSCy Schubert     indx_log->kdb_commit = FALSE;
310*7f2fe78bSCy Schubert 
311*7f2fe78bSCy Schubert     xdrmem_create(&xdrs, (char *)indx_log->entry_data,
312*7f2fe78bSCy Schubert                   indx_log->kdb_entry_size, XDR_ENCODE);
313*7f2fe78bSCy Schubert     if (!xdr_kdb_incr_update_t(&xdrs, upd))
314*7f2fe78bSCy Schubert         return KRB5_LOG_CONV;
315*7f2fe78bSCy Schubert 
316*7f2fe78bSCy Schubert     indx_log->kdb_commit = TRUE;
317*7f2fe78bSCy Schubert     sync_update(ulog, indx_log);
318*7f2fe78bSCy Schubert 
319*7f2fe78bSCy Schubert     /* Modify the ulog header to reflect the new update. */
320*7f2fe78bSCy Schubert     ulog->kdb_last_sno = upd->kdb_entry_sno;
321*7f2fe78bSCy Schubert     ulog->kdb_last_time = upd->kdb_time;
322*7f2fe78bSCy Schubert     if (ulog->kdb_num == 0) {
323*7f2fe78bSCy Schubert         /* We should only see this in old ulogs. */
324*7f2fe78bSCy Schubert         ulog->kdb_num = 1;
325*7f2fe78bSCy Schubert         ulog->kdb_first_sno = upd->kdb_entry_sno;
326*7f2fe78bSCy Schubert         ulog->kdb_first_time = upd->kdb_time;
327*7f2fe78bSCy Schubert     } else if (ulog->kdb_num < ulogentries) {
328*7f2fe78bSCy Schubert         ulog->kdb_num++;
329*7f2fe78bSCy Schubert     } else {
330*7f2fe78bSCy Schubert         /* We are circling; set kdb_first_sno and time to the next update. */
331*7f2fe78bSCy Schubert         i = upd->kdb_entry_sno % ulogentries;
332*7f2fe78bSCy Schubert         indx_log = INDEX(ulog, i);
333*7f2fe78bSCy Schubert         ulog->kdb_first_sno = indx_log->kdb_entry_sno;
334*7f2fe78bSCy Schubert         ulog->kdb_first_time = indx_log->kdb_time;
335*7f2fe78bSCy Schubert     }
336*7f2fe78bSCy Schubert 
337*7f2fe78bSCy Schubert     ulog->kdb_state = KDB_STABLE;
338*7f2fe78bSCy Schubert     sync_header(ulog);
339*7f2fe78bSCy Schubert     return 0;
340*7f2fe78bSCy Schubert }
341*7f2fe78bSCy Schubert 
342*7f2fe78bSCy Schubert /* Add an entry to the update log. */
343*7f2fe78bSCy Schubert krb5_error_code
ulog_add_update(krb5_context context,kdb_incr_update_t * upd)344*7f2fe78bSCy Schubert ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
345*7f2fe78bSCy Schubert {
346*7f2fe78bSCy Schubert     krb5_error_code ret;
347*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
348*7f2fe78bSCy Schubert     kdb_hlog_t *ulog;
349*7f2fe78bSCy Schubert 
350*7f2fe78bSCy Schubert     INIT_ULOG(context);
351*7f2fe78bSCy Schubert     ret = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
352*7f2fe78bSCy Schubert     if (ret)
353*7f2fe78bSCy Schubert         return ret;
354*7f2fe78bSCy Schubert 
355*7f2fe78bSCy Schubert     /* If we have reached the last possible serial number, reinitialize the
356*7f2fe78bSCy Schubert      * ulog and start over.  Replicas will do a full resync. */
357*7f2fe78bSCy Schubert     if (ulog->kdb_last_sno == (kdb_sno_t)-1)
358*7f2fe78bSCy Schubert         reset_ulog(log_ctx);
359*7f2fe78bSCy Schubert 
360*7f2fe78bSCy Schubert     upd->kdb_entry_sno = ulog->kdb_last_sno + 1;
361*7f2fe78bSCy Schubert     time_current(&upd->kdb_time);
362*7f2fe78bSCy Schubert     ret = store_update(log_ctx, upd);
363*7f2fe78bSCy Schubert     unlock_ulog(context);
364*7f2fe78bSCy Schubert     return ret;
365*7f2fe78bSCy Schubert }
366*7f2fe78bSCy Schubert 
367*7f2fe78bSCy Schubert /* Used by the replica to update its hash db from the incr update log. */
368*7f2fe78bSCy Schubert krb5_error_code
ulog_replay(krb5_context context,kdb_incr_result_t * incr_ret,char ** db_args)369*7f2fe78bSCy Schubert ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
370*7f2fe78bSCy Schubert {
371*7f2fe78bSCy Schubert     krb5_db_entry *entry = NULL;
372*7f2fe78bSCy Schubert     kdb_incr_update_t *upd = NULL, *fupd;
373*7f2fe78bSCy Schubert     int i, no_of_updates;
374*7f2fe78bSCy Schubert     krb5_error_code retval;
375*7f2fe78bSCy Schubert     krb5_principal dbprinc;
376*7f2fe78bSCy Schubert     char *dbprincstr;
377*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
378*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = NULL;
379*7f2fe78bSCy Schubert 
380*7f2fe78bSCy Schubert     INIT_ULOG(context);
381*7f2fe78bSCy Schubert 
382*7f2fe78bSCy Schubert     retval = krb5_db_open(context, db_args,
383*7f2fe78bSCy Schubert                           KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
384*7f2fe78bSCy Schubert     if (retval)
385*7f2fe78bSCy Schubert         return retval;
386*7f2fe78bSCy Schubert 
387*7f2fe78bSCy Schubert     no_of_updates = incr_ret->updates.kdb_ulog_t_len;
388*7f2fe78bSCy Schubert     upd = incr_ret->updates.kdb_ulog_t_val;
389*7f2fe78bSCy Schubert     fupd = upd;
390*7f2fe78bSCy Schubert 
391*7f2fe78bSCy Schubert     for (i = 0; i < no_of_updates; i++) {
392*7f2fe78bSCy Schubert         if (!upd->kdb_commit)
393*7f2fe78bSCy Schubert             continue;
394*7f2fe78bSCy Schubert 
395*7f2fe78bSCy Schubert         /* Replay this update in the database. */
396*7f2fe78bSCy Schubert         if (upd->kdb_deleted) {
397*7f2fe78bSCy Schubert             dbprincstr = k5memdup0(upd->kdb_princ_name.utf8str_t_val,
398*7f2fe78bSCy Schubert                                    upd->kdb_princ_name.utf8str_t_len, &retval);
399*7f2fe78bSCy Schubert             if (dbprincstr == NULL)
400*7f2fe78bSCy Schubert                 goto cleanup;
401*7f2fe78bSCy Schubert 
402*7f2fe78bSCy Schubert             retval = krb5_parse_name(context, dbprincstr, &dbprinc);
403*7f2fe78bSCy Schubert             free(dbprincstr);
404*7f2fe78bSCy Schubert             if (retval)
405*7f2fe78bSCy Schubert                 goto cleanup;
406*7f2fe78bSCy Schubert 
407*7f2fe78bSCy Schubert             retval = krb5int_delete_principal_no_log(context, dbprinc);
408*7f2fe78bSCy Schubert             krb5_free_principal(context, dbprinc);
409*7f2fe78bSCy Schubert             if (retval == KRB5_KDB_NOENTRY)
410*7f2fe78bSCy Schubert                 retval = 0;
411*7f2fe78bSCy Schubert             if (retval)
412*7f2fe78bSCy Schubert                 goto cleanup;
413*7f2fe78bSCy Schubert         } else {
414*7f2fe78bSCy Schubert             retval = ulog_conv_2dbentry(context, &entry, upd);
415*7f2fe78bSCy Schubert             if (retval)
416*7f2fe78bSCy Schubert                 goto cleanup;
417*7f2fe78bSCy Schubert 
418*7f2fe78bSCy Schubert             retval = krb5int_put_principal_no_log(context, entry);
419*7f2fe78bSCy Schubert             krb5_db_free_principal(context, entry);
420*7f2fe78bSCy Schubert             if (retval)
421*7f2fe78bSCy Schubert                 goto cleanup;
422*7f2fe78bSCy Schubert         }
423*7f2fe78bSCy Schubert 
424*7f2fe78bSCy Schubert         retval = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
425*7f2fe78bSCy Schubert         if (retval)
426*7f2fe78bSCy Schubert             goto cleanup;
427*7f2fe78bSCy Schubert 
428*7f2fe78bSCy Schubert         /* If (unexpectedly) this update does not follow the last one we
429*7f2fe78bSCy Schubert          * stored, discard any previous ulog state. */
430*7f2fe78bSCy Schubert         if (ulog->kdb_num != 0 && upd->kdb_entry_sno != ulog->kdb_last_sno + 1)
431*7f2fe78bSCy Schubert             reset_ulog(log_ctx);
432*7f2fe78bSCy Schubert 
433*7f2fe78bSCy Schubert         /* Store this update in the ulog for any downstream KDCs. */
434*7f2fe78bSCy Schubert         retval = store_update(log_ctx, upd);
435*7f2fe78bSCy Schubert         unlock_ulog(context);
436*7f2fe78bSCy Schubert         if (retval)
437*7f2fe78bSCy Schubert             goto cleanup;
438*7f2fe78bSCy Schubert 
439*7f2fe78bSCy Schubert         upd++;
440*7f2fe78bSCy Schubert     }
441*7f2fe78bSCy Schubert 
442*7f2fe78bSCy Schubert cleanup:
443*7f2fe78bSCy Schubert     if (retval)
444*7f2fe78bSCy Schubert         (void)ulog_init_header(context);
445*7f2fe78bSCy Schubert     if (fupd)
446*7f2fe78bSCy Schubert         ulog_free_entries(fupd, no_of_updates);
447*7f2fe78bSCy Schubert     return retval;
448*7f2fe78bSCy Schubert }
449*7f2fe78bSCy Schubert 
450*7f2fe78bSCy Schubert /* Reinitialize the log header. */
451*7f2fe78bSCy Schubert krb5_error_code
ulog_init_header(krb5_context context)452*7f2fe78bSCy Schubert ulog_init_header(krb5_context context)
453*7f2fe78bSCy Schubert {
454*7f2fe78bSCy Schubert     krb5_error_code ret;
455*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
456*7f2fe78bSCy Schubert     kdb_hlog_t *ulog;
457*7f2fe78bSCy Schubert 
458*7f2fe78bSCy Schubert     INIT_ULOG(context);
459*7f2fe78bSCy Schubert     ret = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
460*7f2fe78bSCy Schubert     if (ret)
461*7f2fe78bSCy Schubert         return ret;
462*7f2fe78bSCy Schubert     reset_ulog(log_ctx);
463*7f2fe78bSCy Schubert     unlock_ulog(context);
464*7f2fe78bSCy Schubert     return 0;
465*7f2fe78bSCy Schubert }
466*7f2fe78bSCy Schubert 
467*7f2fe78bSCy Schubert /* Map the log file to memory for performance and simplicity. */
468*7f2fe78bSCy Schubert krb5_error_code
ulog_map(krb5_context context,const char * logname,uint32_t ulogentries)469*7f2fe78bSCy Schubert ulog_map(krb5_context context, const char *logname, uint32_t ulogentries)
470*7f2fe78bSCy Schubert {
471*7f2fe78bSCy Schubert     struct stat st;
472*7f2fe78bSCy Schubert     krb5_error_code retval;
473*7f2fe78bSCy Schubert     uint32_t filesize;
474*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
475*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = NULL;
476*7f2fe78bSCy Schubert     krb5_boolean locked = FALSE;
477*7f2fe78bSCy Schubert 
478*7f2fe78bSCy Schubert     log_ctx = create_log_context(context);
479*7f2fe78bSCy Schubert     if (log_ctx == NULL)
480*7f2fe78bSCy Schubert         return ENOMEM;
481*7f2fe78bSCy Schubert 
482*7f2fe78bSCy Schubert     if (stat(logname, &st) == -1) {
483*7f2fe78bSCy Schubert         log_ctx->ulogfd = open(logname, O_RDWR | O_CREAT, 0600);
484*7f2fe78bSCy Schubert         if (log_ctx->ulogfd == -1) {
485*7f2fe78bSCy Schubert             retval = errno;
486*7f2fe78bSCy Schubert             goto cleanup;
487*7f2fe78bSCy Schubert         }
488*7f2fe78bSCy Schubert 
489*7f2fe78bSCy Schubert         filesize = sizeof(kdb_hlog_t) + ulogentries * ULOG_BLOCK;
490*7f2fe78bSCy Schubert         retval = extend_file_to(log_ctx->ulogfd, filesize);
491*7f2fe78bSCy Schubert         if (retval)
492*7f2fe78bSCy Schubert             goto cleanup;
493*7f2fe78bSCy Schubert     } else {
494*7f2fe78bSCy Schubert         log_ctx->ulogfd = open(logname, O_RDWR, 0600);
495*7f2fe78bSCy Schubert         if (log_ctx->ulogfd == -1) {
496*7f2fe78bSCy Schubert             retval = errno;
497*7f2fe78bSCy Schubert             goto cleanup;
498*7f2fe78bSCy Schubert         }
499*7f2fe78bSCy Schubert     }
500*7f2fe78bSCy Schubert 
501*7f2fe78bSCy Schubert     ulog = mmap(0, MAXLOGLEN, PROT_READ | PROT_WRITE, MAP_SHARED,
502*7f2fe78bSCy Schubert                 log_ctx->ulogfd, 0);
503*7f2fe78bSCy Schubert     if (ulog == MAP_FAILED) {
504*7f2fe78bSCy Schubert         retval = errno;
505*7f2fe78bSCy Schubert         goto cleanup;
506*7f2fe78bSCy Schubert     }
507*7f2fe78bSCy Schubert     log_ctx->ulog = ulog;
508*7f2fe78bSCy Schubert     log_ctx->ulogentries = ulogentries;
509*7f2fe78bSCy Schubert 
510*7f2fe78bSCy Schubert     retval = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
511*7f2fe78bSCy Schubert     if (retval)
512*7f2fe78bSCy Schubert         goto cleanup;
513*7f2fe78bSCy Schubert     locked = TRUE;
514*7f2fe78bSCy Schubert 
515*7f2fe78bSCy Schubert     if (ulog->kdb_hmagic != KDB_ULOG_HDR_MAGIC) {
516*7f2fe78bSCy Schubert         if (ulog->kdb_hmagic != 0) {
517*7f2fe78bSCy Schubert             retval = KRB5_LOG_CORRUPT;
518*7f2fe78bSCy Schubert             goto cleanup;
519*7f2fe78bSCy Schubert         }
520*7f2fe78bSCy Schubert         reset_ulog(log_ctx);
521*7f2fe78bSCy Schubert     }
522*7f2fe78bSCy Schubert 
523*7f2fe78bSCy Schubert     /* Reinit ulog if ulogentries changed such that we have too many entries or
524*7f2fe78bSCy Schubert      * our first or last entry was written to the wrong location. */
525*7f2fe78bSCy Schubert     if (ulog->kdb_num != 0 &&
526*7f2fe78bSCy Schubert         (ulog->kdb_num > ulogentries ||
527*7f2fe78bSCy Schubert          !check_sno(log_ctx, ulog->kdb_first_sno, &ulog->kdb_first_time) ||
528*7f2fe78bSCy Schubert          !check_sno(log_ctx, ulog->kdb_last_sno, &ulog->kdb_last_time)))
529*7f2fe78bSCy Schubert         reset_ulog(log_ctx);
530*7f2fe78bSCy Schubert 
531*7f2fe78bSCy Schubert     if (ulog->kdb_num != ulogentries) {
532*7f2fe78bSCy Schubert         /* Expand the ulog file if it isn't big enough. */
533*7f2fe78bSCy Schubert         filesize = sizeof(kdb_hlog_t) + ulogentries * ulog->kdb_block;
534*7f2fe78bSCy Schubert         retval = extend_file_to(log_ctx->ulogfd, filesize);
535*7f2fe78bSCy Schubert         if (retval)
536*7f2fe78bSCy Schubert             goto cleanup;
537*7f2fe78bSCy Schubert     }
538*7f2fe78bSCy Schubert 
539*7f2fe78bSCy Schubert cleanup:
540*7f2fe78bSCy Schubert     if (locked)
541*7f2fe78bSCy Schubert         unlock_ulog(context);
542*7f2fe78bSCy Schubert     if (retval)
543*7f2fe78bSCy Schubert         ulog_fini(context);
544*7f2fe78bSCy Schubert     return retval;
545*7f2fe78bSCy Schubert }
546*7f2fe78bSCy Schubert 
547*7f2fe78bSCy Schubert /* Get the last set of updates seen, (last+1) to n is returned. */
548*7f2fe78bSCy Schubert krb5_error_code
ulog_get_entries(krb5_context context,const kdb_last_t * last,kdb_incr_result_t * ulog_handle)549*7f2fe78bSCy Schubert ulog_get_entries(krb5_context context, const kdb_last_t *last,
550*7f2fe78bSCy Schubert                  kdb_incr_result_t *ulog_handle)
551*7f2fe78bSCy Schubert {
552*7f2fe78bSCy Schubert     XDR xdrs;
553*7f2fe78bSCy Schubert     kdb_ent_header_t *indx_log;
554*7f2fe78bSCy Schubert     kdb_incr_update_t *upd;
555*7f2fe78bSCy Schubert     unsigned int indx, count;
556*7f2fe78bSCy Schubert     uint32_t sno;
557*7f2fe78bSCy Schubert     krb5_error_code retval;
558*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
559*7f2fe78bSCy Schubert     kdb_hlog_t *ulog = NULL;
560*7f2fe78bSCy Schubert     uint32_t ulogentries;
561*7f2fe78bSCy Schubert 
562*7f2fe78bSCy Schubert     INIT_ULOG(context);
563*7f2fe78bSCy Schubert     ulogentries = log_ctx->ulogentries;
564*7f2fe78bSCy Schubert 
565*7f2fe78bSCy Schubert     retval = lock_ulog(context, KRB5_LOCKMODE_SHARED);
566*7f2fe78bSCy Schubert     if (retval)
567*7f2fe78bSCy Schubert         return retval;
568*7f2fe78bSCy Schubert 
569*7f2fe78bSCy Schubert     /* If another process terminated mid-update, reset the ulog and force full
570*7f2fe78bSCy Schubert      * resyncs. */
571*7f2fe78bSCy Schubert     if (ulog->kdb_state != KDB_STABLE)
572*7f2fe78bSCy Schubert         reset_ulog(log_ctx);
573*7f2fe78bSCy Schubert 
574*7f2fe78bSCy Schubert     ulog_handle->ret = get_sno_status(log_ctx, last);
575*7f2fe78bSCy Schubert     if (ulog_handle->ret != UPDATE_OK)
576*7f2fe78bSCy Schubert         goto cleanup;
577*7f2fe78bSCy Schubert 
578*7f2fe78bSCy Schubert     sno = last->last_sno;
579*7f2fe78bSCy Schubert     count = ulog->kdb_last_sno - sno;
580*7f2fe78bSCy Schubert     upd = calloc(count, sizeof(kdb_incr_update_t));
581*7f2fe78bSCy Schubert     if (upd == NULL) {
582*7f2fe78bSCy Schubert         ulog_handle->ret = UPDATE_ERROR;
583*7f2fe78bSCy Schubert         retval = ENOMEM;
584*7f2fe78bSCy Schubert         goto cleanup;
585*7f2fe78bSCy Schubert     }
586*7f2fe78bSCy Schubert     ulog_handle->updates.kdb_ulog_t_val = upd;
587*7f2fe78bSCy Schubert 
588*7f2fe78bSCy Schubert     for (; sno < ulog->kdb_last_sno; sno++) {
589*7f2fe78bSCy Schubert         indx = sno % ulogentries;
590*7f2fe78bSCy Schubert         indx_log = INDEX(ulog, indx);
591*7f2fe78bSCy Schubert 
592*7f2fe78bSCy Schubert         memset(upd, 0, sizeof(kdb_incr_update_t));
593*7f2fe78bSCy Schubert         xdrmem_create(&xdrs, (char *)indx_log->entry_data,
594*7f2fe78bSCy Schubert                       indx_log->kdb_entry_size, XDR_DECODE);
595*7f2fe78bSCy Schubert         if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
596*7f2fe78bSCy Schubert             ulog_handle->ret = UPDATE_ERROR;
597*7f2fe78bSCy Schubert             retval = KRB5_LOG_CONV;
598*7f2fe78bSCy Schubert             goto cleanup;
599*7f2fe78bSCy Schubert         }
600*7f2fe78bSCy Schubert 
601*7f2fe78bSCy Schubert         /* Mark commitment since we didn't want to decode and encode the incr
602*7f2fe78bSCy Schubert          * update record the first time. */
603*7f2fe78bSCy Schubert         upd->kdb_commit = indx_log->kdb_commit;
604*7f2fe78bSCy Schubert         upd++;
605*7f2fe78bSCy Schubert     }
606*7f2fe78bSCy Schubert 
607*7f2fe78bSCy Schubert     ulog_handle->updates.kdb_ulog_t_len = count;
608*7f2fe78bSCy Schubert 
609*7f2fe78bSCy Schubert     ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
610*7f2fe78bSCy Schubert     ulog_handle->lastentry.last_time.seconds = ulog->kdb_last_time.seconds;
611*7f2fe78bSCy Schubert     ulog_handle->lastentry.last_time.useconds = ulog->kdb_last_time.useconds;
612*7f2fe78bSCy Schubert     ulog_handle->ret = UPDATE_OK;
613*7f2fe78bSCy Schubert 
614*7f2fe78bSCy Schubert cleanup:
615*7f2fe78bSCy Schubert     unlock_ulog(context);
616*7f2fe78bSCy Schubert     return retval;
617*7f2fe78bSCy Schubert }
618*7f2fe78bSCy Schubert 
619*7f2fe78bSCy Schubert krb5_error_code
ulog_set_role(krb5_context ctx,iprop_role role)620*7f2fe78bSCy Schubert ulog_set_role(krb5_context ctx, iprop_role role)
621*7f2fe78bSCy Schubert {
622*7f2fe78bSCy Schubert     if (create_log_context(ctx) == NULL)
623*7f2fe78bSCy Schubert         return ENOMEM;
624*7f2fe78bSCy Schubert     ctx->kdblog_context->iproprole = role;
625*7f2fe78bSCy Schubert     return 0;
626*7f2fe78bSCy Schubert }
627*7f2fe78bSCy Schubert 
628*7f2fe78bSCy Schubert update_status_t
ulog_get_sno_status(krb5_context context,const kdb_last_t * last)629*7f2fe78bSCy Schubert ulog_get_sno_status(krb5_context context, const kdb_last_t *last)
630*7f2fe78bSCy Schubert {
631*7f2fe78bSCy Schubert     update_status_t status;
632*7f2fe78bSCy Schubert 
633*7f2fe78bSCy Schubert     if (lock_ulog(context, KRB5_LOCKMODE_SHARED) != 0)
634*7f2fe78bSCy Schubert         return UPDATE_ERROR;
635*7f2fe78bSCy Schubert     status = get_sno_status(context->kdblog_context, last);
636*7f2fe78bSCy Schubert     unlock_ulog(context);
637*7f2fe78bSCy Schubert     return status;
638*7f2fe78bSCy Schubert }
639*7f2fe78bSCy Schubert 
640*7f2fe78bSCy Schubert krb5_error_code
ulog_get_last(krb5_context context,kdb_last_t * last_out)641*7f2fe78bSCy Schubert ulog_get_last(krb5_context context, kdb_last_t *last_out)
642*7f2fe78bSCy Schubert {
643*7f2fe78bSCy Schubert     krb5_error_code ret;
644*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
645*7f2fe78bSCy Schubert     kdb_hlog_t *ulog;
646*7f2fe78bSCy Schubert 
647*7f2fe78bSCy Schubert     INIT_ULOG(context);
648*7f2fe78bSCy Schubert     ret = lock_ulog(context, KRB5_LOCKMODE_SHARED);
649*7f2fe78bSCy Schubert     if (ret)
650*7f2fe78bSCy Schubert         return ret;
651*7f2fe78bSCy Schubert     last_out->last_sno = log_ctx->ulog->kdb_last_sno;
652*7f2fe78bSCy Schubert     last_out->last_time = log_ctx->ulog->kdb_last_time;
653*7f2fe78bSCy Schubert     unlock_ulog(context);
654*7f2fe78bSCy Schubert     return 0;
655*7f2fe78bSCy Schubert }
656*7f2fe78bSCy Schubert 
657*7f2fe78bSCy Schubert krb5_error_code
ulog_set_last(krb5_context context,const kdb_last_t * last)658*7f2fe78bSCy Schubert ulog_set_last(krb5_context context, const kdb_last_t *last)
659*7f2fe78bSCy Schubert {
660*7f2fe78bSCy Schubert     krb5_error_code ret;
661*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
662*7f2fe78bSCy Schubert     kdb_hlog_t *ulog;
663*7f2fe78bSCy Schubert 
664*7f2fe78bSCy Schubert     INIT_ULOG(context);
665*7f2fe78bSCy Schubert     ret = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
666*7f2fe78bSCy Schubert     if (ret)
667*7f2fe78bSCy Schubert         return ret;
668*7f2fe78bSCy Schubert 
669*7f2fe78bSCy Schubert     set_dummy(log_ctx, last->last_sno, &last->last_time);
670*7f2fe78bSCy Schubert     sync_header(ulog);
671*7f2fe78bSCy Schubert     unlock_ulog(context);
672*7f2fe78bSCy Schubert     return 0;
673*7f2fe78bSCy Schubert }
674*7f2fe78bSCy Schubert 
675*7f2fe78bSCy Schubert void
ulog_fini(krb5_context context)676*7f2fe78bSCy Schubert ulog_fini(krb5_context context)
677*7f2fe78bSCy Schubert {
678*7f2fe78bSCy Schubert     kdb_log_context *log_ctx = context->kdblog_context;
679*7f2fe78bSCy Schubert 
680*7f2fe78bSCy Schubert     if (log_ctx == NULL)
681*7f2fe78bSCy Schubert         return;
682*7f2fe78bSCy Schubert     if (log_ctx->ulog != NULL)
683*7f2fe78bSCy Schubert         munmap(log_ctx->ulog, MAXLOGLEN);
684*7f2fe78bSCy Schubert     if (log_ctx->ulogfd != -1)
685*7f2fe78bSCy Schubert         close(log_ctx->ulogfd);
686*7f2fe78bSCy Schubert     free(log_ctx);
687*7f2fe78bSCy Schubert     context->kdblog_context = NULL;
688*7f2fe78bSCy Schubert }
689