keytab_copy: Fix style, whitespaces
[idra/samba.git] / source4 / auth / kerberos / keytab_copy.c
1 /*
2  * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * Copyright (c) 2011 Andrew Bartlett
5  *
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 "includes.h"
37 #include "system/kerberos.h"
38 #include "auth/kerberos/kerberos.h"
39
40 static krb5_boolean
41 compare_keyblock(const krb5_keyblock *a, const krb5_keyblock *b)
42 {
43     if(a->keytype != b->keytype ||
44        a->keyvalue.length != b->keyvalue.length ||
45        memcmp(a->keyvalue.data, b->keyvalue.data, a->keyvalue.length) != 0)
46         return FALSE;
47     return TRUE;
48 }
49
50 static krb5_error_code copy_one_entry(krb5_context context,
51                                       krb5_keytab src_keytab,
52                                       krb5_keytab dst_keytab,
53                                       krb5_keytab_entry entry)
54 {
55     krb5_error_code ret;
56     krb5_keytab_entry dummy;
57
58     char *name_str;
59     char *etype_str;
60     ret = krb5_unparse_name (context, entry.principal, &name_str);
61     if(ret) {
62         krb5_set_error_message(context, ret, "krb5_unparse_name");
63         name_str = NULL; /* XXX */
64         return ret;
65     }
66     ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &etype_str);
67     if(ret) {
68         krb5_set_error_message(context, ret, "krb5_enctype_to_string");
69         etype_str = NULL; /* XXX */
70         return ret;
71     }
72     ret = krb5_kt_get_entry(context, dst_keytab,
73                             entry.principal,
74                             entry.vno,
75                             entry.keyblock.keytype,
76                             &dummy);
77     if(ret == 0) {
78         /* this entry is already in the new keytab, so no need to
79            copy it; if the keyblocks are not the same, something
80            is weird, so complain about that */
81         if(!compare_keyblock(&entry.keyblock, &dummy.keyblock)) {
82                 krb5_warn(context, 0, "entry with different keyvalue "
83                           "already exists for %s, keytype %s, kvno %d",
84                           name_str, etype_str, entry.vno);
85         }
86         krb5_kt_free_entry(context, &dummy);
87         krb5_kt_free_entry (context, &entry);
88         free(name_str);
89         free(etype_str);
90         return ret;
91     } else if(ret != KRB5_KT_NOTFOUND) {
92         krb5_set_error_message (context, ret, "fetching %s/%s/%u",
93                                 name_str, etype_str, entry.vno);
94         krb5_kt_free_entry (context, &entry);
95         free(name_str);
96         free(etype_str);
97         return ret;
98     }
99     ret = krb5_kt_add_entry (context, dst_keytab, &entry);
100     krb5_kt_free_entry (context, &entry);
101     if (ret) {
102         krb5_set_error_message (context, ret, "adding %s/%s/%u",
103                                 name_str, etype_str, entry.vno);
104         free(name_str);
105         free(etype_str);
106         return ret;
107     }
108     free(name_str);
109     free(etype_str);
110     return ret;
111 }
112
113 krb5_error_code kt_copy(krb5_context context, const char *from, const char *to)
114 {
115     krb5_error_code ret;
116     krb5_keytab src_keytab, dst_keytab;
117     krb5_kt_cursor cursor;
118     krb5_keytab_entry entry;
119
120     ret = krb5_kt_resolve (context, from, &src_keytab);
121     if (ret) {
122         krb5_set_error_message (context, ret, "resolving src keytab `%s'", from);
123         return ret;
124     }
125
126     ret = krb5_kt_resolve (context, to, &dst_keytab);
127     if (ret) {
128         krb5_kt_close (context, src_keytab);
129         krb5_set_error_message (context, ret, "resolving dst keytab `%s'", to);
130         return ret;
131     }
132
133     ret = krb5_kt_start_seq_get (context, src_keytab, &cursor);
134     if (ret) {
135         krb5_set_error_message (context, ret, "krb5_kt_start_seq_get %s", from);
136         goto out;
137     }
138
139     while((ret = krb5_kt_next_entry(context, src_keytab,
140                                     &entry, &cursor)) == 0) {
141         ret = copy_one_entry(context, src_keytab, dst_keytab, entry);
142         if (ret) {
143             break;
144         }
145     }
146     krb5_kt_end_seq_get (context, src_keytab, &cursor);
147
148   out:
149     krb5_kt_close (context, src_keytab);
150     krb5_kt_close (context, dst_keytab);
151     if (ret == KRB5_KT_END) {
152         return 0;
153     } else if (ret == 0) {
154         return EINVAL;
155     }
156     return ret;
157 }
158
159 krb5_error_code kt_copy_one_principal(krb5_context context,
160                                       const char *from,
161                                       const char *to,
162                                       const char *principal,
163                                       krb5_kvno kvno,
164                                       krb5_enctype *enctypes)
165 {
166     krb5_error_code ret;
167     krb5_keytab src_keytab, dst_keytab;
168     krb5_keytab_entry entry;
169     krb5_principal princ;
170     int i;
171     bool found_one = false;
172
173     ret = krb5_parse_name (context, principal, &princ);
174     if(ret) {
175             krb5_set_error_message(context, ret, "krb5_unparse_name");
176             return ret;
177     }
178
179     ret = krb5_kt_resolve (context, from, &src_keytab);
180     if (ret) {
181         krb5_set_error_message(context, ret, "resolving src keytab `%s'", from);
182         return ret;
183     }
184
185     ret = krb5_kt_resolve (context, to, &dst_keytab);
186     if (ret) {
187         krb5_kt_close (context, src_keytab);
188         krb5_set_error_message(context, ret, "resolving dst keytab `%s'", to);
189         return ret;
190     }
191
192     for (i=0; enctypes[i]; i++) {
193         ret = krb5_kt_get_entry(context, src_keytab,
194                                 princ,
195                                 kvno,
196                                 enctypes[i],
197                                 &entry);
198         if (ret == KRB5_KT_NOTFOUND) {
199             continue;
200         } else if (ret) {
201             break;
202         }
203         found_one = true;
204         ret = copy_one_entry(context, src_keytab, dst_keytab, entry);
205         if (ret) {
206             break;
207         }
208     }
209     if (ret == KRB5_KT_NOTFOUND) {
210         if (!found_one) {
211             char *princ_string;
212             int ret2 = krb5_unparse_name (context, princ, &princ_string);
213             if (ret2) {
214                 krb5_set_error_message(context, ret,
215                                         "failed to fetch principal %s",
216                                         princ_string);
217             }
218         } else {
219             /* Not finding an enc type is not an error,
220              * as long as we copied one for the principal */
221             ret = 0;
222         }
223     }
224
225     krb5_kt_close (context, src_keytab);
226     krb5_kt_close (context, dst_keytab);
227     return ret;
228 }