From 38a233b28a0d6efc9f00addb96c6688bc009f59e Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Fri, 18 Aug 1995 02:43:55 +0000 Subject: [PATCH] First cut of ktutil; change functions have not yet been added git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6547 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kadmin/ktutil/.cvsignore | 1 + src/kadmin/ktutil/ChangeLog | 0 src/kadmin/ktutil/Makefile.in | 32 +++ src/kadmin/ktutil/configure.in | 10 + src/kadmin/ktutil/ktutil.c | 225 ++++++++++++++++++ src/kadmin/ktutil/ktutil.h | 58 +++++ src/kadmin/ktutil/ktutil_ct.ct | 51 +++++ src/kadmin/ktutil/ktutil_funcs.c | 382 +++++++++++++++++++++++++++++++ 8 files changed, 759 insertions(+) create mode 100644 src/kadmin/ktutil/.cvsignore create mode 100644 src/kadmin/ktutil/ChangeLog create mode 100644 src/kadmin/ktutil/Makefile.in create mode 100644 src/kadmin/ktutil/configure.in create mode 100644 src/kadmin/ktutil/ktutil.c create mode 100644 src/kadmin/ktutil/ktutil.h create mode 100644 src/kadmin/ktutil/ktutil_ct.ct create mode 100644 src/kadmin/ktutil/ktutil_funcs.c diff --git a/src/kadmin/ktutil/.cvsignore b/src/kadmin/ktutil/.cvsignore new file mode 100644 index 000000000..e8c05a6b1 --- /dev/null +++ b/src/kadmin/ktutil/.cvsignore @@ -0,0 +1 @@ +configure diff --git a/src/kadmin/ktutil/ChangeLog b/src/kadmin/ktutil/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/kadmin/ktutil/Makefile.in b/src/kadmin/ktutil/Makefile.in new file mode 100644 index 000000000..d59ad0709 --- /dev/null +++ b/src/kadmin/ktutil/Makefile.in @@ -0,0 +1,32 @@ +CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) + +all:: + +OBJS= ktutil.o \ + ktutil_ct.o \ + ktutil_funcs.o + +SRCS= $(srcdir)/ktutil.c \ + $(srcdir)/ktutil_ct.c \ + $(srcdir)/ktutil_funcs.c + +all:: ktutil + +ktutil: ktutil.o $(OBJS) $(DEPLIBS) + $(LD) $(LDFLAGS) $(LDARGS) -o ktutil $(OBJS) $(LIBS) + +install:: + $(INSTALL_PROGRAM) ktutil ${DESTDIR}$(ADMIN_BINDIR)/ktutil + +# needed until we run makedepend +ktutil_ct.c: ktutil_ct.ct + +ktutil_ct.o: ktutil_ct.c + +clean:: + $(RM) ktutil_ct.c + +depend:: ktutil_ct.c + +clean:: + $(RM) ktutil diff --git a/src/kadmin/ktutil/configure.in b/src/kadmin/ktutil/configure.in new file mode 100644 index 000000000..6797af109 --- /dev/null +++ b/src/kadmin/ktutil/configure.in @@ -0,0 +1,10 @@ +AC_INIT(ktutil.c) +CONFIG_RULES +AC_PROG_INSTALL +SS_RULES +USE_KADM_LIBRARY +USE_KRB4_LIBRARY +USE_SS_LIBRARY +KRB5_LIBRARIES +V5_USE_SHARED_LIB +V5_AC_OUTPUT_MAKEFILE diff --git a/src/kadmin/ktutil/ktutil.c b/src/kadmin/ktutil/ktutil.c new file mode 100644 index 000000000..ae886ba10 --- /dev/null +++ b/src/kadmin/ktutil/ktutil.c @@ -0,0 +1,225 @@ +/* + * kadmin/ktutil/ktutil.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * SS user interface for ktutil. + */ + +#include "k5-int.h" +#include "ktutil.h" +#include +#include +#include +#ifdef HAS_STDLIB_H +#include +#endif + +extern ss_request_table ktutil_cmds; +krb5_context kcontext; +krb5_kt_list ktlist = NULL; + +static char *Month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +int main(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval; + extern krb5_kt_ops krb5_ktf_writable_ops; + int sci_idx; + + krb5_init_context(&kcontext); + krb5_init_ets(kcontext); + retval = krb5_kt_register(kcontext, &krb5_ktf_writable_ops); + if (retval) { + com_err(argv[0], retval, + "while registering writable key table functions"); + exit(1); + } + sci_idx = ss_create_invocation("ktutil", "5.0", (char *)NULL, + &ktutil_cmds, &retval); + if (retval) { + ss_perror(sci_idx, retval, "creating invocation"); + exit(1); + } + ss_listen(sci_idx, &retval); + ktutil_free_kt_list(kcontext, ktlist); + exit(0); +} + +void ktutil_clear_list(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval; + + if (argc != 1) { + fprintf(stderr, "%s: invalid arguments\n", argv[0]); + return; + } + retval = ktutil_free_kt_list(kcontext, ktlist); + if (retval) + com_err(argv[0], retval, "while freeing ktlist"); + ktlist = NULL; +} + +void ktutil_read_v5(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval; + + if (argc != 2) { + fprintf(stderr, "%s: must specify keytab to read\n", argv[0]); + return; + } + retval = ktutil_read_keytab(kcontext, argv[1], &ktlist); + if (retval) + com_err(argv[0], retval, "while reading keytab \"%s\"", argv[1]); +} + +void ktutil_read_v4(argc, argv) + int argc; + char *argv[]; +{ +#ifdef KRB5_KRB4_COMPAT + krb5_error_code retval; + + if (argc != 2) { + fprintf(stderr, "%s: must specify the srvtab to read\n", argv[0]); + return; + } + retval = ktutil_read_srvtab(kcontext, argv[1], &ktlist); + if (retval) + com_err(argv[0], retval, "while reading srvtab \"%s\"", argv[1]); +#else + fprintf(stderr, "%s: krb4 support not configured\n", argv[0]); +#endif +} + +void ktutil_write_v5(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval; + + if (argc != 2) { + fprintf(stderr, "%s: must specify keytab to write\n", argv[0]); + return; + } + retval = ktutil_write_keytab(kcontext, ktlist, argv[1]); + if (retval) + com_err(argv[0], retval, "while writing keytab \"%s\"", argv[1]); +} + +void ktutil_write_v4(argc, argv) + int argc; + char *argv[]; +{ +#ifdef KRB5_KRB4_COMPAT + krb5_error_code retval; + + if (argc != 2) { + fprintf(stderr, "%s: must specify srvtab to write\n", argv[0]); + return; + } + retval = ktutil_write_keytab(kcontext, ktlist, argv[1]); + if (retval) + com_err(argv[0], retval, "while writing srvtab \"%s\"", argv[1]); +#else + fprintf(stderr, "%s: krb4 support not configured\n", argv[0]); +#endif +} + +void ktutil_delete_entry(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval; + + if (argc != 2) { + fprintf(stderr, "%s: must specify entry to delete\n", argv[0]); + return; + } + retval = ktutil_delete(kcontext, &ktlist, atoi(argv[1])); + if (retval) + com_err(argv[0], retval, "while deleting entry %d", atoi(argv[1])); +} + +void ktutil_list(argc, argv) + int argc; + char *argv[]; +{ + krb5_error_code retval; + krb5_kt_list lp; + struct tm *stime; + int show_time = 0, show_keys = 0; + int i, j; + char *pname; + + for (i = 1; i < argc; i++) { + if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-t", 2)) { + show_time++; + continue; + } + if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-k", 2)) { + show_keys++; + continue; + } + fprintf(stderr, "%s: illegal arguments\n", argv[0]); + return; + } + if (show_time) { + printf("slot KVNO Timestamp Principal\n"); + printf("---- ---- ------------------ -------------------------------------------------------\n"); + } else { + printf("slot KVNO Principal\n"); + printf("---- ---- --------------------------------------------------------------------------\n"); + } + for (i = 1, lp = ktlist; lp; i++, lp = lp->next) { + retval = krb5_unparse_name(kcontext, lp->entry->principal, &pname); + if (retval) { + com_err(argv[0], retval, "while unparsing principal name"); + return; + } + printf("%4d %4d ", i, lp->entry->vno); + if (show_time) { + stime = localtime((time_t *)&lp->entry->timestamp); + printf("%2d-%s-%2d %02d:%02d:%02d ", + stime->tm_mday, + Month_names[stime->tm_mon], + stime->tm_year, + stime->tm_hour, + stime->tm_min, + stime->tm_sec); + } + printf("%40s", pname); + if (show_keys) { + printf(" (0x"); + for (j = 0; j < lp->entry->key.length; j++) + printf("%02x", lp->entry->key.contents[j]); + printf(")"); + } + printf("\n"); + krb5_xfree(pname); + } +} diff --git a/src/kadmin/ktutil/ktutil.h b/src/kadmin/ktutil/ktutil.h new file mode 100644 index 000000000..0f14defb7 --- /dev/null +++ b/src/kadmin/ktutil/ktutil.h @@ -0,0 +1,58 @@ +/* + * kadmin/ktutil/ktutil.h + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +typedef struct _krb5_kt_list { + struct _krb5_kt_list *next; + krb5_keytab_entry *entry; +} *krb5_kt_list; + +krb5_error_code ktutil_free_kt_list + KRB5_PROTOTYPE((krb5_context, + krb5_kt_list)); + +krb5_error_code ktutil_delete + KRB5_PROTOTYPE((krb5_context, + krb5_kt_list *, + int)); + +krb5_error_code ktutil_read_keytab + KRB5_PROTOTYPE((krb5_context, + char *, + krb5_kt_list *)); + +krb5_error_code ktutil_write_keytab + KRB5_PROTOTYPE((krb5_context, + krb5_kt_list, + char *)); + +#ifdef KRB5_KRB4_COMPAT +krb5_error_code ktutil_read_srvtab + KRB5_PROTOTYPE((krb5_context, + char *, + krb5_kt_list *)); +krb5_error_code ktutil_write_srvtab + KRB5_PROTOTYPE((krb5_context, + krb5_kt_list, + char *)); +#endif diff --git a/src/kadmin/ktutil/ktutil_ct.ct b/src/kadmin/ktutil/ktutil_ct.ct new file mode 100644 index 000000000..1f0269f6d --- /dev/null +++ b/src/kadmin/ktutil/ktutil_ct.ct @@ -0,0 +1,51 @@ +# Copyright 1995 by the Massachusetts Institute of Technology. +# All Rights Reserved. +# +# Export of this software from the United States of America may +# require a specific license from the United States Government. +# It is the responsibility of any person or organization contemplating +# export to obtain such a license before exporting. +# +# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +# distribute this software and its documentation for any purpose and +# without fee is hereby granted, provided that the above copyright +# notice appear in all copies and that both that copyright notice and +# this permission notice appear in supporting documentation, and that +# the name of M.I.T. not be used in advertising or publicity pertaining +# to distribution of the software without specific, written prior +# permission. M.I.T. makes no representations about the suitability of +# this software for any purpose. It is provided "as is" without express +# or implied warranty. +# +# +# Command table for ktutil +# + +command_table ktutil_cmds; + +request ktutil_clear_list, "Clear the current keylist.", + clear_list, clear; + +request ktutil_read_v5, "Read a krb5 keytab into the current keylist.", + read_kt, rkt; + +request ktutil_read_v4, "Read a krb4 srvtab into the current keylist.", + read_st, rst; + +request ktutil_write_v5, "Write the current keylist to a krb5 keytab.", + write_kt, wkt; + +request ktutil_write_v4, "Write the current keylist to a krb4 srvtab.", + write_st, wst; + +request ktutil_delete_entry, "Delete an entry from the current keylist.", + delete_entry, delent; + +request ktutil_list, "List the current keylist.", + list, l; + +request ss_list_requests, "List available requests.", + list_requests, lr, "?"; + +request ss_quit, "Exit program.", + quit, exit, q; diff --git a/src/kadmin/ktutil/ktutil_funcs.c b/src/kadmin/ktutil/ktutil_funcs.c new file mode 100644 index 000000000..2702c840e --- /dev/null +++ b/src/kadmin/ktutil/ktutil_funcs.c @@ -0,0 +1,382 @@ +/* + * kadmin/ktutil/ktutil_funcs.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Utility functions for ktutil. + */ + +#include "k5-int.h" +#include "ktutil.h" +#ifdef KRB5_KRB4_COMPAT +#include "kerberosIV/krb.h" +#include +#endif +#include + +/* + * Free a kt_list + */ +krb5_error_code ktutil_free_kt_list(context, list) + krb5_context context; + krb5_kt_list list; +{ + krb5_kt_list lp, prev; + krb5_error_code retval = 0; + + for (lp = list; lp;) { + retval = krb5_kt_free_entry(context, lp->entry); + krb5_xfree(lp->entry); + if (retval) + break; + prev = lp; + lp = lp->next; + krb5_xfree(prev); + } + return retval; +} + +/* + * Delete a numbered entry in a kt_list. Takes a pointer to a kt_list + * in case head gets deleted. + */ +krb5_error_code ktutil_delete(context, list, index) + krb5_context context; + krb5_kt_list *list; + int index; +{ + krb5_kt_list lp, prev; + int i; + + for (lp = *list, i = 1; lp; prev = lp, lp = lp->next, i++) { + if (i == index) { + if (i == 1) + *list = lp->next; + else + prev->next = lp->next; + lp->next = NULL; + return ktutil_free_kt_list(context, lp); + } + } + return EINVAL; +} + +/* + * Read in a keytab and append it to list. If list starts as NULL, + * allocate a new one if necessary. + */ +krb5_error_code ktutil_read_keytab(context, name, list) + krb5_context context; + char *name; + krb5_kt_list *list; +{ + krb5_kt_list lp = NULL, tail = NULL, back = NULL; + krb5_keytab kt; + krb5_keytab_entry *entry; + krb5_kt_cursor cursor; + krb5_error_code retval = 0; + + if (*list) { + /* point lp at the tail of the list */ + for (lp = *list; lp->next; lp = lp->next); + back = lp; + } + retval = krb5_kt_resolve(context, name, &kt); + if (retval) + return retval; + retval = krb5_kt_start_seq_get(context, kt, &cursor); + if (retval) + goto close_kt; + for (;;) { + entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry)); + if (!entry) { + retval = ENOMEM; + break; + } + memset((char *)entry, 0, sizeof (*entry)); + retval = krb5_kt_next_entry(context, kt, entry, &cursor); + if (retval) + break; + if (!lp) { /* if list is empty, start one */ + lp = (krb5_kt_list)malloc(sizeof (*lp)); + if (!lp) { + retval = ENOMEM; + break; + } + } else { + lp->next = (krb5_kt_list)malloc(sizeof (*lp)); + if (!lp->next) { + retval = ENOMEM; + break; + } + lp = lp->next; + } + if (!tail) + tail = lp; + lp->next = NULL; + lp->entry = entry; + } + if (entry) + krb5_xfree(entry); + if (retval) + if (retval == KRB5_KT_END) + retval = 0; + else { + ktutil_free_kt_list(context, tail); + tail = NULL; + if (back) + back->next = NULL; + } + if (!*list) + *list = tail; + krb5_kt_end_seq_get(context, kt, &cursor); + close_kt: + krb5_kt_close(context, kt); + return retval; +} + +/* + * Takes a kt_list and writes it to the named keytab. + */ +krb5_error_code ktutil_write_keytab(context, list, name) + krb5_context context; + krb5_kt_list list; + char *name; +{ + krb5_kt_list lp; + krb5_keytab kt; + char ktname[MAXPATHLEN+sizeof("WRFILE:")+1]; + krb5_error_code retval = 0; + + strcpy(ktname, "WRFILE:"); + strncat(ktname, name, MAXPATHLEN); + retval = krb5_kt_resolve(context, ktname, &kt); + if (retval) + return retval; + for (lp = list; lp; lp = lp->next) { + retval = krb5_kt_add_entry(context, kt, lp->entry); + if (retval) + break; + } + krb5_kt_close(context, kt); + return retval; +} + +#ifdef KRB5_KRB4_COMPAT +/* + * getst() takes a file pointer, a string and a count. It reads from + * the file until either it has read "count" characters, or until it + * reads a null byte. When finished, what has been read exists in the + * given string "s". If "count" characters were actually read, the + * last is changed to a null, so the returned string is always null- + * terminated. getst() returns the number of characters read, + * including the null terminator. + */ + +int getst(fp, s, n) + FILE *fp; + register char *s; + int n; +{ + register count = n; + while (fread(s, 1, 1, fp) > 0 && --count) + if (*s++ == '\0') + return (n - count); + *s = '\0'; + return (n - count); +} + +/* + * Read in a named krb4 srvtab and append to list. Allocate new list + * if needed. + */ +krb5_error_code ktutil_read_srvtab(context, name, list) + krb5_context context; + char *name; + krb5_kt_list *list; +{ + krb5_kt_list lp = NULL, tail = NULL, back = NULL; + krb5_keytab_entry *entry; + krb5_error_code retval = 0; + char sname[SNAME_SZ]; /* name of service */ + char sinst[INST_SZ]; /* instance of service */ + char srealm[REALM_SZ]; /* realm of service */ + unsigned char kvno; /* key version number */ + des_cblock key; + FILE *fp; + + if (*list) { + /* point lp at the tail of the list */ + for (lp = *list; lp->next; lp = lp->next); + back = lp; + } + fp = fopen(name, "r"); + if (!fp) + return EIO; + for (;;) { + entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry)); + if (!entry) { + retval = ENOMEM; + break; + } + memset((char *)entry, 0, sizeof (*entry)); + memset(sname, 0, sizeof (sname)); + memset(sinst, 0, sizeof (sinst)); + memset(srealm, 0, sizeof (srealm)); + if (!(getst(fp, sname, SNAME_SZ) > 0 && + getst(fp, sinst, INST_SZ) > 0 && + getst(fp, srealm, REALM_SZ) > 0 && + fread(&kvno, 1, 1, fp) > 0 && + fread((char *)key, sizeof (key), 1, fp) > 0)) + break; + entry->magic = KV5M_KEYTAB_ENTRY; + entry->timestamp = 0; /* XXX */ + entry->vno = kvno; + retval = krb5_425_conv_principal(context, + sname, sinst, srealm, + &entry->principal); + if (retval) + break; + entry->key.magic = KV5M_KEYBLOCK; + entry->key.etype = ETYPE_UNKNOWN; + entry->key.keytype = KEYTYPE_DES; + entry->key.length = sizeof (key); + entry->key.contents = (krb5_octet *)malloc(sizeof (key)); + if (!entry->key.contents) { + retval = ENOMEM; + break; + } + memcpy((char *)entry->key.contents, (char *)key, sizeof (key)); + if (!lp) { /* if list is empty, start one */ + lp = (krb5_kt_list)malloc(sizeof (*lp)); + if (!lp) { + retval = ENOMEM; + break; + } + } else { + lp->next = (krb5_kt_list)malloc(sizeof (*lp)); + if (!lp->next) { + retval = ENOMEM; + break; + } + lp = lp->next; + } + lp->next = NULL; + lp->entry = entry; + if (!tail) + tail = lp; + } + if (entry) { + if (entry->magic == KV5M_KEYTAB_ENTRY) + krb5_kt_free_entry(context, entry); + krb5_xfree(entry); + } + if (retval) { + ktutil_free_kt_list(context, tail); + tail = NULL; + if (back) + back->next = NULL; + } + if (!*list) + *list = tail; + fclose(fp); + return retval; +} + +/* + * Writes a kt_list out to a krb4 srvtab file. Note that it first + * prunes the kt_list so that it won't contain any keys that are not + * the most recent, and ignores keys that are not KEYTYPE_DES. + */ +krb5_error_code ktutil_write_srvtab(context, list, name) + krb5_context context; + krb5_kt_list list; + char *name; +{ + krb5_kt_list lp, lp1, prev, pruned = NULL; + krb5_error_code retval = 0; + FILE *fp; + char sname[SNAME_SZ]; + char sinst[INST_SZ]; + char srealm[REALM_SZ]; + + /* First do heinous stuff to prune the list. */ + for (lp = list; lp; lp = lp->next) { + if (lp->entry->key.keytype == KEYTYPE_DES) { /* only DES keys! */ + for (lp1 = pruned; lp1; prev = lp1, lp1 = lp1->next) { + /* Hunt for the current principal in the pruned list */ + if (krb5_principal_compare(context, + lp->entry->principal, + lp1->entry->principal)) + break; + } + if (!lp1) { /* need to add entry to tail of pruned list */ + if (!pruned) { + pruned = (krb5_kt_list) malloc(sizeof (*pruned)); + if (!pruned) + return ENOMEM; + lp1 = pruned; + } else { + prev->next + = (krb5_kt_list) malloc(sizeof (*pruned)); + if (!prev->next) { + retval = ENOMEM; + goto free_pruned; + } + lp1 = prev->next; + } + lp1->entry = lp->entry; + } else if (lp1->entry->vno < lp->entry->vno) + /* Check if lp->entry is newer kvno; if so, update */ + lp1->entry = lp->entry; + } + } + fp = fopen(name, "w"); + if (!fp) { + retval = EIO; + goto free_pruned; + } + for (lp = pruned; lp; lp = lp->next) { + retval = krb5_524_conv_principal(context, + lp->entry->principal, + sname, sinst, srealm); + if (retval) + break; + fwrite(sname, strlen(sname) + 1, 1, fp); + fwrite(sinst, strlen(sinst) + 1, 1, fp); + fwrite(srealm, strlen(srealm) + 1, 1, fp); + fwrite((char *)&lp->entry->vno, 1, 1, fp); + fwrite((char *)lp->entry->key.contents, + sizeof (des_cblock), 1, fp); + } + fclose(fp); + free_pruned: + /* + * Loop over and free the pruned list; don't use free_kt_list + * because that kills the entries. + */ + for (lp = pruned; lp;) { + prev = lp; + lp = lp->next; + krb5_xfree(prev); + } + return retval; +} +#endif /* KRB5_KRB4_COMPAT */ -- 2.26.2