/ admin / copy.c
copy.c
  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  
 36  RCSID("$Id$");
 37  
 38  
 39  static krb5_boolean
 40  compare_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  
 49  int
 50  kt_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  }