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