1 /*	$NetBSD: keytab_memory.c,v 1.2 2017/01/28 21:31:49 christos 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 	return krb5_enomem(context);
79     }
80     d->name = strdup(name);
81     if (d->name == NULL) {
82 	HEIMDAL_MUTEX_unlock(&mkt_mutex);
83 	free(d);
84 	return krb5_enomem(context);
85     }
86     d->entries = NULL;
87     d->num_entries = 0;
88     d->refcount = 1;
89     d->next = mkt_head;
90     mkt_head = d;
91     HEIMDAL_MUTEX_unlock(&mkt_mutex);
92     id->data = d;
93     return 0;
94 }
95 
96 static krb5_error_code KRB5_CALLCONV
mkt_close(krb5_context context,krb5_keytab id)97 mkt_close(krb5_context context, krb5_keytab id)
98 {
99     struct mkt_data *d = id->data, **dp;
100     int i;
101 
102     HEIMDAL_MUTEX_lock(&mkt_mutex);
103     if (d->refcount < 1)
104 	krb5_abortx(context,
105 		    "krb5 internal error, memory keytab refcount < 1 on close");
106 
107     if (--d->refcount > 0) {
108 	HEIMDAL_MUTEX_unlock(&mkt_mutex);
109 	return 0;
110     }
111     for (dp = &mkt_head; *dp != NULL; dp = &(*dp)->next) {
112 	if (*dp == d) {
113 	    *dp = d->next;
114 	    break;
115 	}
116     }
117     HEIMDAL_MUTEX_unlock(&mkt_mutex);
118 
119     free(d->name);
120     for(i = 0; i < d->num_entries; i++)
121 	krb5_kt_free_entry(context, &d->entries[i]);
122     free(d->entries);
123     free(d);
124     return 0;
125 }
126 
127 static krb5_error_code KRB5_CALLCONV
mkt_get_name(krb5_context context,krb5_keytab id,char * name,size_t namesize)128 mkt_get_name(krb5_context context,
129 	     krb5_keytab id,
130 	     char *name,
131 	     size_t namesize)
132 {
133     struct mkt_data *d = id->data;
134     strlcpy(name, d->name, namesize);
135     return 0;
136 }
137 
138 static krb5_error_code KRB5_CALLCONV
mkt_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * c)139 mkt_start_seq_get(krb5_context context,
140 		  krb5_keytab id,
141 		  krb5_kt_cursor *c)
142 {
143     /* XXX */
144     c->fd = 0;
145     return 0;
146 }
147 
148 static krb5_error_code KRB5_CALLCONV
mkt_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * c)149 mkt_next_entry(krb5_context context,
150 	       krb5_keytab id,
151 	       krb5_keytab_entry *entry,
152 	       krb5_kt_cursor *c)
153 {
154     struct mkt_data *d = id->data;
155     if(c->fd >= d->num_entries)
156 	return KRB5_KT_END;
157     return krb5_kt_copy_entry_contents(context, &d->entries[c->fd++], entry);
158 }
159 
160 static krb5_error_code KRB5_CALLCONV
mkt_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)161 mkt_end_seq_get(krb5_context context,
162 		krb5_keytab id,
163 		krb5_kt_cursor *cursor)
164 {
165     return 0;
166 }
167 
168 static krb5_error_code KRB5_CALLCONV
mkt_add_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)169 mkt_add_entry(krb5_context context,
170 	      krb5_keytab id,
171 	      krb5_keytab_entry *entry)
172 {
173     struct mkt_data *d = id->data;
174     krb5_keytab_entry *tmp;
175     tmp = realloc(d->entries, (d->num_entries + 1) * sizeof(*d->entries));
176     if (tmp == NULL)
177 	return krb5_enomem(context);
178     d->entries = tmp;
179     return krb5_kt_copy_entry_contents(context, entry,
180 				       &d->entries[d->num_entries++]);
181 }
182 
183 static krb5_error_code KRB5_CALLCONV
mkt_remove_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)184 mkt_remove_entry(krb5_context context,
185 		 krb5_keytab id,
186 		 krb5_keytab_entry *entry)
187 {
188     struct mkt_data *d = id->data;
189     krb5_keytab_entry *e, *end;
190     int found = 0;
191 
192     if (d->num_entries == 0) {
193 	krb5_clear_error_message(context);
194         return KRB5_KT_NOTFOUND;
195     }
196 
197     /* do this backwards to minimize copying */
198     for(end = d->entries + d->num_entries, e = end - 1; e >= d->entries; e--) {
199 	if(krb5_kt_compare(context, e, entry->principal,
200 			   entry->vno, entry->keyblock.keytype)) {
201 	    krb5_kt_free_entry(context, e);
202 	    memmove(e, e + 1, (end - e - 1) * sizeof(*e));
203 	    memset(end - 1, 0, sizeof(*end));
204 	    d->num_entries--;
205 	    end--;
206 	    found = 1;
207 	}
208     }
209     if (!found) {
210 	krb5_clear_error_message (context);
211 	return KRB5_KT_NOTFOUND;
212     }
213     e = realloc(d->entries, d->num_entries * sizeof(*d->entries));
214     if(e != NULL || d->num_entries == 0)
215 	d->entries = e;
216     return 0;
217 }
218 
219 const krb5_kt_ops krb5_mkt_ops = {
220     "MEMORY",
221     mkt_resolve,
222     mkt_get_name,
223     mkt_close,
224     NULL, /* destroy */
225     NULL, /* get */
226     mkt_start_seq_get,
227     mkt_next_entry,
228     mkt_end_seq_get,
229     mkt_add_entry,
230     mkt_remove_entry,
231     NULL,
232     0
233 };
234