xref: /freebsd/crypto/heimdal/lib/kadm5/log.c (revision ae83180158c4c937f170e31eff311b18c0286a93)
1 /*
2  * Copyright (c) 1997 - 2000 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 
36 RCSID("$Id: log.c,v 1.18 2000/07/24 04:32:17 assar Exp $");
37 
38 /*
39  * A log record consists of:
40  *
41  * version number		4 bytes
42  * time in seconds		4 bytes
43  * operation (enum kadm_ops)	4 bytes
44  * length of record		4 bytes
45  * data...			n bytes
46  * length of record		4 bytes
47  * version number		4 bytes
48  *
49  */
50 
51 kadm5_ret_t
52 kadm5_log_get_version_fd (int fd,
53 			  u_int32_t *ver)
54 {
55     int ret;
56     krb5_storage *sp;
57     int32_t old_version;
58 
59     ret = lseek (fd, 0, SEEK_END);
60     if(ret < 0)
61 	return errno;
62     if(ret == 0) {
63 	*ver = 0;
64 	return 0;
65     }
66     sp = krb5_storage_from_fd (fd);
67     sp->seek(sp, -4, SEEK_CUR);
68     krb5_ret_int32 (sp, &old_version);
69     *ver = old_version;
70     krb5_storage_free(sp);
71     lseek (fd, 0, SEEK_END);
72     return 0;
73 }
74 
75 kadm5_ret_t
76 kadm5_log_get_version (kadm5_server_context *context, u_int32_t *ver)
77 {
78     return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
79 }
80 
81 kadm5_ret_t
82 kadm5_log_set_version (kadm5_server_context *context, u_int32_t vno)
83 {
84     kadm5_log_context *log_context = &context->log_context;
85 
86     log_context->version = vno;
87     return 0;
88 }
89 
90 kadm5_ret_t
91 kadm5_log_init (kadm5_server_context *context)
92 {
93     int fd;
94     kadm5_ret_t ret;
95     kadm5_log_context *log_context = &context->log_context;
96 
97     if (log_context->log_fd != -1)
98 	return 0;
99     fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
100     if (fd < 0)
101 	return errno;
102     if (flock (fd, LOCK_EX) < 0) {
103 	close (fd);
104 	return errno;
105     }
106 
107     ret = kadm5_log_get_version_fd (fd, &log_context->version);
108     if (ret)
109 	return ret;
110 
111     log_context->log_fd  = fd;
112     return 0;
113 }
114 
115 kadm5_ret_t
116 kadm5_log_reinit (kadm5_server_context *context)
117 {
118     int fd;
119     kadm5_log_context *log_context = &context->log_context;
120 
121     if (log_context->log_fd != -1) {
122 	close (log_context->log_fd);
123 	log_context->log_fd = -1;
124     }
125     fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
126     if (fd < 0)
127 	return errno;
128     if (flock (fd, LOCK_EX) < 0) {
129 	close (fd);
130 	return errno;
131     }
132 
133     log_context->version = 0;
134     log_context->log_fd  = fd;
135     return 0;
136 }
137 
138 
139 kadm5_ret_t
140 kadm5_log_end (kadm5_server_context *context)
141 {
142     kadm5_log_context *log_context = &context->log_context;
143     int fd = log_context->log_fd;
144 
145     flock (fd, LOCK_UN);
146     close(fd);
147     log_context->log_fd = -1;
148     return 0;
149 }
150 
151 static kadm5_ret_t
152 kadm5_log_preamble (kadm5_server_context *context,
153 		    krb5_storage *sp,
154 		    enum kadm_ops op)
155 {
156     kadm5_log_context *log_context = &context->log_context;
157     kadm5_ret_t kadm_ret;
158 
159     kadm_ret = kadm5_log_init (context);
160     if (kadm_ret)
161 	return kadm_ret;
162 
163     krb5_store_int32 (sp, ++log_context->version);
164     krb5_store_int32 (sp, time(NULL));
165     krb5_store_int32 (sp, op);
166     return 0;
167 }
168 
169 static kadm5_ret_t
170 kadm5_log_postamble (kadm5_log_context *context,
171 		     krb5_storage *sp)
172 {
173     krb5_store_int32 (sp, context->version);
174     return 0;
175 }
176 
177 /*
178  * flush the log record in `sp'.
179  */
180 
181 static kadm5_ret_t
182 kadm5_log_flush (kadm5_log_context *log_context,
183 		 krb5_storage *sp)
184 {
185     krb5_data data;
186     size_t len;
187     int ret;
188 
189     krb5_storage_to_data(sp, &data);
190     len = data.length;
191     ret = write (log_context->log_fd, data.data, len);
192     if (ret != len) {
193 	krb5_data_free(&data);
194 	return errno;
195     }
196     if (fsync (log_context->log_fd) < 0) {
197 	krb5_data_free(&data);
198 	return errno;
199     }
200     /*
201      * Try to send a signal to any running `ipropd-master'
202      */
203     sendto (log_context->socket_fd,
204 	    (void *)&log_context->version,
205 	    sizeof(log_context->version),
206 	    0,
207 	    (struct sockaddr *)&log_context->socket_name,
208 	    sizeof(log_context->socket_name));
209 
210     krb5_data_free(&data);
211     return 0;
212 }
213 
214 /*
215  * Add a `create' operation to the log.
216  */
217 
218 kadm5_ret_t
219 kadm5_log_create (kadm5_server_context *context,
220 		  hdb_entry *ent)
221 {
222     krb5_storage *sp;
223     kadm5_ret_t ret;
224     krb5_data value;
225     kadm5_log_context *log_context = &context->log_context;
226 
227     sp = krb5_storage_emem();
228     ret = hdb_entry2value (context->context, ent, &value);
229     if (ret) {
230 	krb5_storage_free(sp);
231 	return ret;
232     }
233     ret = kadm5_log_preamble (context, sp, kadm_create);
234     if (ret) {
235 	krb5_data_free (&value);
236 	krb5_storage_free(sp);
237 	return ret;
238     }
239     krb5_store_int32 (sp, value.length);
240     sp->store(sp, value.data, value.length);
241     krb5_store_int32 (sp, value.length);
242     krb5_data_free (&value);
243     ret = kadm5_log_postamble (log_context, sp);
244     if (ret) {
245 	krb5_storage_free (sp);
246 	return ret;
247     }
248     ret = kadm5_log_flush (log_context, sp);
249     krb5_storage_free (sp);
250     if (ret)
251 	return ret;
252     ret = kadm5_log_end (context);
253     return ret;
254 }
255 
256 /*
257  * Read the data of a create log record from `sp' and change the
258  * database.
259  */
260 
261 kadm5_ret_t
262 kadm5_log_replay_create (kadm5_server_context *context,
263 			 u_int32_t ver,
264 			 u_int32_t len,
265 			 krb5_storage *sp)
266 {
267     krb5_error_code ret;
268     krb5_data data;
269     hdb_entry ent;
270 
271     krb5_data_alloc (&data, len);
272     sp->fetch (sp, data.data, len);
273     ret = hdb_value2entry (context->context, &data, &ent);
274     krb5_data_free(&data);
275     if (ret)
276 	return ret;
277     ret = context->db->store(context->context, context->db, 0, &ent);
278     hdb_free_entry (context->context, &ent);
279     return ret;
280 }
281 
282 /*
283  * Add a `delete' operation to the log.
284  */
285 
286 kadm5_ret_t
287 kadm5_log_delete (kadm5_server_context *context,
288 		  krb5_principal princ)
289 {
290     krb5_storage *sp;
291     kadm5_ret_t ret;
292     off_t off;
293     off_t len;
294     kadm5_log_context *log_context = &context->log_context;
295 
296     sp = krb5_storage_emem();
297     ret = kadm5_log_preamble (context, sp, kadm_delete);
298     if (ret) {
299 	krb5_storage_free(sp);
300 	return ret;
301     }
302     krb5_store_int32 (sp, 0);
303     off = sp->seek (sp, 0, SEEK_CUR);
304     krb5_store_principal (sp, princ);
305     len = sp->seek (sp, 0, SEEK_CUR) - off;
306     sp->seek(sp, -(len + 4), SEEK_CUR);
307     krb5_store_int32 (sp, len);
308     sp->seek(sp, len, SEEK_CUR);
309     krb5_store_int32 (sp, len);
310     if (ret) {
311 	krb5_storage_free (sp);
312 	return ret;
313     }
314     ret = kadm5_log_postamble (log_context, sp);
315     if (ret) {
316 	krb5_storage_free (sp);
317 	return ret;
318     }
319     ret = kadm5_log_flush (log_context, sp);
320     krb5_storage_free (sp);
321     if (ret)
322 	return ret;
323     ret = kadm5_log_end (context);
324     return ret;
325 }
326 
327 /*
328  * Read a `delete' log operation from `sp' and apply it.
329  */
330 
331 kadm5_ret_t
332 kadm5_log_replay_delete (kadm5_server_context *context,
333 			 u_int32_t ver,
334 			 u_int32_t len,
335 			 krb5_storage *sp)
336 {
337     krb5_error_code ret;
338     hdb_entry ent;
339 
340     krb5_ret_principal (sp, &ent.principal);
341 
342     ret = context->db->remove(context->context, context->db, &ent);
343     krb5_free_principal (context->context, ent.principal);
344     return ret;
345 }
346 
347 /*
348  * Add a `rename' operation to the log.
349  */
350 
351 kadm5_ret_t
352 kadm5_log_rename (kadm5_server_context *context,
353 		  krb5_principal source,
354 		  hdb_entry *ent)
355 {
356     krb5_storage *sp;
357     kadm5_ret_t ret;
358     off_t off;
359     off_t len;
360     krb5_data value;
361     kadm5_log_context *log_context = &context->log_context;
362 
363     sp = krb5_storage_emem();
364     ret = hdb_entry2value (context->context, ent, &value);
365     if (ret) {
366 	krb5_storage_free(sp);
367 	return ret;
368     }
369     ret = kadm5_log_preamble (context, sp, kadm_rename);
370     if (ret) {
371 	krb5_storage_free(sp);
372 	krb5_data_free (&value);
373 	return ret;
374     }
375     krb5_store_int32 (sp, 0);
376     off = sp->seek (sp, 0, SEEK_CUR);
377     krb5_store_principal (sp, source);
378     sp->store(sp, value.data, value.length);
379     krb5_data_free (&value);
380     len = sp->seek (sp, 0, SEEK_CUR) - off;
381 
382     sp->seek(sp, -(len + 4), SEEK_CUR);
383     krb5_store_int32 (sp, len);
384     sp->seek(sp, len, SEEK_CUR);
385     krb5_store_int32 (sp, len);
386     if (ret) {
387 	krb5_storage_free (sp);
388 	return ret;
389     }
390     ret = kadm5_log_postamble (log_context, sp);
391     if (ret) {
392 	krb5_storage_free (sp);
393 	return ret;
394     }
395     ret = kadm5_log_flush (log_context, sp);
396     krb5_storage_free (sp);
397     if (ret)
398 	return ret;
399     ret = kadm5_log_end (context);
400     return ret;
401 }
402 
403 /*
404  * Read a `rename' log operation from `sp' and apply it.
405  */
406 
407 kadm5_ret_t
408 kadm5_log_replay_rename (kadm5_server_context *context,
409 			 u_int32_t ver,
410 			 u_int32_t len,
411 			 krb5_storage *sp)
412 {
413     krb5_error_code ret;
414     krb5_principal source;
415     hdb_entry source_ent, target_ent;
416     krb5_data value;
417     off_t off;
418     size_t princ_len, data_len;
419 
420     off = sp->seek(sp, 0, SEEK_CUR);
421     krb5_ret_principal (sp, &source);
422     princ_len = sp->seek(sp, 0, SEEK_CUR) - off;
423     data_len = len - princ_len;
424     krb5_data_alloc (&value, data_len);
425     sp->fetch (sp, value.data, data_len);
426     ret = hdb_value2entry (context->context, &value, &target_ent);
427     krb5_data_free(&value);
428     if (ret) {
429 	krb5_free_principal (context->context, source);
430 	return ret;
431     }
432     ret = context->db->store (context->context, context->db, 0, &target_ent);
433     hdb_free_entry (context->context, &target_ent);
434     if (ret) {
435 	krb5_free_principal (context->context, source);
436 	return ret;
437     }
438     source_ent.principal = source;
439     ret = context->db->remove (context->context, context->db, &source_ent);
440     krb5_free_principal (context->context, source);
441     return ret;
442 }
443 
444 
445 /*
446  * Add a `modify' operation to the log.
447  */
448 
449 kadm5_ret_t
450 kadm5_log_modify (kadm5_server_context *context,
451 		  hdb_entry *ent,
452 		  u_int32_t mask)
453 {
454     krb5_storage *sp;
455     kadm5_ret_t ret;
456     krb5_data value;
457     u_int32_t len;
458     kadm5_log_context *log_context = &context->log_context;
459 
460     sp = krb5_storage_emem();
461     ret = hdb_entry2value (context->context, ent, &value);
462     if (ret) {
463 	krb5_storage_free(sp);
464 	return ret;
465     }
466     ret = kadm5_log_preamble (context, sp, kadm_modify);
467     if (ret) {
468 	krb5_data_free (&value);
469 	krb5_storage_free(sp);
470 	return ret;
471     }
472     len = value.length + 4;
473     krb5_store_int32 (sp, len);
474     krb5_store_int32 (sp, mask);
475     sp->store(sp, value.data, value.length);
476     krb5_data_free (&value);
477     krb5_store_int32 (sp, len);
478     if (ret) {
479 	krb5_storage_free (sp);
480 	return ret;
481     }
482     ret = kadm5_log_postamble (log_context, sp);
483     if (ret) {
484 	krb5_storage_free (sp);
485 	return ret;
486     }
487     ret = kadm5_log_flush (log_context, sp);
488     krb5_storage_free (sp);
489     if (ret)
490 	return ret;
491     ret = kadm5_log_end (context);
492     return ret;
493 }
494 
495 /*
496  * Read a `modify' log operation from `sp' and apply it.
497  */
498 
499 kadm5_ret_t
500 kadm5_log_replay_modify (kadm5_server_context *context,
501 			 u_int32_t ver,
502 			 u_int32_t len,
503 			 krb5_storage *sp)
504 {
505     krb5_error_code ret;
506     int32_t mask;
507     krb5_data value;
508     hdb_entry ent, log_ent;
509 
510     krb5_ret_int32 (sp, &mask);
511     len -= 4;
512     krb5_data_alloc (&value, len);
513     sp->fetch (sp, value.data, len);
514     ret = hdb_value2entry (context->context, &value, &log_ent);
515     krb5_data_free(&value);
516     if (ret)
517 	return ret;
518     ent.principal = log_ent.principal;
519     log_ent.principal = NULL;
520     ret = context->db->fetch(context->context, context->db,
521 			     HDB_F_DECRYPT, &ent);
522     if (ret)
523 	return ret;
524     if (mask & KADM5_PRINC_EXPIRE_TIME) {
525 	if (log_ent.valid_end == NULL) {
526 	    ent.valid_end = NULL;
527 	} else {
528 	    if (ent.valid_end == NULL)
529 		ent.valid_end = malloc(sizeof(*ent.valid_end));
530 	    *ent.valid_end = *log_ent.valid_end;
531 	}
532     }
533     if (mask & KADM5_PW_EXPIRATION) {
534 	if (log_ent.pw_end == NULL) {
535 	    ent.pw_end = NULL;
536 	} else {
537 	    if (ent.pw_end == NULL)
538 		ent.pw_end = malloc(sizeof(*ent.pw_end));
539 	    *ent.pw_end = *log_ent.pw_end;
540 	}
541     }
542     if (mask & KADM5_LAST_PWD_CHANGE) {
543 	abort ();		/* XXX */
544     }
545     if (mask & KADM5_ATTRIBUTES) {
546 	ent.flags = log_ent.flags;
547     }
548     if (mask & KADM5_MAX_LIFE) {
549 	if (log_ent.max_life == NULL) {
550 	    ent.max_life = NULL;
551 	} else {
552 	    if (ent.max_life == NULL)
553 		ent.max_life = malloc (sizeof(*ent.max_life));
554 	    *ent.max_life = *log_ent.max_life;
555 	}
556     }
557     if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
558 	if (ent.modified_by == NULL) {
559 	    ent.modified_by = malloc(sizeof(*ent.modified_by));
560 	} else
561 	    free_Event(ent.modified_by);
562 	copy_Event(log_ent.modified_by, ent.modified_by);
563     }
564     if (mask & KADM5_KVNO) {
565 	ent.kvno = log_ent.kvno;
566     }
567     if (mask & KADM5_MKVNO) {
568 	abort ();		/* XXX */
569     }
570     if (mask & KADM5_AUX_ATTRIBUTES) {
571 	abort ();		/* XXX */
572     }
573     if (mask & KADM5_POLICY) {
574 	abort ();		/* XXX */
575     }
576     if (mask & KADM5_POLICY_CLR) {
577 	abort ();		/* XXX */
578     }
579     if (mask & KADM5_MAX_RLIFE) {
580 	if (log_ent.max_renew == NULL) {
581 	    ent.max_renew = NULL;
582 	} else {
583 	    if (ent.max_renew == NULL)
584 		ent.max_renew = malloc (sizeof(*ent.max_renew));
585 	    *ent.max_renew = *log_ent.max_renew;
586 	}
587     }
588     if (mask & KADM5_LAST_SUCCESS) {
589 	abort ();		/* XXX */
590     }
591     if (mask & KADM5_LAST_FAILED) {
592 	abort ();		/* XXX */
593     }
594     if (mask & KADM5_FAIL_AUTH_COUNT) {
595 	abort ();		/* XXX */
596     }
597     if (mask & KADM5_KEY_DATA) {
598 	size_t len;
599 	int i;
600 
601 	for (i = 0; i < ent.keys.len; ++i)
602 	    free_Key(&ent.keys.val[i]);
603 	free (ent.keys.val);
604 
605 	len = log_ent.keys.len;
606 
607 	ent.keys.len = len;
608 	ent.keys.val = malloc(len * sizeof(*ent.keys.val));
609 	for (i = 0; i < ent.keys.len; ++i)
610 	    copy_Key(&log_ent.keys.val[i],
611 		     &ent.keys.val[i]);
612     }
613     ret = context->db->store(context->context, context->db,
614 			     HDB_F_REPLACE, &ent);
615     hdb_free_entry (context->context, &ent);
616     hdb_free_entry (context->context, &log_ent);
617     return ret;
618 }
619 
620 /*
621  * Add a `nop' operation to the log.
622  */
623 
624 kadm5_ret_t
625 kadm5_log_nop (kadm5_server_context *context)
626 {
627     krb5_storage *sp;
628     kadm5_ret_t ret;
629     kadm5_log_context *log_context = &context->log_context;
630 
631     sp = krb5_storage_emem();
632     ret = kadm5_log_preamble (context, sp, kadm_nop);
633     if (ret) {
634 	krb5_storage_free (sp);
635 	return ret;
636     }
637     krb5_store_int32 (sp, 0);
638     krb5_store_int32 (sp, 0);
639     ret = kadm5_log_postamble (log_context, sp);
640     if (ret) {
641 	krb5_storage_free (sp);
642 	return ret;
643     }
644     ret = kadm5_log_flush (log_context, sp);
645     krb5_storage_free (sp);
646     if (ret)
647 	return ret;
648     ret = kadm5_log_end (context);
649     return ret;
650 }
651 
652 /*
653  * Read a `nop' log operation from `sp' and apply it.
654  */
655 
656 kadm5_ret_t
657 kadm5_log_replay_nop (kadm5_server_context *context,
658 		      u_int32_t ver,
659 		      u_int32_t len,
660 		      krb5_storage *sp)
661 {
662     return 0;
663 }
664 
665 /*
666  * Call `func' for each log record in the log in `context'
667  */
668 
669 kadm5_ret_t
670 kadm5_log_foreach (kadm5_server_context *context,
671 		   void (*func)(kadm5_server_context *server_context,
672 				u_int32_t ver,
673 				time_t timestamp,
674 				enum kadm_ops op,
675 				u_int32_t len,
676 				krb5_storage *sp))
677 {
678     int fd = context->log_context.log_fd;
679     krb5_storage *sp;
680 
681     lseek (fd, 0, SEEK_SET);
682     sp = krb5_storage_from_fd (fd);
683     for (;;) {
684 	int32_t ver, timestamp, op, len;
685 
686 	if(krb5_ret_int32 (sp, &ver) != 0)
687 	    break;
688 	krb5_ret_int32 (sp, &timestamp);
689 	krb5_ret_int32 (sp, &op);
690 	krb5_ret_int32 (sp, &len);
691 	(*func)(context, ver, timestamp, op, len, sp);
692 	sp->seek(sp, 8, SEEK_CUR);
693     }
694     return 0;
695 }
696 
697 /*
698  * Go to end of log.
699  */
700 
701 krb5_storage *
702 kadm5_log_goto_end (int fd)
703 {
704     krb5_storage *sp;
705 
706     sp = krb5_storage_from_fd (fd);
707     sp->seek(sp, 0, SEEK_END);
708     return sp;
709 }
710 
711 /*
712  * Return previous log entry.
713  */
714 
715 kadm5_ret_t
716 kadm5_log_previous (krb5_storage *sp,
717 		    u_int32_t *ver,
718 		    time_t *timestamp,
719 		    enum kadm_ops *op,
720 		    u_int32_t *len)
721 {
722     off_t off;
723     int32_t tmp;
724 
725     sp->seek(sp, -8, SEEK_CUR);
726     krb5_ret_int32 (sp, &tmp);
727     *len = tmp;
728     krb5_ret_int32 (sp, &tmp);
729     *ver = tmp;
730     off = 24 + *len;
731     sp->seek(sp, -off, SEEK_CUR);
732     krb5_ret_int32 (sp, &tmp);
733     assert(tmp == *ver);
734     krb5_ret_int32 (sp, &tmp);
735     *timestamp = tmp;
736     krb5_ret_int32 (sp, &tmp);
737     *op = tmp;
738     krb5_ret_int32 (sp, &tmp);
739     assert(tmp == *len);
740     return 0;
741 }
742 
743 /*
744  * Replay a record from the log
745  */
746 
747 kadm5_ret_t
748 kadm5_log_replay (kadm5_server_context *context,
749 		  enum kadm_ops op,
750 		  u_int32_t ver,
751 		  u_int32_t len,
752 		  krb5_storage *sp)
753 {
754     switch (op) {
755     case kadm_create :
756 	return kadm5_log_replay_create (context, ver, len, sp);
757     case kadm_delete :
758 	return kadm5_log_replay_delete (context, ver, len, sp);
759     case kadm_rename :
760 	return kadm5_log_replay_rename (context, ver, len, sp);
761     case kadm_modify :
762 	return kadm5_log_replay_modify (context, ver, len, sp);
763     case kadm_nop :
764 	return kadm5_log_replay_nop (context, ver, len, sp);
765     default :
766 	return KADM5_FAILURE;
767     }
768 }
769 
770 /*
771  * truncate the log - i.e. create an empty file with just (nop vno + 2)
772  */
773 
774 kadm5_ret_t
775 kadm5_log_truncate (kadm5_server_context *server_context)
776 {
777     kadm5_ret_t ret;
778     u_int32_t vno;
779 
780     ret = kadm5_log_init (server_context);
781     if (ret)
782 	return ret;
783 
784     ret = kadm5_log_get_version (server_context, &vno);
785     if (ret)
786 	return ret;
787 
788     ret = kadm5_log_reinit (server_context);
789     if (ret)
790 	return ret;
791 
792     ret = kadm5_log_set_version (server_context, vno + 1);
793     if (ret)
794 	return ret;
795 
796     ret = kadm5_log_nop (server_context);
797     if (ret)
798 	return ret;
799 
800     ret = kadm5_log_end (server_context);
801     if (ret)
802 	return ret;
803     return 0;
804 
805 }
806