Imported Upstream version 1.15.1
[platform/upstream/krb5.git] / src / lib / krb5 / keytab / ktbase.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/keytab/ktbase.c - Registration functions for keytab */
3 /*
4  * Copyright 1990,2008 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 /*
27  * Copyright 2007 by Secure Endpoints Inc.
28  *
29  * Permission is hereby granted, free of charge, to any person
30  * obtaining a copy of this software and associated documentation files
31  * (the "Software"), to deal in the Software without restriction,
32  * including without limitation the rights to use, copy, modify, merge,
33  * publish, distribute, sublicense, and/or sell copies of the Software,
34  * and to permit persons to whom the Software is furnished to do so,
35  * subject to the following conditions:
36  *
37  * The above copyright notice and this permission notice shall be
38  * included in all copies or substantial portions of the Software.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
41  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
42  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
43  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
44  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
45  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
46  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
47  * SOFTWARE.
48  */
49
50 #include "k5-int.h"
51 #include "k5-thread.h"
52 #include "kt-int.h"
53
54 #ifndef LEAN_CLIENT
55
56 extern const krb5_kt_ops krb5_ktf_ops;
57 extern const krb5_kt_ops krb5_ktf_writable_ops;
58 extern const krb5_kt_ops krb5_kts_ops;
59 extern const krb5_kt_ops krb5_mkt_ops;
60
61 struct krb5_kt_typelist {
62     const krb5_kt_ops *ops;
63     const struct krb5_kt_typelist *next;
64 };
65 const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = {
66     &krb5_kts_ops,
67     NULL
68 };
69 const static struct krb5_kt_typelist krb5_kt_typelist_memory = {
70     &krb5_mkt_ops,
71     &krb5_kt_typelist_srvtab
72 };
73 const static struct krb5_kt_typelist krb5_kt_typelist_wrfile  = {
74     &krb5_ktf_writable_ops,
75     &krb5_kt_typelist_memory
76 };
77 const static struct krb5_kt_typelist krb5_kt_typelist_file  = {
78     &krb5_ktf_ops,
79     &krb5_kt_typelist_wrfile
80 };
81
82 static const struct krb5_kt_typelist *kt_typehead = &krb5_kt_typelist_file;
83 /* Lock for protecting the type list.  */
84 static k5_mutex_t kt_typehead_lock = K5_MUTEX_PARTIAL_INITIALIZER;
85
86 int krb5int_kt_initialize(void)
87 {
88     int err;
89
90     err = k5_mutex_finish_init(&kt_typehead_lock);
91     if (err)
92         goto done;
93     err = krb5int_mkt_initialize();
94     if (err)
95         goto done;
96
97 done:
98     return(err);
99 }
100
101 void
102 krb5int_kt_finalize(void)
103 {
104     const struct krb5_kt_typelist *t, *t_next;
105
106     k5_mutex_destroy(&kt_typehead_lock);
107     for (t = kt_typehead; t != &krb5_kt_typelist_file; t = t_next) {
108         t_next = t->next;
109         free((struct krb5_kt_typelist *)t);
110     }
111
112     krb5int_mkt_finalize();
113 }
114
115
116 /*
117  * Register a new key table type
118  * don't replace if it already exists; return an error instead.
119  */
120
121 krb5_error_code KRB5_CALLCONV
122 krb5_kt_register(krb5_context context, const krb5_kt_ops *ops)
123 {
124     const struct krb5_kt_typelist *t;
125     struct krb5_kt_typelist *newt;
126
127     k5_mutex_lock(&kt_typehead_lock);
128     for (t = kt_typehead; t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
129         ;
130     if (t) {
131         k5_mutex_unlock(&kt_typehead_lock);
132         return KRB5_KT_TYPE_EXISTS;
133     }
134     if (!(newt = (struct krb5_kt_typelist *) malloc(sizeof(*t)))) {
135         k5_mutex_unlock(&kt_typehead_lock);
136         return ENOMEM;
137     }
138     newt->next = kt_typehead;
139     newt->ops = ops;
140     kt_typehead = newt;
141     k5_mutex_unlock(&kt_typehead_lock);
142     return 0;
143 }
144
145 /*
146  * Resolve a key table name into a keytab object.
147  *
148  * The name is currently constrained to be of the form "type:residual";
149  *
150  * The "type" portion corresponds to one of the registered key table
151  * types, while the "residual" portion is specific to the
152  * particular keytab type.
153  */
154
155 #include <ctype.h>
156 krb5_error_code KRB5_CALLCONV
157 krb5_kt_resolve (krb5_context context, const char *name, krb5_keytab *ktid)
158 {
159     const struct krb5_kt_typelist *tlist;
160     char *pfx = NULL;
161     unsigned int pfxlen;
162     const char *cp, *resid;
163     krb5_error_code err = 0;
164     krb5_keytab id;
165
166     *ktid = NULL;
167
168     cp = strchr (name, ':');
169     if (!cp)
170         return (*krb5_kt_dfl_ops.resolve)(context, name, ktid);
171
172     pfxlen = cp - name;
173
174     if ( pfxlen == 1 && isalpha((unsigned char) name[0]) ) {
175         /* We found a drive letter not a prefix - use FILE */
176         pfx = strdup("FILE");
177         if (!pfx)
178             return ENOMEM;
179
180         resid = name;
181     } else if (name[0] == '/') {
182         pfx = strdup("FILE");
183         if (!pfx)
184             return ENOMEM;
185         resid = name;
186     } else {
187         resid = name + pfxlen + 1;
188         pfx = k5memdup0(name, pfxlen, &err);
189         if (pfx == NULL)
190             return err;
191     }
192
193     *ktid = (krb5_keytab) 0;
194
195     k5_mutex_lock(&kt_typehead_lock);
196     tlist = kt_typehead;
197     /* Don't need to hold the lock, since entries are never modified
198        or removed once they're in the list.  Just need to protect
199        access to the list head variable itself.  */
200     k5_mutex_unlock(&kt_typehead_lock);
201     for (; tlist; tlist = tlist->next) {
202         if (strcmp (tlist->ops->prefix, pfx) == 0) {
203             err = (*tlist->ops->resolve)(context, resid, &id);
204             if (!err)
205                 *ktid = id;
206             goto cleanup;
207         }
208     }
209     err = KRB5_KT_UNKNOWN_TYPE;
210
211 cleanup:
212     free(pfx);
213     return err;
214 }
215
216 krb5_error_code KRB5_CALLCONV
217 krb5_kt_dup(krb5_context context, krb5_keytab in, krb5_keytab *out)
218 {
219     krb5_error_code err;
220     char name[BUFSIZ];
221
222     err = in->ops->get_name(context, in, name, sizeof(name));
223     return err ? err : krb5_kt_resolve(context, name, out);
224 }
225
226 /*
227  * Routines to deal with externalizingt krb5_keytab.
228  *      keytab_size();
229  *      keytab_externalize();
230  *      keytab_internalize();
231  */
232 static krb5_error_code keytab_size
233 (krb5_context, krb5_pointer, size_t *);
234 static krb5_error_code keytab_externalize
235 (krb5_context, krb5_pointer, krb5_octet **, size_t *);
236 static krb5_error_code keytab_internalize
237 (krb5_context,krb5_pointer *, krb5_octet **, size_t *);
238
239 /*
240  * Serialization entry for this type.
241  */
242 static const krb5_ser_entry krb5_keytab_ser_entry = {
243     KV5M_KEYTAB,                        /* Type                 */
244     keytab_size,                   /* Sizer routine        */
245     keytab_externalize,            /* Externalize routine  */
246     keytab_internalize             /* Internalize routine  */
247 };
248
249 static krb5_error_code
250 keytab_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
251 {
252     krb5_error_code     kret;
253     krb5_keytab         keytab;
254     krb5_ser_handle     shandle;
255
256     kret = EINVAL;
257     if ((keytab = (krb5_keytab) arg) &&
258         keytab->ops &&
259         (shandle = (krb5_ser_handle) keytab->ops->serializer) &&
260         shandle->sizer)
261         kret = (*shandle->sizer)(kcontext, arg, sizep);
262     return(kret);
263 }
264
265 static krb5_error_code
266 keytab_externalize(krb5_context kcontext, krb5_pointer arg,
267                    krb5_octet **buffer, size_t *lenremain)
268 {
269     krb5_error_code     kret;
270     krb5_keytab         keytab;
271     krb5_ser_handle     shandle;
272
273     kret = EINVAL;
274     if ((keytab = (krb5_keytab) arg) &&
275         keytab->ops &&
276         (shandle = (krb5_ser_handle) keytab->ops->serializer) &&
277         shandle->externalizer)
278         kret = (*shandle->externalizer)(kcontext, arg, buffer, lenremain);
279     return(kret);
280 }
281
282 static krb5_error_code
283 keytab_internalize(krb5_context kcontext, krb5_pointer *argp,
284                    krb5_octet **buffer, size_t *lenremain)
285 {
286     krb5_error_code     kret;
287     krb5_ser_handle     shandle;
288
289     kret = EINVAL;
290     if ((shandle = (krb5_ser_handle) krb5_kt_dfl_ops.serializer) &&
291         shandle->internalizer)
292         kret = (*shandle->internalizer)(kcontext, argp, buffer, lenremain);
293     return(kret);
294 }
295
296 krb5_error_code KRB5_CALLCONV
297 krb5_ser_keytab_init(krb5_context kcontext)
298 {
299     return(krb5_register_serializer(kcontext, &krb5_keytab_ser_entry));
300 }
301 #endif /* LEAN_CLIENT */