remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / kadm5 / log.c
1 /*
2  * Copyright (c) 1997 - 2003 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.20 2003/04/16 17:56:55 lha 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     krb5_storage_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     krb5_storage_write(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     ret = krb5_data_alloc (&data, len);
272     if (ret)
273         return ret;
274     krb5_storage_read (sp, data.data, len);
275     ret = hdb_value2entry (context->context, &data, &ent);
276     krb5_data_free(&data);
277     if (ret)
278         return ret;
279     ret = context->db->store(context->context, context->db, 0, &ent);
280     hdb_free_entry (context->context, &ent);
281     return ret;
282 }
283
284 /*
285  * Add a `delete' operation to the log.
286  */
287
288 kadm5_ret_t
289 kadm5_log_delete (kadm5_server_context *context,
290                   krb5_principal princ)
291 {
292     krb5_storage *sp;
293     kadm5_ret_t ret;
294     off_t off;
295     off_t len;
296     kadm5_log_context *log_context = &context->log_context;
297
298     sp = krb5_storage_emem();
299     ret = kadm5_log_preamble (context, sp, kadm_delete);
300     if (ret) {
301         krb5_storage_free(sp);
302         return ret;
303     }
304     krb5_store_int32 (sp, 0);
305     off = krb5_storage_seek (sp, 0, SEEK_CUR);
306     krb5_store_principal (sp, princ);
307     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
308     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
309     krb5_store_int32 (sp, len);
310     krb5_storage_seek(sp, len, SEEK_CUR);
311     krb5_store_int32 (sp, len);
312     if (ret) {
313         krb5_storage_free (sp);
314         return ret;
315     }
316     ret = kadm5_log_postamble (log_context, sp);
317     if (ret) {
318         krb5_storage_free (sp);
319         return ret;
320     }
321     ret = kadm5_log_flush (log_context, sp);
322     krb5_storage_free (sp);
323     if (ret)
324         return ret;
325     ret = kadm5_log_end (context);
326     return ret;
327 }
328
329 /*
330  * Read a `delete' log operation from `sp' and apply it.
331  */
332
333 kadm5_ret_t
334 kadm5_log_replay_delete (kadm5_server_context *context,
335                          u_int32_t ver,
336                          u_int32_t len,
337                          krb5_storage *sp)
338 {
339     krb5_error_code ret;
340     hdb_entry ent;
341
342     krb5_ret_principal (sp, &ent.principal);
343
344     ret = context->db->remove(context->context, context->db, &ent);
345     krb5_free_principal (context->context, ent.principal);
346     return ret;
347 }
348
349 /*
350  * Add a `rename' operation to the log.
351  */
352
353 kadm5_ret_t
354 kadm5_log_rename (kadm5_server_context *context,
355                   krb5_principal source,
356                   hdb_entry *ent)
357 {
358     krb5_storage *sp;
359     kadm5_ret_t ret;
360     off_t off;
361     off_t len;
362     krb5_data value;
363     kadm5_log_context *log_context = &context->log_context;
364
365     sp = krb5_storage_emem();
366     ret = hdb_entry2value (context->context, ent, &value);
367     if (ret) {
368         krb5_storage_free(sp);
369         return ret;
370     }
371     ret = kadm5_log_preamble (context, sp, kadm_rename);
372     if (ret) {
373         krb5_storage_free(sp);
374         krb5_data_free (&value);
375         return ret;
376     }
377     krb5_store_int32 (sp, 0);
378     off = krb5_storage_seek (sp, 0, SEEK_CUR);
379     krb5_store_principal (sp, source);
380     krb5_storage_write(sp, value.data, value.length);
381     krb5_data_free (&value);
382     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
383
384     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
385     krb5_store_int32 (sp, len);
386     krb5_storage_seek(sp, len, SEEK_CUR);
387     krb5_store_int32 (sp, len);
388     if (ret) {
389         krb5_storage_free (sp);
390         return ret;
391     }
392     ret = kadm5_log_postamble (log_context, sp);
393     if (ret) {
394         krb5_storage_free (sp);
395         return ret;
396     }
397     ret = kadm5_log_flush (log_context, sp);
398     krb5_storage_free (sp);
399     if (ret)
400         return ret;
401     ret = kadm5_log_end (context);
402     return ret;
403 }
404
405 /*
406  * Read a `rename' log operation from `sp' and apply it.
407  */
408
409 kadm5_ret_t
410 kadm5_log_replay_rename (kadm5_server_context *context,
411                          u_int32_t ver,
412                          u_int32_t len,
413                          krb5_storage *sp)
414 {
415     krb5_error_code ret;
416     krb5_principal source;
417     hdb_entry source_ent, target_ent;
418     krb5_data value;
419     off_t off;
420     size_t princ_len, data_len;
421
422     off = krb5_storage_seek(sp, 0, SEEK_CUR);
423     krb5_ret_principal (sp, &source);
424     princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
425     data_len = len - princ_len;
426     ret = krb5_data_alloc (&value, data_len);
427     if (ret) {
428         krb5_free_principal (context->context, source);
429         return ret;
430     }
431     krb5_storage_read (sp, value.data, data_len);
432     ret = hdb_value2entry (context->context, &value, &target_ent);
433     krb5_data_free(&value);
434     if (ret) {
435         krb5_free_principal (context->context, source);
436         return ret;
437     }
438     ret = context->db->store (context->context, context->db, 0, &target_ent);
439     hdb_free_entry (context->context, &target_ent);
440     if (ret) {
441         krb5_free_principal (context->context, source);
442         return ret;
443     }
444     source_ent.principal = source;
445     ret = context->db->remove (context->context, context->db, &source_ent);
446     krb5_free_principal (context->context, source);
447     return ret;
448 }
449
450
451 /*
452  * Add a `modify' operation to the log.
453  */
454
455 kadm5_ret_t
456 kadm5_log_modify (kadm5_server_context *context,
457                   hdb_entry *ent,
458                   u_int32_t mask)
459 {
460     krb5_storage *sp;
461     kadm5_ret_t ret;
462     krb5_data value;
463     u_int32_t len;
464     kadm5_log_context *log_context = &context->log_context;
465
466     sp = krb5_storage_emem();
467     ret = hdb_entry2value (context->context, ent, &value);
468     if (ret) {
469         krb5_storage_free(sp);
470         return ret;
471     }
472     ret = kadm5_log_preamble (context, sp, kadm_modify);
473     if (ret) {
474         krb5_data_free (&value);
475         krb5_storage_free(sp);
476         return ret;
477     }
478     len = value.length + 4;
479     krb5_store_int32 (sp, len);
480     krb5_store_int32 (sp, mask);
481     krb5_storage_write (sp, value.data, value.length);
482     krb5_data_free (&value);
483     krb5_store_int32 (sp, len);
484     if (ret) {
485         krb5_storage_free (sp);
486         return ret;
487     }
488     ret = kadm5_log_postamble (log_context, sp);
489     if (ret) {
490         krb5_storage_free (sp);
491         return ret;
492     }
493     ret = kadm5_log_flush (log_context, sp);
494     krb5_storage_free (sp);
495     if (ret)
496         return ret;
497     ret = kadm5_log_end (context);
498     return ret;
499 }
500
501 /*
502  * Read a `modify' log operation from `sp' and apply it.
503  */
504
505 kadm5_ret_t
506 kadm5_log_replay_modify (kadm5_server_context *context,
507                          u_int32_t ver,
508                          u_int32_t len,
509                          krb5_storage *sp)
510 {
511     krb5_error_code ret;
512     int32_t mask;
513     krb5_data value;
514     hdb_entry ent, log_ent;
515
516     krb5_ret_int32 (sp, &mask);
517     len -= 4;
518     ret = krb5_data_alloc (&value, len);
519     if (ret)
520         return ret;
521     krb5_storage_read (sp, value.data, len);
522     ret = hdb_value2entry (context->context, &value, &log_ent);
523     krb5_data_free(&value);
524     if (ret)
525         return ret;
526     ent.principal = log_ent.principal;
527     log_ent.principal = NULL;
528     ret = context->db->fetch(context->context, context->db, 
529                              HDB_F_DECRYPT, &ent);
530     if (ret)
531         return ret;
532     if (mask & KADM5_PRINC_EXPIRE_TIME) {
533         if (log_ent.valid_end == NULL) {
534             ent.valid_end = NULL;
535         } else {
536             if (ent.valid_end == NULL)
537                 ent.valid_end = malloc(sizeof(*ent.valid_end));
538             *ent.valid_end = *log_ent.valid_end;
539         }
540     }
541     if (mask & KADM5_PW_EXPIRATION) {
542         if (log_ent.pw_end == NULL) {
543             ent.pw_end = NULL;
544         } else {
545             if (ent.pw_end == NULL)
546                 ent.pw_end = malloc(sizeof(*ent.pw_end));
547             *ent.pw_end = *log_ent.pw_end;
548         }
549     }
550     if (mask & KADM5_LAST_PWD_CHANGE) {
551         abort ();               /* XXX */
552     }
553     if (mask & KADM5_ATTRIBUTES) {
554         ent.flags = log_ent.flags;
555     }
556     if (mask & KADM5_MAX_LIFE) {
557         if (log_ent.max_life == NULL) {
558             ent.max_life = NULL;
559         } else {
560             if (ent.max_life == NULL)
561                 ent.max_life = malloc (sizeof(*ent.max_life));
562             *ent.max_life = *log_ent.max_life;
563         }
564     }
565     if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
566         if (ent.modified_by == NULL) {
567             ent.modified_by = malloc(sizeof(*ent.modified_by));
568         } else
569             free_Event(ent.modified_by);
570         copy_Event(log_ent.modified_by, ent.modified_by);
571     }
572     if (mask & KADM5_KVNO) {
573         ent.kvno = log_ent.kvno;
574     }
575     if (mask & KADM5_MKVNO) {
576         abort ();               /* XXX */
577     }
578     if (mask & KADM5_AUX_ATTRIBUTES) {
579         abort ();               /* XXX */
580     }
581     if (mask & KADM5_POLICY) {
582         abort ();               /* XXX */
583     }
584     if (mask & KADM5_POLICY_CLR) {
585         abort ();               /* XXX */
586     }
587     if (mask & KADM5_MAX_RLIFE) {
588         if (log_ent.max_renew == NULL) {
589             ent.max_renew = NULL;
590         } else {
591             if (ent.max_renew == NULL)
592                 ent.max_renew = malloc (sizeof(*ent.max_renew));
593             *ent.max_renew = *log_ent.max_renew;
594         }
595     }
596     if (mask & KADM5_LAST_SUCCESS) {
597         abort ();               /* XXX */
598     }
599     if (mask & KADM5_LAST_FAILED) {
600         abort ();               /* XXX */
601     }
602     if (mask & KADM5_FAIL_AUTH_COUNT) {
603         abort ();               /* XXX */
604     }
605     if (mask & KADM5_KEY_DATA) {
606         size_t len;
607         int i;
608
609         for (i = 0; i < ent.keys.len; ++i)
610             free_Key(&ent.keys.val[i]);
611         free (ent.keys.val);
612
613         len = log_ent.keys.len;
614
615         ent.keys.len = len;
616         ent.keys.val = malloc(len * sizeof(*ent.keys.val));
617         for (i = 0; i < ent.keys.len; ++i)
618             copy_Key(&log_ent.keys.val[i],
619                      &ent.keys.val[i]);
620     }
621     ret = context->db->store(context->context, context->db, 
622                              HDB_F_REPLACE, &ent);
623     hdb_free_entry (context->context, &ent);
624     hdb_free_entry (context->context, &log_ent);
625     return ret;
626 }
627
628 /*
629  * Add a `nop' operation to the log.
630  */
631
632 kadm5_ret_t
633 kadm5_log_nop (kadm5_server_context *context)
634 {
635     krb5_storage *sp;
636     kadm5_ret_t ret;
637     kadm5_log_context *log_context = &context->log_context;
638
639     sp = krb5_storage_emem();
640     ret = kadm5_log_preamble (context, sp, kadm_nop);
641     if (ret) {
642         krb5_storage_free (sp);
643         return ret;
644     }
645     krb5_store_int32 (sp, 0);
646     krb5_store_int32 (sp, 0);
647     ret = kadm5_log_postamble (log_context, sp);
648     if (ret) {
649         krb5_storage_free (sp);
650         return ret;
651     }
652     ret = kadm5_log_flush (log_context, sp);
653     krb5_storage_free (sp);
654     if (ret)
655         return ret;
656     ret = kadm5_log_end (context);
657     return ret;
658 }
659
660 /*
661  * Read a `nop' log operation from `sp' and apply it.
662  */
663
664 kadm5_ret_t
665 kadm5_log_replay_nop (kadm5_server_context *context,
666                       u_int32_t ver,
667                       u_int32_t len,
668                       krb5_storage *sp)
669 {
670     return 0;
671 }
672
673 /*
674  * Call `func' for each log record in the log in `context'
675  */
676
677 kadm5_ret_t
678 kadm5_log_foreach (kadm5_server_context *context,
679                    void (*func)(kadm5_server_context *server_context,
680                                 u_int32_t ver,
681                                 time_t timestamp,
682                                 enum kadm_ops op,
683                                 u_int32_t len,
684                                 krb5_storage *sp))
685 {
686     int fd = context->log_context.log_fd;
687     krb5_storage *sp;
688
689     lseek (fd, 0, SEEK_SET);
690     sp = krb5_storage_from_fd (fd);
691     for (;;) {
692         int32_t ver, timestamp, op, len;
693
694         if(krb5_ret_int32 (sp, &ver) != 0)
695             break;
696         krb5_ret_int32 (sp, &timestamp);
697         krb5_ret_int32 (sp, &op);
698         krb5_ret_int32 (sp, &len);
699         (*func)(context, ver, timestamp, op, len, sp);
700         krb5_storage_seek(sp, 8, SEEK_CUR);
701     }
702     return 0;
703 }
704
705 /*
706  * Go to end of log.
707  */
708
709 krb5_storage *
710 kadm5_log_goto_end (int fd)
711 {
712     krb5_storage *sp;
713
714     sp = krb5_storage_from_fd (fd);
715     krb5_storage_seek(sp, 0, SEEK_END);
716     return sp;
717 }
718
719 /*
720  * Return previous log entry.
721  */
722
723 kadm5_ret_t
724 kadm5_log_previous (krb5_storage *sp,
725                     u_int32_t *ver,
726                     time_t *timestamp,
727                     enum kadm_ops *op,
728                     u_int32_t *len)
729 {
730     off_t off;
731     int32_t tmp;
732
733     krb5_storage_seek(sp, -8, SEEK_CUR);
734     krb5_ret_int32 (sp, &tmp);
735     *len = tmp;
736     krb5_ret_int32 (sp, &tmp);
737     *ver = tmp;
738     off = 24 + *len;
739     krb5_storage_seek(sp, -off, SEEK_CUR);
740     krb5_ret_int32 (sp, &tmp);
741     assert(tmp == *ver);
742     krb5_ret_int32 (sp, &tmp);
743     *timestamp = tmp;
744     krb5_ret_int32 (sp, &tmp);
745     *op = tmp;
746     krb5_ret_int32 (sp, &tmp);
747     assert(tmp == *len);
748     return 0;
749 }
750
751 /*
752  * Replay a record from the log
753  */
754
755 kadm5_ret_t
756 kadm5_log_replay (kadm5_server_context *context,
757                   enum kadm_ops op,
758                   u_int32_t ver,
759                   u_int32_t len,
760                   krb5_storage *sp)
761 {
762     switch (op) {
763     case kadm_create :
764         return kadm5_log_replay_create (context, ver, len, sp);
765     case kadm_delete :
766         return kadm5_log_replay_delete (context, ver, len, sp);
767     case kadm_rename :
768         return kadm5_log_replay_rename (context, ver, len, sp);
769     case kadm_modify :
770         return kadm5_log_replay_modify (context, ver, len, sp);
771     case kadm_nop :
772         return kadm5_log_replay_nop (context, ver, len, sp);
773     default :
774         return KADM5_FAILURE;
775     }
776 }
777
778 /*
779  * truncate the log - i.e. create an empty file with just (nop vno + 2)
780  */
781
782 kadm5_ret_t
783 kadm5_log_truncate (kadm5_server_context *server_context)
784 {
785     kadm5_ret_t ret;
786     u_int32_t vno;
787
788     ret = kadm5_log_init (server_context);
789     if (ret)
790         return ret;
791
792     ret = kadm5_log_get_version (server_context, &vno);
793     if (ret)
794         return ret;
795
796     ret = kadm5_log_reinit (server_context);
797     if (ret)
798         return ret;
799
800     ret = kadm5_log_set_version (server_context, vno + 1);
801     if (ret)
802         return ret;
803
804     ret = kadm5_log_nop (server_context);
805     if (ret)
806         return ret;
807
808     ret = kadm5_log_end (server_context);
809     if (ret)
810         return ret;
811     return 0;
812
813 }