Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / heimdal / lib / kadm5 / log.c
1 /*
2  * Copyright (c) 1997 - 2002 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.19 2002/05/24 15:19:21 joda 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     krb5_data_alloc (&data, len);
272     krb5_storage_read (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 = krb5_storage_seek (sp, 0, SEEK_CUR);
304     krb5_store_principal (sp, princ);
305     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
306     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
307     krb5_store_int32 (sp, len);
308     krb5_storage_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 = krb5_storage_seek (sp, 0, SEEK_CUR);
377     krb5_store_principal (sp, source);
378     krb5_storage_write(sp, value.data, value.length);
379     krb5_data_free (&value);
380     len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
381
382     krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
383     krb5_store_int32 (sp, len);
384     krb5_storage_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 = krb5_storage_seek(sp, 0, SEEK_CUR);
421     krb5_ret_principal (sp, &source);
422     princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
423     data_len = len - princ_len;
424     krb5_data_alloc (&value, data_len);
425     krb5_storage_read (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     krb5_storage_write (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     krb5_storage_read (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         krb5_storage_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     krb5_storage_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     krb5_storage_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     krb5_storage_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 }