Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/kadm5/log.c
34870 views
1
/*
2
* Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* 3. Neither the name of the Institute nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include "kadm5_locl.h"
35
#include "heim_threads.h"
36
37
RCSID("$Id$");
38
39
/*
40
* A log record consists of:
41
*
42
* version number 4 bytes
43
* time in seconds 4 bytes
44
* operation (enum kadm_ops) 4 bytes
45
* length of record 4 bytes
46
* data... n bytes
47
* length of record 4 bytes
48
* version number 4 bytes
49
*
50
*/
51
52
kadm5_ret_t
53
kadm5_log_get_version_fd (int fd,
54
uint32_t *ver)
55
{
56
int ret;
57
krb5_storage *sp;
58
int32_t old_version;
59
60
ret = lseek (fd, 0, SEEK_END);
61
if(ret < 0)
62
return errno;
63
if(ret == 0) {
64
*ver = 0;
65
return 0;
66
}
67
sp = krb5_storage_from_fd (fd);
68
krb5_storage_seek(sp, -4, SEEK_CUR);
69
krb5_ret_int32 (sp, &old_version);
70
*ver = old_version;
71
krb5_storage_free(sp);
72
lseek (fd, 0, SEEK_END);
73
return 0;
74
}
75
76
kadm5_ret_t
77
kadm5_log_get_version (kadm5_server_context *context, uint32_t *ver)
78
{
79
return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
80
}
81
82
kadm5_ret_t
83
kadm5_log_set_version (kadm5_server_context *context, uint32_t vno)
84
{
85
kadm5_log_context *log_context = &context->log_context;
86
87
log_context->version = vno;
88
return 0;
89
}
90
91
kadm5_ret_t
92
kadm5_log_init (kadm5_server_context *context)
93
{
94
int fd;
95
kadm5_ret_t ret;
96
kadm5_log_context *log_context = &context->log_context;
97
98
if (log_context->log_fd != -1)
99
return 0;
100
fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
101
if (fd < 0) {
102
ret = errno;
103
krb5_set_error_message(context->context, ret, "kadm5_log_init: open %s",
104
log_context->log_file);
105
return ret;
106
}
107
if (flock (fd, LOCK_EX) < 0) {
108
ret = errno;
109
krb5_set_error_message(context->context, ret, "kadm5_log_init: flock %s",
110
log_context->log_file);
111
close (fd);
112
return errno;
113
}
114
115
ret = kadm5_log_get_version_fd (fd, &log_context->version);
116
if (ret)
117
return ret;
118
119
log_context->log_fd = fd;
120
return 0;
121
}
122
123
kadm5_ret_t
124
kadm5_log_reinit (kadm5_server_context *context)
125
{
126
int fd;
127
kadm5_log_context *log_context = &context->log_context;
128
129
if (log_context->log_fd != -1) {
130
flock (log_context->log_fd, LOCK_UN);
131
close (log_context->log_fd);
132
log_context->log_fd = -1;
133
}
134
fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
135
if (fd < 0)
136
return errno;
137
if (flock (fd, LOCK_EX) < 0) {
138
close (fd);
139
return errno;
140
}
141
142
log_context->version = 0;
143
log_context->log_fd = fd;
144
return 0;
145
}
146
147
148
kadm5_ret_t
149
kadm5_log_end (kadm5_server_context *context)
150
{
151
kadm5_log_context *log_context = &context->log_context;
152
int fd = log_context->log_fd;
153
154
flock (fd, LOCK_UN);
155
close(fd);
156
log_context->log_fd = -1;
157
return 0;
158
}
159
160
static kadm5_ret_t
161
kadm5_log_preamble (kadm5_server_context *context,
162
krb5_storage *sp,
163
enum kadm_ops op)
164
{
165
kadm5_log_context *log_context = &context->log_context;
166
kadm5_ret_t kadm_ret;
167
168
kadm_ret = kadm5_log_init (context);
169
if (kadm_ret)
170
return kadm_ret;
171
172
krb5_store_int32 (sp, ++log_context->version);
173
krb5_store_int32 (sp, time(NULL));
174
krb5_store_int32 (sp, op);
175
return 0;
176
}
177
178
static kadm5_ret_t
179
kadm5_log_postamble (kadm5_log_context *context,
180
krb5_storage *sp)
181
{
182
krb5_store_int32 (sp, context->version);
183
return 0;
184
}
185
186
/*
187
* flush the log record in `sp'.
188
*/
189
190
static kadm5_ret_t
191
kadm5_log_flush (kadm5_log_context *log_context,
192
krb5_storage *sp)
193
{
194
krb5_data data;
195
size_t len;
196
ssize_t ret;
197
198
krb5_storage_to_data(sp, &data);
199
len = data.length;
200
ret = write (log_context->log_fd, data.data, len);
201
if (ret < 0 || (size_t)ret != len) {
202
krb5_data_free(&data);
203
return errno;
204
}
205
if (fsync (log_context->log_fd) < 0) {
206
krb5_data_free(&data);
207
return errno;
208
}
209
210
/*
211
* Try to send a signal to any running `ipropd-master'
212
*/
213
#ifndef NO_UNIX_SOCKETS
214
sendto (log_context->socket_fd,
215
(void *)&log_context->version,
216
sizeof(log_context->version),
217
0,
218
(struct sockaddr *)&log_context->socket_name,
219
sizeof(log_context->socket_name));
220
#else
221
sendto (log_context->socket_fd,
222
(void *)&log_context->version,
223
sizeof(log_context->version),
224
0,
225
log_context->socket_info->ai_addr,
226
log_context->socket_info->ai_addrlen);
227
#endif
228
229
krb5_data_free(&data);
230
return 0;
231
}
232
233
/*
234
* Add a `create' operation to the log.
235
*/
236
237
kadm5_ret_t
238
kadm5_log_create (kadm5_server_context *context,
239
hdb_entry *ent)
240
{
241
krb5_storage *sp;
242
kadm5_ret_t ret;
243
krb5_data value;
244
kadm5_log_context *log_context = &context->log_context;
245
246
sp = krb5_storage_emem();
247
ret = hdb_entry2value (context->context, ent, &value);
248
if (ret) {
249
krb5_storage_free(sp);
250
return ret;
251
}
252
ret = kadm5_log_preamble (context, sp, kadm_create);
253
if (ret) {
254
krb5_data_free (&value);
255
krb5_storage_free(sp);
256
return ret;
257
}
258
krb5_store_int32 (sp, value.length);
259
krb5_storage_write(sp, value.data, value.length);
260
krb5_store_int32 (sp, value.length);
261
krb5_data_free (&value);
262
ret = kadm5_log_postamble (log_context, sp);
263
if (ret) {
264
krb5_storage_free (sp);
265
return ret;
266
}
267
ret = kadm5_log_flush (log_context, sp);
268
krb5_storage_free (sp);
269
if (ret)
270
return ret;
271
ret = kadm5_log_end (context);
272
return ret;
273
}
274
275
/*
276
* Read the data of a create log record from `sp' and change the
277
* database.
278
*/
279
280
static kadm5_ret_t
281
kadm5_log_replay_create (kadm5_server_context *context,
282
uint32_t ver,
283
uint32_t len,
284
krb5_storage *sp)
285
{
286
krb5_error_code ret;
287
krb5_data data;
288
hdb_entry_ex ent;
289
290
memset(&ent, 0, sizeof(ent));
291
292
ret = krb5_data_alloc (&data, len);
293
if (ret) {
294
krb5_set_error_message(context->context, ret, "out of memory");
295
return ret;
296
}
297
krb5_storage_read (sp, data.data, len);
298
ret = hdb_value2entry (context->context, &data, &ent.entry);
299
krb5_data_free(&data);
300
if (ret) {
301
krb5_set_error_message(context->context, ret,
302
"Unmarshaling hdb entry failed");
303
return ret;
304
}
305
ret = context->db->hdb_store(context->context, context->db, 0, &ent);
306
hdb_free_entry (context->context, &ent);
307
return ret;
308
}
309
310
/*
311
* Add a `delete' operation to the log.
312
*/
313
314
kadm5_ret_t
315
kadm5_log_delete (kadm5_server_context *context,
316
krb5_principal princ)
317
{
318
krb5_storage *sp;
319
kadm5_ret_t ret;
320
off_t off;
321
off_t len;
322
kadm5_log_context *log_context = &context->log_context;
323
324
sp = krb5_storage_emem();
325
if (sp == NULL)
326
return ENOMEM;
327
ret = kadm5_log_preamble (context, sp, kadm_delete);
328
if (ret)
329
goto out;
330
ret = krb5_store_int32 (sp, 0);
331
if (ret)
332
goto out;
333
off = krb5_storage_seek (sp, 0, SEEK_CUR);
334
ret = krb5_store_principal (sp, princ);
335
if (ret)
336
goto out;
337
len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
338
krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
339
ret = krb5_store_int32 (sp, len);
340
if (ret)
341
goto out;
342
krb5_storage_seek(sp, len, SEEK_CUR);
343
ret = krb5_store_int32 (sp, len);
344
if (ret)
345
goto out;
346
ret = kadm5_log_postamble (log_context, sp);
347
if (ret)
348
goto out;
349
ret = kadm5_log_flush (log_context, sp);
350
if (ret)
351
goto out;
352
ret = kadm5_log_end (context);
353
out:
354
krb5_storage_free (sp);
355
return ret;
356
}
357
358
/*
359
* Read a `delete' log operation from `sp' and apply it.
360
*/
361
362
static kadm5_ret_t
363
kadm5_log_replay_delete (kadm5_server_context *context,
364
uint32_t ver,
365
uint32_t len,
366
krb5_storage *sp)
367
{
368
krb5_error_code ret;
369
krb5_principal principal;
370
371
ret = krb5_ret_principal (sp, &principal);
372
if (ret) {
373
krb5_set_error_message(context->context, ret, "Failed to read deleted "
374
"principal from log version: %ld", (long)ver);
375
return ret;
376
}
377
378
ret = context->db->hdb_remove(context->context, context->db, principal);
379
krb5_free_principal (context->context, principal);
380
return ret;
381
}
382
383
/*
384
* Add a `rename' operation to the log.
385
*/
386
387
kadm5_ret_t
388
kadm5_log_rename (kadm5_server_context *context,
389
krb5_principal source,
390
hdb_entry *ent)
391
{
392
krb5_storage *sp;
393
kadm5_ret_t ret;
394
off_t off;
395
off_t len;
396
krb5_data value;
397
kadm5_log_context *log_context = &context->log_context;
398
399
krb5_data_zero(&value);
400
401
sp = krb5_storage_emem();
402
ret = hdb_entry2value (context->context, ent, &value);
403
if (ret)
404
goto failed;
405
406
ret = kadm5_log_preamble (context, sp, kadm_rename);
407
if (ret)
408
goto failed;
409
410
ret = krb5_store_int32 (sp, 0);
411
if (ret)
412
goto failed;
413
off = krb5_storage_seek (sp, 0, SEEK_CUR);
414
ret = krb5_store_principal (sp, source);
415
if (ret)
416
goto failed;
417
418
krb5_storage_write(sp, value.data, value.length);
419
len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
420
421
krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
422
ret = krb5_store_int32 (sp, len);
423
if (ret)
424
goto failed;
425
426
krb5_storage_seek(sp, len, SEEK_CUR);
427
ret = krb5_store_int32 (sp, len);
428
if (ret)
429
goto failed;
430
431
ret = kadm5_log_postamble (log_context, sp);
432
if (ret)
433
goto failed;
434
435
ret = kadm5_log_flush (log_context, sp);
436
if (ret)
437
goto failed;
438
krb5_storage_free (sp);
439
krb5_data_free (&value);
440
441
return kadm5_log_end (context);
442
443
failed:
444
krb5_data_free(&value);
445
krb5_storage_free(sp);
446
return ret;
447
}
448
449
/*
450
* Read a `rename' log operation from `sp' and apply it.
451
*/
452
453
static kadm5_ret_t
454
kadm5_log_replay_rename (kadm5_server_context *context,
455
uint32_t ver,
456
uint32_t len,
457
krb5_storage *sp)
458
{
459
krb5_error_code ret;
460
krb5_principal source;
461
hdb_entry_ex target_ent;
462
krb5_data value;
463
off_t off;
464
size_t princ_len, data_len;
465
466
memset(&target_ent, 0, sizeof(target_ent));
467
468
off = krb5_storage_seek(sp, 0, SEEK_CUR);
469
ret = krb5_ret_principal (sp, &source);
470
if (ret) {
471
krb5_set_error_message(context->context, ret, "Failed to read renamed "
472
"principal in log, version: %ld", (long)ver);
473
return ret;
474
}
475
princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
476
data_len = len - princ_len;
477
ret = krb5_data_alloc (&value, data_len);
478
if (ret) {
479
krb5_free_principal (context->context, source);
480
return ret;
481
}
482
krb5_storage_read (sp, value.data, data_len);
483
ret = hdb_value2entry (context->context, &value, &target_ent.entry);
484
krb5_data_free(&value);
485
if (ret) {
486
krb5_free_principal (context->context, source);
487
return ret;
488
}
489
ret = context->db->hdb_store (context->context, context->db,
490
0, &target_ent);
491
hdb_free_entry (context->context, &target_ent);
492
if (ret) {
493
krb5_free_principal (context->context, source);
494
return ret;
495
}
496
ret = context->db->hdb_remove (context->context, context->db, source);
497
krb5_free_principal (context->context, source);
498
return ret;
499
}
500
501
502
/*
503
* Add a `modify' operation to the log.
504
*/
505
506
kadm5_ret_t
507
kadm5_log_modify (kadm5_server_context *context,
508
hdb_entry *ent,
509
uint32_t mask)
510
{
511
krb5_storage *sp;
512
kadm5_ret_t ret;
513
krb5_data value;
514
uint32_t len;
515
kadm5_log_context *log_context = &context->log_context;
516
517
krb5_data_zero(&value);
518
519
sp = krb5_storage_emem();
520
ret = hdb_entry2value (context->context, ent, &value);
521
if (ret)
522
goto failed;
523
524
ret = kadm5_log_preamble (context, sp, kadm_modify);
525
if (ret)
526
goto failed;
527
528
len = value.length + 4;
529
ret = krb5_store_int32 (sp, len);
530
if (ret)
531
goto failed;
532
ret = krb5_store_int32 (sp, mask);
533
if (ret)
534
goto failed;
535
krb5_storage_write (sp, value.data, value.length);
536
537
ret = krb5_store_int32 (sp, len);
538
if (ret)
539
goto failed;
540
ret = kadm5_log_postamble (log_context, sp);
541
if (ret)
542
goto failed;
543
ret = kadm5_log_flush (log_context, sp);
544
if (ret)
545
goto failed;
546
krb5_data_free(&value);
547
krb5_storage_free (sp);
548
return kadm5_log_end (context);
549
failed:
550
krb5_data_free(&value);
551
krb5_storage_free(sp);
552
return ret;
553
}
554
555
/*
556
* Read a `modify' log operation from `sp' and apply it.
557
*/
558
559
static kadm5_ret_t
560
kadm5_log_replay_modify (kadm5_server_context *context,
561
uint32_t ver,
562
uint32_t len,
563
krb5_storage *sp)
564
{
565
krb5_error_code ret;
566
int32_t mask;
567
krb5_data value;
568
hdb_entry_ex ent, log_ent;
569
570
memset(&log_ent, 0, sizeof(log_ent));
571
572
krb5_ret_int32 (sp, &mask);
573
len -= 4;
574
ret = krb5_data_alloc (&value, len);
575
if (ret) {
576
krb5_set_error_message(context->context, ret, "out of memory");
577
return ret;
578
}
579
krb5_storage_read (sp, value.data, len);
580
ret = hdb_value2entry (context->context, &value, &log_ent.entry);
581
krb5_data_free(&value);
582
if (ret)
583
return ret;
584
585
memset(&ent, 0, sizeof(ent));
586
ret = context->db->hdb_fetch_kvno(context->context, context->db,
587
log_ent.entry.principal,
588
HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
589
if (ret)
590
goto out;
591
if (mask & KADM5_PRINC_EXPIRE_TIME) {
592
if (log_ent.entry.valid_end == NULL) {
593
ent.entry.valid_end = NULL;
594
} else {
595
if (ent.entry.valid_end == NULL) {
596
ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
597
if (ent.entry.valid_end == NULL) {
598
ret = ENOMEM;
599
krb5_set_error_message(context->context, ret, "out of memory");
600
goto out;
601
}
602
}
603
*ent.entry.valid_end = *log_ent.entry.valid_end;
604
}
605
}
606
if (mask & KADM5_PW_EXPIRATION) {
607
if (log_ent.entry.pw_end == NULL) {
608
ent.entry.pw_end = NULL;
609
} else {
610
if (ent.entry.pw_end == NULL) {
611
ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
612
if (ent.entry.pw_end == NULL) {
613
ret = ENOMEM;
614
krb5_set_error_message(context->context, ret, "out of memory");
615
goto out;
616
}
617
}
618
*ent.entry.pw_end = *log_ent.entry.pw_end;
619
}
620
}
621
if (mask & KADM5_LAST_PWD_CHANGE) {
622
abort (); /* XXX */
623
}
624
if (mask & KADM5_ATTRIBUTES) {
625
ent.entry.flags = log_ent.entry.flags;
626
}
627
if (mask & KADM5_MAX_LIFE) {
628
if (log_ent.entry.max_life == NULL) {
629
ent.entry.max_life = NULL;
630
} else {
631
if (ent.entry.max_life == NULL) {
632
ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
633
if (ent.entry.max_life == NULL) {
634
ret = ENOMEM;
635
krb5_set_error_message(context->context, ret, "out of memory");
636
goto out;
637
}
638
}
639
*ent.entry.max_life = *log_ent.entry.max_life;
640
}
641
}
642
if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
643
if (ent.entry.modified_by == NULL) {
644
ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
645
if (ent.entry.modified_by == NULL) {
646
ret = ENOMEM;
647
krb5_set_error_message(context->context, ret, "out of memory");
648
goto out;
649
}
650
} else
651
free_Event(ent.entry.modified_by);
652
ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
653
if (ret) {
654
krb5_set_error_message(context->context, ret, "out of memory");
655
goto out;
656
}
657
}
658
if (mask & KADM5_KVNO) {
659
ent.entry.kvno = log_ent.entry.kvno;
660
}
661
if (mask & KADM5_MKVNO) {
662
abort (); /* XXX */
663
}
664
if (mask & KADM5_AUX_ATTRIBUTES) {
665
abort (); /* XXX */
666
}
667
if (mask & KADM5_POLICY) {
668
abort (); /* XXX */
669
}
670
if (mask & KADM5_POLICY_CLR) {
671
abort (); /* XXX */
672
}
673
if (mask & KADM5_MAX_RLIFE) {
674
if (log_ent.entry.max_renew == NULL) {
675
ent.entry.max_renew = NULL;
676
} else {
677
if (ent.entry.max_renew == NULL) {
678
ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
679
if (ent.entry.max_renew == NULL) {
680
ret = ENOMEM;
681
krb5_set_error_message(context->context, ret, "out of memory");
682
goto out;
683
}
684
}
685
*ent.entry.max_renew = *log_ent.entry.max_renew;
686
}
687
}
688
if (mask & KADM5_LAST_SUCCESS) {
689
abort (); /* XXX */
690
}
691
if (mask & KADM5_LAST_FAILED) {
692
abort (); /* XXX */
693
}
694
if (mask & KADM5_FAIL_AUTH_COUNT) {
695
abort (); /* XXX */
696
}
697
if (mask & KADM5_KEY_DATA) {
698
size_t num;
699
size_t i;
700
701
for (i = 0; i < ent.entry.keys.len; ++i)
702
free_Key(&ent.entry.keys.val[i]);
703
free (ent.entry.keys.val);
704
705
num = log_ent.entry.keys.len;
706
707
ent.entry.keys.len = num;
708
ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
709
if (ent.entry.keys.val == NULL) {
710
krb5_set_error_message(context->context, ENOMEM, "out of memory");
711
return ENOMEM;
712
}
713
for (i = 0; i < ent.entry.keys.len; ++i) {
714
ret = copy_Key(&log_ent.entry.keys.val[i],
715
&ent.entry.keys.val[i]);
716
if (ret) {
717
krb5_set_error_message(context->context, ret, "out of memory");
718
goto out;
719
}
720
}
721
}
722
if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
723
HDB_extensions *es = ent.entry.extensions;
724
725
ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
726
if (ent.entry.extensions == NULL)
727
goto out;
728
729
ret = copy_HDB_extensions(log_ent.entry.extensions,
730
ent.entry.extensions);
731
if (ret) {
732
krb5_set_error_message(context->context, ret, "out of memory");
733
free(ent.entry.extensions);
734
ent.entry.extensions = es;
735
goto out;
736
}
737
if (es) {
738
free_HDB_extensions(es);
739
free(es);
740
}
741
}
742
ret = context->db->hdb_store(context->context, context->db,
743
HDB_F_REPLACE, &ent);
744
out:
745
hdb_free_entry (context->context, &ent);
746
hdb_free_entry (context->context, &log_ent);
747
return ret;
748
}
749
750
/*
751
* Add a `nop' operation to the log. Does not close the log.
752
*/
753
754
kadm5_ret_t
755
kadm5_log_nop (kadm5_server_context *context)
756
{
757
krb5_storage *sp;
758
kadm5_ret_t ret;
759
kadm5_log_context *log_context = &context->log_context;
760
761
sp = krb5_storage_emem();
762
ret = kadm5_log_preamble (context, sp, kadm_nop);
763
if (ret) {
764
krb5_storage_free (sp);
765
return ret;
766
}
767
krb5_store_int32 (sp, 0);
768
krb5_store_int32 (sp, 0);
769
ret = kadm5_log_postamble (log_context, sp);
770
if (ret) {
771
krb5_storage_free (sp);
772
return ret;
773
}
774
ret = kadm5_log_flush (log_context, sp);
775
krb5_storage_free (sp);
776
777
return ret;
778
}
779
780
/*
781
* Read a `nop' log operation from `sp' and apply it.
782
*/
783
784
static kadm5_ret_t
785
kadm5_log_replay_nop (kadm5_server_context *context,
786
uint32_t ver,
787
uint32_t len,
788
krb5_storage *sp)
789
{
790
return 0;
791
}
792
793
/*
794
* Call `func' for each log record in the log in `context'
795
*/
796
797
kadm5_ret_t
798
kadm5_log_foreach (kadm5_server_context *context,
799
void (*func)(kadm5_server_context *server_context,
800
uint32_t ver,
801
time_t timestamp,
802
enum kadm_ops op,
803
uint32_t len,
804
krb5_storage *,
805
void *),
806
void *ctx)
807
{
808
int fd = context->log_context.log_fd;
809
krb5_storage *sp;
810
811
lseek (fd, 0, SEEK_SET);
812
sp = krb5_storage_from_fd (fd);
813
for (;;) {
814
int32_t ver, timestamp, op, len, len2, ver2;
815
816
if(krb5_ret_int32 (sp, &ver) != 0)
817
break;
818
krb5_ret_int32 (sp, &timestamp);
819
krb5_ret_int32 (sp, &op);
820
krb5_ret_int32 (sp, &len);
821
(*func)(context, ver, timestamp, op, len, sp, ctx);
822
krb5_ret_int32 (sp, &len2);
823
krb5_ret_int32 (sp, &ver2);
824
if (len != len2)
825
abort();
826
if (ver != ver2)
827
abort();
828
}
829
krb5_storage_free(sp);
830
return 0;
831
}
832
833
/*
834
* Go to end of log.
835
*/
836
837
krb5_storage *
838
kadm5_log_goto_end (int fd)
839
{
840
krb5_storage *sp;
841
842
sp = krb5_storage_from_fd (fd);
843
krb5_storage_seek(sp, 0, SEEK_END);
844
return sp;
845
}
846
847
/*
848
* Return previous log entry.
849
*
850
* The pointer in `sp´ is assumed to be at the top of the entry before
851
* previous entry. On success, the `sp´ pointer is set to data portion
852
* of previous entry. In case of error, it's not changed at all.
853
*/
854
855
kadm5_ret_t
856
kadm5_log_previous (krb5_context context,
857
krb5_storage *sp,
858
uint32_t *ver,
859
time_t *timestamp,
860
enum kadm_ops *op,
861
uint32_t *len)
862
{
863
krb5_error_code ret;
864
off_t off, oldoff;
865
int32_t tmp;
866
867
oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
868
869
krb5_storage_seek(sp, -8, SEEK_CUR);
870
ret = krb5_ret_int32 (sp, &tmp);
871
if (ret)
872
goto end_of_storage;
873
*len = tmp;
874
ret = krb5_ret_int32 (sp, &tmp);
875
if (ret)
876
goto end_of_storage;
877
*ver = tmp;
878
off = 24 + *len;
879
krb5_storage_seek(sp, -off, SEEK_CUR);
880
ret = krb5_ret_int32 (sp, &tmp);
881
if (ret)
882
goto end_of_storage;
883
if ((uint32_t)tmp != *ver) {
884
krb5_storage_seek(sp, oldoff, SEEK_SET);
885
krb5_set_error_message(context, KADM5_BAD_DB,
886
"kadm5_log_previous: log entry "
887
"have consistency failure, version number wrong "
888
"(tmp %lu ver %lu)",
889
(unsigned long)tmp,
890
(unsigned long)*ver);
891
return KADM5_BAD_DB;
892
}
893
ret = krb5_ret_int32 (sp, &tmp);
894
if (ret)
895
goto end_of_storage;
896
*timestamp = tmp;
897
ret = krb5_ret_int32 (sp, &tmp);
898
if (ret)
899
goto end_of_storage;
900
*op = tmp;
901
ret = krb5_ret_int32 (sp, &tmp);
902
if (ret)
903
goto end_of_storage;
904
if ((uint32_t)tmp != *len) {
905
krb5_storage_seek(sp, oldoff, SEEK_SET);
906
krb5_set_error_message(context, KADM5_BAD_DB,
907
"kadm5_log_previous: log entry "
908
"have consistency failure, length wrong");
909
return KADM5_BAD_DB;
910
}
911
return 0;
912
913
end_of_storage:
914
krb5_storage_seek(sp, oldoff, SEEK_SET);
915
krb5_set_error_message(context, ret, "kadm5_log_previous: end of storage "
916
"reached before end");
917
return ret;
918
}
919
920
/*
921
* Replay a record from the log
922
*/
923
924
kadm5_ret_t
925
kadm5_log_replay (kadm5_server_context *context,
926
enum kadm_ops op,
927
uint32_t ver,
928
uint32_t len,
929
krb5_storage *sp)
930
{
931
switch (op) {
932
case kadm_create :
933
return kadm5_log_replay_create (context, ver, len, sp);
934
case kadm_delete :
935
return kadm5_log_replay_delete (context, ver, len, sp);
936
case kadm_rename :
937
return kadm5_log_replay_rename (context, ver, len, sp);
938
case kadm_modify :
939
return kadm5_log_replay_modify (context, ver, len, sp);
940
case kadm_nop :
941
return kadm5_log_replay_nop (context, ver, len, sp);
942
default :
943
krb5_set_error_message(context->context, KADM5_FAILURE,
944
"Unsupported replay op %d", (int)op);
945
return KADM5_FAILURE;
946
}
947
}
948
949
/*
950
* truncate the log - i.e. create an empty file with just (nop vno + 2)
951
*/
952
953
kadm5_ret_t
954
kadm5_log_truncate (kadm5_server_context *server_context)
955
{
956
kadm5_ret_t ret;
957
uint32_t vno;
958
959
ret = kadm5_log_init (server_context);
960
if (ret)
961
return ret;
962
963
ret = kadm5_log_get_version (server_context, &vno);
964
if (ret)
965
return ret;
966
967
ret = kadm5_log_reinit (server_context);
968
if (ret)
969
return ret;
970
971
ret = kadm5_log_set_version (server_context, vno);
972
if (ret)
973
return ret;
974
975
ret = kadm5_log_nop (server_context);
976
if (ret)
977
return ret;
978
979
ret = kadm5_log_end (server_context);
980
if (ret)
981
return ret;
982
return 0;
983
984
}
985
986
#ifndef NO_UNIX_SOCKETS
987
988
static char *default_signal = NULL;
989
static HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
990
991
const char *
992
kadm5_log_signal_socket(krb5_context context)
993
{
994
HEIMDAL_MUTEX_lock(&signal_mutex);
995
if (!default_signal)
996
asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
997
HEIMDAL_MUTEX_unlock(&signal_mutex);
998
999
return krb5_config_get_string_default(context,
1000
NULL,
1001
default_signal,
1002
"kdc",
1003
"signal_socket",
1004
NULL);
1005
}
1006
1007
#else /* NO_UNIX_SOCKETS */
1008
1009
#define SIGNAL_SOCKET_HOST "127.0.0.1"
1010
#define SIGNAL_SOCKET_PORT "12701"
1011
1012
kadm5_ret_t
1013
kadm5_log_signal_socket_info(krb5_context context,
1014
int server_end,
1015
struct addrinfo **ret_addrs)
1016
{
1017
struct addrinfo hints;
1018
struct addrinfo *addrs = NULL;
1019
kadm5_ret_t ret = KADM5_FAILURE;
1020
int wsret;
1021
1022
memset(&hints, 0, sizeof(hints));
1023
1024
hints.ai_flags = AI_NUMERICHOST;
1025
if (server_end)
1026
hints.ai_flags |= AI_PASSIVE;
1027
hints.ai_family = AF_INET;
1028
hints.ai_socktype = SOCK_STREAM;
1029
hints.ai_protocol = IPPROTO_TCP;
1030
1031
wsret = getaddrinfo(SIGNAL_SOCKET_HOST,
1032
SIGNAL_SOCKET_PORT,
1033
&hints, &addrs);
1034
1035
if (wsret != 0) {
1036
krb5_set_error_message(context, KADM5_FAILURE,
1037
"%s", gai_strerror(wsret));
1038
goto done;
1039
}
1040
1041
if (addrs == NULL) {
1042
krb5_set_error_message(context, KADM5_FAILURE,
1043
"getaddrinfo() failed to return address list");
1044
goto done;
1045
}
1046
1047
*ret_addrs = addrs;
1048
addrs = NULL;
1049
ret = 0;
1050
1051
done:
1052
if (addrs)
1053
freeaddrinfo(addrs);
1054
return ret;
1055
}
1056
1057
#endif
1058
1059