1/*	$NetBSD: copy.c,v 1.2 2017/01/28 21:31:44 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997-2004 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "ktutil_locl.h"
37
38__RCSID("$NetBSD: copy.c,v 1.2 2017/01/28 21:31:44 christos Exp $");
39
40
41static krb5_boolean
42compare_keyblock(const krb5_keyblock *a, const krb5_keyblock *b)
43{
44    if(a->keytype != b->keytype ||
45       a->keyvalue.length != b->keyvalue.length ||
46       memcmp(a->keyvalue.data, b->keyvalue.data, a->keyvalue.length) != 0)
47	return FALSE;
48    return TRUE;
49}
50
51int
52kt_copy (void *opt, int argc, char **argv)
53{
54    krb5_error_code ret;
55    krb5_keytab src_keytab, dst_keytab;
56    krb5_kt_cursor cursor;
57    krb5_keytab_entry entry, dummy;
58    const char *from = argv[0];
59    const char *to = argv[1];
60
61    ret = krb5_kt_resolve (context, from, &src_keytab);
62    if (ret) {
63	krb5_warn (context, ret, "resolving src keytab `%s'", from);
64	return 1;
65    }
66
67    ret = krb5_kt_resolve (context, to, &dst_keytab);
68    if (ret) {
69	krb5_kt_close (context, src_keytab);
70	krb5_warn (context, ret, "resolving dst keytab `%s'", to);
71	return 1;
72    }
73
74    ret = krb5_kt_start_seq_get (context, src_keytab, &cursor);
75    if (ret) {
76	krb5_warn (context, ret, "krb5_kt_start_seq_get %s", keytab_string);
77	goto out;
78    }
79
80    if (verbose_flag)
81	fprintf(stderr, "copying %s to %s\n", from, to);
82
83    while((ret = krb5_kt_next_entry(context, src_keytab,
84				    &entry, &cursor)) == 0) {
85	char *name_str;
86	char *etype_str;
87	ret = krb5_unparse_name (context, entry.principal, &name_str);
88	if(ret) {
89	    krb5_warn(context, ret, "krb5_unparse_name");
90	    name_str = NULL; /* XXX */
91	}
92	ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str);
93	if(ret) {
94	    krb5_warn(context, ret, "krb5_enctype_to_string");
95	    etype_str = NULL; /* XXX */
96	}
97	ret = krb5_kt_get_entry(context, dst_keytab,
98				entry.principal,
99				entry.vno,
100				entry.keyblock.keytype,
101				&dummy);
102	if(ret == 0) {
103	    /* this entry is already in the new keytab, so no need to
104               copy it; if the keyblocks are not the same, something
105               is weird, so complain about that */
106	    if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) {
107		krb5_warnx(context, "entry with different keyvalue "
108			   "already exists for %s, keytype %s, kvno %d",
109			   name_str, etype_str, entry.vno);
110	    }
111	    krb5_kt_free_entry(context, &dummy);
112	    krb5_kt_free_entry (context, &entry);
113	    free(name_str);
114	    free(etype_str);
115	    continue;
116	} else if(ret != KRB5_KT_NOTFOUND) {
117	    krb5_warn (context, ret, "%s: fetching %s/%s/%u",
118		       to, name_str, etype_str, entry.vno);
119	    krb5_kt_free_entry (context, &entry);
120	    free(name_str);
121	    free(etype_str);
122	    break;
123	}
124	if (verbose_flag)
125	    fprintf (stderr, "copying %s, keytype %s, kvno %d\n", name_str,
126		     etype_str, entry.vno);
127	ret = krb5_kt_add_entry (context, dst_keytab, &entry);
128	krb5_kt_free_entry (context, &entry);
129	if (ret) {
130	    krb5_warn (context, ret, "%s: adding %s/%s/%u",
131		       to, name_str, etype_str, entry.vno);
132	    free(name_str);
133	    free(etype_str);
134	    break;
135	}
136	free(name_str);
137	free(etype_str);
138    }
139    krb5_kt_end_seq_get (context, src_keytab, &cursor);
140
141  out:
142    krb5_kt_close (context, src_keytab);
143    krb5_kt_close (context, dst_keytab);
144    return ret != 0;
145}
146