1/* 2 * Copyright (c) 1997-2004 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 "ktutil_locl.h" 35 36RCSID("$Id$"); 37 38 39static krb5_boolean 40compare_keyblock(const krb5_keyblock *a, const krb5_keyblock *b) 41{ 42 if(a->keytype != b->keytype || 43 a->keyvalue.length != b->keyvalue.length || 44 memcmp(a->keyvalue.data, b->keyvalue.data, a->keyvalue.length) != 0) 45 return FALSE; 46 return TRUE; 47} 48 49int 50kt_copy (struct copy_options *opt, int argc, char **argv) 51{ 52 krb5_keytab src_keytab = NULL, dst_keytab = NULL; 53 krb5_principal match_principal = NULL; 54 krb5_keytab_entry entry, dummy; 55 const char *from = argv[0]; 56 const char *to = argv[1]; 57 krb5_kt_cursor cursor; 58 krb5_error_code ret; 59 60 ret = krb5_kt_resolve (context, from, &src_keytab); 61 if (ret) { 62 krb5_warn (context, ret, "resolving src keytab `%s'", from); 63 goto out; 64 } 65 66 ret = krb5_kt_resolve (context, to, &dst_keytab); 67 if (ret) { 68 krb5_warn (context, ret, "resolving dst keytab `%s'", to); 69 goto out; 70 } 71 72 if (opt->match_principal_string) { 73 ret = krb5_parse_name(context, 74 opt->match_principal_string, 75 &match_principal); 76 if (ret) { 77 krb5_warn (context, ret, "failed parsing match principal `%s'", 78 opt->match_principal_string); 79 goto out; 80 } 81 if (verbose_flag) { 82 char *str = NULL; 83 ret = krb5_unparse_name(context, match_principal, &str); 84 if (ret == 0) { 85 fprintf(stderr, "matching on principal %s\n", str); 86 krb5_xfree(str); 87 } 88 } 89 } 90 91 ret = krb5_kt_start_seq_get (context, src_keytab, &cursor); 92 if (ret) { 93 krb5_warn (context, ret, "krb5_kt_start_seq_get %s", keytab_string); 94 goto out; 95 } 96 97 if (verbose_flag) 98 fprintf(stderr, "copying %s to %s\n", from, to); 99 100 while((ret = krb5_kt_next_entry(context, src_keytab, 101 &entry, &cursor)) == 0) { 102 char *name_str; 103 char *etype_str; 104 ret = krb5_unparse_name (context, entry.principal, &name_str); 105 if(ret) { 106 krb5_warn(context, ret, "krb5_unparse_name"); 107 name_str = NULL; /* XXX */ 108 } 109 ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str); 110 if(ret) { 111 krb5_warn(context, ret, "krb5_enctype_to_string"); 112 etype_str = NULL; /* XXX */ 113 } 114 115 if (match_principal && 116 !krb5_principal_match(context, entry.principal, match_principal)) 117 { 118 if (verbose_flag) { 119 krb5_warnx(context, "skipping %s, keytype %s, kvno %d", 120 name_str, etype_str, entry.vno); 121 } 122 free(name_str); 123 free(etype_str); 124 continue; 125 } 126 127 ret = krb5_kt_get_entry(context, dst_keytab, 128 entry.principal, 129 entry.vno, 130 entry.keyblock.keytype, 131 &dummy); 132 if(ret == 0) { 133 /* this entry is already in the new keytab, so no need to 134 copy it; if the keyblocks are not the same, something 135 is weird, so complain about that */ 136 if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) { 137 krb5_warnx(context, "entry with different keyvalue " 138 "already exists for %s, keytype %s, kvno %d", 139 name_str, etype_str, entry.vno); 140 } 141 krb5_kt_free_entry(context, &dummy); 142 krb5_kt_free_entry (context, &entry); 143 free(name_str); 144 free(etype_str); 145 continue; 146 } else if(ret != KRB5_KT_NOTFOUND) { 147 krb5_warn (context, ret, "%s: fetching %s/%s/%u", 148 to, name_str, etype_str, entry.vno); 149 krb5_kt_free_entry (context, &entry); 150 free(name_str); 151 free(etype_str); 152 break; 153 } 154 if (verbose_flag) 155 fprintf (stderr, "copying %s, keytype %s, kvno %d\n", name_str, 156 etype_str, entry.vno); 157 ret = krb5_kt_add_entry (context, dst_keytab, &entry); 158 krb5_kt_free_entry (context, &entry); 159 if (ret) { 160 krb5_warn (context, ret, "%s: adding %s/%s/%u", 161 to, name_str, etype_str, entry.vno); 162 free(name_str); 163 free(etype_str); 164 break; 165 } 166 free(name_str); 167 free(etype_str); 168 } 169 krb5_kt_end_seq_get (context, src_keytab, &cursor); 170 171 out: 172 if (match_principal) 173 krb5_free_principal(context, match_principal); 174 if (src_keytab) 175 krb5_kt_close (context, src_keytab); 176 if (dst_keytab) 177 krb5_kt_close (context, dst_keytab); 178 return ret != 0; 179} 180