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