1 /* $NetBSD: keytab_any.c,v 1.1.1.1 2011/04/13 18:15:34 elric Exp $ */
2
3 /*
4 * Copyright (c) 2001-2002 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
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 "krb5_locl.h"
37
38 struct any_data {
39 krb5_keytab kt;
40 char *name;
41 struct any_data *next;
42 };
43
44 static void
free_list(krb5_context context,struct any_data * a)45 free_list (krb5_context context, struct any_data *a)
46 {
47 struct any_data *next;
48
49 for (; a != NULL; a = next) {
50 next = a->next;
51 free (a->name);
52 if(a->kt)
53 krb5_kt_close(context, a->kt);
54 free (a);
55 }
56 }
57
58 static krb5_error_code KRB5_CALLCONV
any_resolve(krb5_context context,const char * name,krb5_keytab id)59 any_resolve(krb5_context context, const char *name, krb5_keytab id)
60 {
61 struct any_data *a, *a0 = NULL, *prev = NULL;
62 krb5_error_code ret;
63 char buf[256];
64
65 while (strsep_copy(&name, ",", buf, sizeof(buf)) != -1) {
66 a = calloc(1, sizeof(*a));
67 if (a == NULL) {
68 ret = ENOMEM;
69 goto fail;
70 }
71 if (a0 == NULL) {
72 a0 = a;
73 a->name = strdup(buf);
74 if (a->name == NULL) {
75 ret = ENOMEM;
76 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
77 goto fail;
78 }
79 } else
80 a->name = NULL;
81 if (prev != NULL)
82 prev->next = a;
83 a->next = NULL;
84 ret = krb5_kt_resolve (context, buf, &a->kt);
85 if (ret)
86 goto fail;
87 prev = a;
88 }
89 if (a0 == NULL) {
90 krb5_set_error_message(context, ENOENT, N_("empty ANY: keytab", ""));
91 return ENOENT;
92 }
93 id->data = a0;
94 return 0;
95 fail:
96 free_list (context, a0);
97 return ret;
98 }
99
100 static krb5_error_code KRB5_CALLCONV
any_get_name(krb5_context context,krb5_keytab id,char * name,size_t namesize)101 any_get_name (krb5_context context,
102 krb5_keytab id,
103 char *name,
104 size_t namesize)
105 {
106 struct any_data *a = id->data;
107 strlcpy(name, a->name, namesize);
108 return 0;
109 }
110
111 static krb5_error_code KRB5_CALLCONV
any_close(krb5_context context,krb5_keytab id)112 any_close (krb5_context context,
113 krb5_keytab id)
114 {
115 struct any_data *a = id->data;
116
117 free_list (context, a);
118 return 0;
119 }
120
121 struct any_cursor_extra_data {
122 struct any_data *a;
123 krb5_kt_cursor cursor;
124 };
125
126 static krb5_error_code KRB5_CALLCONV
any_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * c)127 any_start_seq_get(krb5_context context,
128 krb5_keytab id,
129 krb5_kt_cursor *c)
130 {
131 struct any_data *a = id->data;
132 struct any_cursor_extra_data *ed;
133 krb5_error_code ret;
134
135 c->data = malloc (sizeof(struct any_cursor_extra_data));
136 if(c->data == NULL){
137 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
138 return ENOMEM;
139 }
140 ed = (struct any_cursor_extra_data *)c->data;
141 for (ed->a = a; ed->a != NULL; ed->a = ed->a->next) {
142 ret = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
143 if (ret == 0)
144 break;
145 }
146 if (ed->a == NULL) {
147 free (c->data);
148 c->data = NULL;
149 krb5_clear_error_message (context);
150 return KRB5_KT_END;
151 }
152 return 0;
153 }
154
155 static krb5_error_code KRB5_CALLCONV
any_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor)156 any_next_entry (krb5_context context,
157 krb5_keytab id,
158 krb5_keytab_entry *entry,
159 krb5_kt_cursor *cursor)
160 {
161 krb5_error_code ret, ret2;
162 struct any_cursor_extra_data *ed;
163
164 ed = (struct any_cursor_extra_data *)cursor->data;
165 do {
166 ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor);
167 if (ret == 0)
168 return 0;
169 else if (ret != KRB5_KT_END)
170 return ret;
171
172 ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor);
173 if (ret2)
174 return ret2;
175 while ((ed->a = ed->a->next) != NULL) {
176 ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
177 if (ret2 == 0)
178 break;
179 }
180 if (ed->a == NULL) {
181 krb5_clear_error_message (context);
182 return KRB5_KT_END;
183 }
184 } while (1);
185 }
186
187 static krb5_error_code KRB5_CALLCONV
any_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)188 any_end_seq_get(krb5_context context,
189 krb5_keytab id,
190 krb5_kt_cursor *cursor)
191 {
192 krb5_error_code ret = 0;
193 struct any_cursor_extra_data *ed;
194
195 ed = (struct any_cursor_extra_data *)cursor->data;
196 if (ed->a != NULL)
197 ret = krb5_kt_end_seq_get(context, ed->a->kt, &ed->cursor);
198 free (ed);
199 cursor->data = NULL;
200 return ret;
201 }
202
203 static krb5_error_code KRB5_CALLCONV
any_add_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)204 any_add_entry(krb5_context context,
205 krb5_keytab id,
206 krb5_keytab_entry *entry)
207 {
208 struct any_data *a = id->data;
209 krb5_error_code ret;
210 while(a != NULL) {
211 ret = krb5_kt_add_entry(context, a->kt, entry);
212 if(ret != 0 && ret != KRB5_KT_NOWRITE) {
213 krb5_set_error_message(context, ret,
214 N_("failed to add entry to %s", ""),
215 a->name);
216 return ret;
217 }
218 a = a->next;
219 }
220 return 0;
221 }
222
223 static krb5_error_code KRB5_CALLCONV
any_remove_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)224 any_remove_entry(krb5_context context,
225 krb5_keytab id,
226 krb5_keytab_entry *entry)
227 {
228 struct any_data *a = id->data;
229 krb5_error_code ret;
230 int found = 0;
231 while(a != NULL) {
232 ret = krb5_kt_remove_entry(context, a->kt, entry);
233 if(ret == 0)
234 found++;
235 else {
236 if(ret != KRB5_KT_NOWRITE && ret != KRB5_KT_NOTFOUND) {
237 krb5_set_error_message(context, ret,
238 N_("Failed to remove keytab "
239 "entry from %s", "keytab name"),
240 a->name);
241 return ret;
242 }
243 }
244 a = a->next;
245 }
246 if(!found)
247 return KRB5_KT_NOTFOUND;
248 return 0;
249 }
250
251 const krb5_kt_ops krb5_any_ops = {
252 "ANY",
253 any_resolve,
254 any_get_name,
255 any_close,
256 NULL, /* destroy */
257 NULL, /* get */
258 any_start_seq_get,
259 any_next_entry,
260 any_end_seq_get,
261 any_add_entry,
262 any_remove_entry
263 };
264