xref: /minix3/crypto/external/bsd/heimdal/dist/lib/krb5/keytab_memory.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
1 /*	$NetBSD: keytab_memory.c,v 1.1.1.1 2011/04/13 18:15:34 elric Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 2001 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 /* memory operations -------------------------------------------- */
39 
40 struct mkt_data {
41     krb5_keytab_entry *entries;
42     int num_entries;
43     char *name;
44     int refcount;
45     struct mkt_data *next;
46 };
47 
48 /* this mutex protects mkt_head, ->refcount, and ->next
49  * content is not protected (name is static and need no protection)
50  */
51 static HEIMDAL_MUTEX mkt_mutex = HEIMDAL_MUTEX_INITIALIZER;
52 static struct mkt_data *mkt_head;
53 
54 
55 static krb5_error_code KRB5_CALLCONV
mkt_resolve(krb5_context context,const char * name,krb5_keytab id)56 mkt_resolve(krb5_context context, const char *name, krb5_keytab id)
57 {
58     struct mkt_data *d;
59 
60     HEIMDAL_MUTEX_lock(&mkt_mutex);
61 
62     for (d = mkt_head; d != NULL; d = d->next)
63 	if (strcmp(d->name, name) == 0)
64 	    break;
65     if (d) {
66 	if (d->refcount < 1)
67 	    krb5_abortx(context, "Double close on memory keytab, "
68 			"refcount < 1 %d", d->refcount);
69 	d->refcount++;
70 	id->data = d;
71 	HEIMDAL_MUTEX_unlock(&mkt_mutex);
72 	return 0;
73     }
74 
75     d = calloc(1, sizeof(*d));
76     if(d == NULL) {
77 	HEIMDAL_MUTEX_unlock(&mkt_mutex);
78 	krb5_set_error_message(context, ENOMEM,
79 			       N_("malloc: out of memory", ""));
80 	return ENOMEM;
81     }
82     d->name = strdup(name);
83     if (d->name == NULL) {
84 	HEIMDAL_MUTEX_unlock(&mkt_mutex);
85 	free(d);
86 	krb5_set_error_message(context, ENOMEM,
87 			       N_("malloc: out of memory", ""));
88 	return ENOMEM;
89     }
90     d->entries = NULL;
91     d->num_entries = 0;
92     d->refcount = 1;
93     d->next = mkt_head;
94     mkt_head = d;
95     HEIMDAL_MUTEX_unlock(&mkt_mutex);
96     id->data = d;
97     return 0;
98 }
99 
100 static krb5_error_code KRB5_CALLCONV
mkt_close(krb5_context context,krb5_keytab id)101 mkt_close(krb5_context context, krb5_keytab id)
102 {
103     struct mkt_data *d = id->data, **dp;
104     int i;
105 
106     HEIMDAL_MUTEX_lock(&mkt_mutex);
107     if (d->refcount < 1)
108 	krb5_abortx(context,
109 		    "krb5 internal error, memory keytab refcount < 1 on close");
110 
111     if (--d->refcount > 0) {
112 	HEIMDAL_MUTEX_unlock(&mkt_mutex);
113 	return 0;
114     }
115     for (dp = &mkt_head; *dp != NULL; dp = &(*dp)->next) {
116 	if (*dp == d) {
117 	    *dp = d->next;
118 	    break;
119 	}
120     }
121     HEIMDAL_MUTEX_unlock(&mkt_mutex);
122 
123     free(d->name);
124     for(i = 0; i < d->num_entries; i++)
125 	krb5_kt_free_entry(context, &d->entries[i]);
126     free(d->entries);
127     free(d);
128     return 0;
129 }
130 
131 static krb5_error_code KRB5_CALLCONV
mkt_get_name(krb5_context context,krb5_keytab id,char * name,size_t namesize)132 mkt_get_name(krb5_context context,
133 	     krb5_keytab id,
134 	     char *name,
135 	     size_t namesize)
136 {
137     struct mkt_data *d = id->data;
138     strlcpy(name, d->name, namesize);
139     return 0;
140 }
141 
142 static krb5_error_code KRB5_CALLCONV
mkt_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * c)143 mkt_start_seq_get(krb5_context context,
144 		  krb5_keytab id,
145 		  krb5_kt_cursor *c)
146 {
147     /* XXX */
148     c->fd = 0;
149     return 0;
150 }
151 
152 static krb5_error_code KRB5_CALLCONV
mkt_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * c)153 mkt_next_entry(krb5_context context,
154 	       krb5_keytab id,
155 	       krb5_keytab_entry *entry,
156 	       krb5_kt_cursor *c)
157 {
158     struct mkt_data *d = id->data;
159     if(c->fd >= d->num_entries)
160 	return KRB5_KT_END;
161     return krb5_kt_copy_entry_contents(context, &d->entries[c->fd++], entry);
162 }
163 
164 static krb5_error_code KRB5_CALLCONV
mkt_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)165 mkt_end_seq_get(krb5_context context,
166 		krb5_keytab id,
167 		krb5_kt_cursor *cursor)
168 {
169     return 0;
170 }
171 
172 static krb5_error_code KRB5_CALLCONV
mkt_add_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)173 mkt_add_entry(krb5_context context,
174 	      krb5_keytab id,
175 	      krb5_keytab_entry *entry)
176 {
177     struct mkt_data *d = id->data;
178     krb5_keytab_entry *tmp;
179     tmp = realloc(d->entries, (d->num_entries + 1) * sizeof(*d->entries));
180     if(tmp == NULL) {
181 	krb5_set_error_message(context, ENOMEM,
182 			       N_("malloc: out of memory", ""));
183 	return ENOMEM;
184     }
185     d->entries = tmp;
186     return krb5_kt_copy_entry_contents(context, entry,
187 				       &d->entries[d->num_entries++]);
188 }
189 
190 static krb5_error_code KRB5_CALLCONV
mkt_remove_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)191 mkt_remove_entry(krb5_context context,
192 		 krb5_keytab id,
193 		 krb5_keytab_entry *entry)
194 {
195     struct mkt_data *d = id->data;
196     krb5_keytab_entry *e, *end;
197     int found = 0;
198 
199     if (d->num_entries == 0) {
200 	krb5_clear_error_message(context);
201         return KRB5_KT_NOTFOUND;
202     }
203 
204     /* do this backwards to minimize copying */
205     for(end = d->entries + d->num_entries, e = end - 1; e >= d->entries; e--) {
206 	if(krb5_kt_compare(context, e, entry->principal,
207 			   entry->vno, entry->keyblock.keytype)) {
208 	    krb5_kt_free_entry(context, e);
209 	    memmove(e, e + 1, (end - e - 1) * sizeof(*e));
210 	    memset(end - 1, 0, sizeof(*end));
211 	    d->num_entries--;
212 	    end--;
213 	    found = 1;
214 	}
215     }
216     if (!found) {
217 	krb5_clear_error_message (context);
218 	return KRB5_KT_NOTFOUND;
219     }
220     e = realloc(d->entries, d->num_entries * sizeof(*d->entries));
221     if(e != NULL || d->num_entries == 0)
222 	d->entries = e;
223     return 0;
224 }
225 
226 const krb5_kt_ops krb5_mkt_ops = {
227     "MEMORY",
228     mkt_resolve,
229     mkt_get_name,
230     mkt_close,
231     NULL, /* destroy */
232     NULL, /* get */
233     mkt_start_seq_get,
234     mkt_next_entry,
235     mkt_end_seq_get,
236     mkt_add_entry,
237     mkt_remove_entry
238 };
239