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_mkt_ops;
59 
60 struct krb5_kt_typelist {
61     const krb5_kt_ops *ops;
62     const struct krb5_kt_typelist *next;
63 };
64 const static struct krb5_kt_typelist krb5_kt_typelist_memory = {
65     &krb5_mkt_ops,
66     NULL
67 };
68 const static struct krb5_kt_typelist krb5_kt_typelist_wrfile  = {
69     &krb5_ktf_writable_ops,
70     &krb5_kt_typelist_memory
71 };
72 const static struct krb5_kt_typelist krb5_kt_typelist_file  = {
73     &krb5_ktf_ops,
74     &krb5_kt_typelist_wrfile
75 };
76 
77 static const struct krb5_kt_typelist *kt_typehead = &krb5_kt_typelist_file;
78 /* Lock for protecting the type list.  */
79 static k5_mutex_t kt_typehead_lock = K5_MUTEX_PARTIAL_INITIALIZER;
80 
krb5int_kt_initialize(void)81 int krb5int_kt_initialize(void)
82 {
83     int err;
84 
85     err = k5_mutex_finish_init(&kt_typehead_lock);
86     if (err)
87         goto done;
88     err = krb5int_mkt_initialize();
89     if (err)
90         goto done;
91 
92 done:
93     return(err);
94 }
95 
96 void
krb5int_kt_finalize(void)97 krb5int_kt_finalize(void)
98 {
99     const struct krb5_kt_typelist *t, *t_next;
100 
101     k5_mutex_destroy(&kt_typehead_lock);
102     for (t = kt_typehead; t != &krb5_kt_typelist_file; t = t_next) {
103         t_next = t->next;
104         free((struct krb5_kt_typelist *)t);
105     }
106 
107     krb5int_mkt_finalize();
108 }
109 
110 
111 /*
112  * Register a new key table type
113  * don't replace if it already exists; return an error instead.
114  */
115 
116 krb5_error_code KRB5_CALLCONV
krb5_kt_register(krb5_context context,const krb5_kt_ops * ops)117 krb5_kt_register(krb5_context context, const krb5_kt_ops *ops)
118 {
119     const struct krb5_kt_typelist *t;
120     struct krb5_kt_typelist *newt;
121 
122     k5_mutex_lock(&kt_typehead_lock);
123     for (t = kt_typehead; t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
124         ;
125     if (t) {
126         k5_mutex_unlock(&kt_typehead_lock);
127         return KRB5_KT_TYPE_EXISTS;
128     }
129     if (!(newt = (struct krb5_kt_typelist *) malloc(sizeof(*t)))) {
130         k5_mutex_unlock(&kt_typehead_lock);
131         return ENOMEM;
132     }
133     newt->next = kt_typehead;
134     newt->ops = ops;
135     kt_typehead = newt;
136     k5_mutex_unlock(&kt_typehead_lock);
137     return 0;
138 }
139 
140 /*
141  * Resolve a key table name into a keytab object.
142  *
143  * The name is currently constrained to be of the form "type:residual";
144  *
145  * The "type" portion corresponds to one of the registered key table
146  * types, while the "residual" portion is specific to the
147  * particular keytab type.
148  */
149 
150 #include <ctype.h>
151 krb5_error_code KRB5_CALLCONV
krb5_kt_resolve(krb5_context context,const char * name,krb5_keytab * ktid)152 krb5_kt_resolve (krb5_context context, const char *name, krb5_keytab *ktid)
153 {
154     const struct krb5_kt_typelist *tlist;
155     char *pfx = NULL;
156     unsigned int pfxlen;
157     const char *cp, *resid;
158     krb5_error_code err = 0;
159     krb5_keytab id;
160 
161     *ktid = NULL;
162 
163     cp = strchr (name, ':');
164     if (!cp)
165         return (*krb5_kt_dfl_ops.resolve)(context, name, ktid);
166 
167     pfxlen = cp - name;
168 
169     if ( pfxlen == 1 && isalpha((unsigned char) name[0]) ) {
170         /* We found a drive letter not a prefix - use FILE */
171         pfx = strdup("FILE");
172         if (!pfx)
173             return ENOMEM;
174 
175         resid = name;
176     } else if (name[0] == '/') {
177         pfx = strdup("FILE");
178         if (!pfx)
179             return ENOMEM;
180         resid = name;
181     } else {
182         resid = name + pfxlen + 1;
183         pfx = k5memdup0(name, pfxlen, &err);
184         if (pfx == NULL)
185             return err;
186     }
187 
188     *ktid = (krb5_keytab) 0;
189 
190     k5_mutex_lock(&kt_typehead_lock);
191     tlist = kt_typehead;
192     /* Don't need to hold the lock, since entries are never modified
193        or removed once they're in the list.  Just need to protect
194        access to the list head variable itself.  */
195     k5_mutex_unlock(&kt_typehead_lock);
196     for (; tlist; tlist = tlist->next) {
197         if (strcmp (tlist->ops->prefix, pfx) == 0) {
198             err = (*tlist->ops->resolve)(context, resid, &id);
199             if (!err)
200                 *ktid = id;
201             goto cleanup;
202         }
203     }
204     err = KRB5_KT_UNKNOWN_TYPE;
205 
206 cleanup:
207     free(pfx);
208     return err;
209 }
210 
211 krb5_error_code KRB5_CALLCONV
krb5_kt_dup(krb5_context context,krb5_keytab in,krb5_keytab * out)212 krb5_kt_dup(krb5_context context, krb5_keytab in, krb5_keytab *out)
213 {
214     krb5_error_code err;
215     char name[BUFSIZ];
216 
217     err = in->ops->get_name(context, in, name, sizeof(name));
218     return err ? err : krb5_kt_resolve(context, name, out);
219 }
220 
221 #endif /* LEAN_CLIENT */
222