1 /*
2    Unix SMB/CIFS implementation.
3 
4    Database Glue between Samba and the KDC
5 
6    Copyright (C) Guenther Deschner <gd@samba.org> 2014
7    Copyright (C) Andreas Schneider <asn@samba.org> 2014
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19 
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23 
24 #include "includes.h"
25 #include <hdb.h>
26 #include "sdb.h"
27 #include "sdb_hdb.h"
28 #include "lib/krb5_wrap/krb5_samba.h"
29 #include "kdc/samba_kdc.h"
30 
sdb_flags_to_hdb_flags(const struct SDBFlags * s,HDBFlags * h)31 static void sdb_flags_to_hdb_flags(const struct SDBFlags *s,
32 				   HDBFlags *h)
33 {
34 	SMB_ASSERT(sizeof(struct SDBFlags) == sizeof(HDBFlags));
35 
36 	h->initial = s->initial;
37 	h->forwardable = s->forwardable;
38 	h->proxiable = s->proxiable;
39 	h->renewable = s->renewable;
40 	h->postdate = s->postdate;
41 	h->server = s->server;
42 	h->client = s->client;
43 	h->invalid = s->invalid;
44 	h->require_preauth = s->require_preauth;
45 	h->change_pw = s->change_pw;
46 	h->require_hwauth = s->require_hwauth;
47 	h->ok_as_delegate = s->ok_as_delegate;
48 	h->user_to_user = s->user_to_user;
49 	h->immutable = s->immutable;
50 	h->trusted_for_delegation = s->trusted_for_delegation;
51 	h->allow_kerberos4 = s->allow_kerberos4;
52 	h->allow_digest = s->allow_digest;
53 	h->locked_out = s->locked_out;
54 	h->_unused18 = s->_unused18;
55 	h->_unused19 = s->_unused19;
56 	h->_unused20 = s->_unused20;
57 	h->_unused21 = s->_unused21;
58 	h->_unused22 = s->_unused22;
59 	h->_unused23 = s->_unused23;
60 	h->_unused24 = s->_unused24;
61 	h->_unused25 = s->_unused25;
62 	h->_unused26 = s->_unused26;
63 	h->_unused27 = s->_unused27;
64 	h->_unused28 = s->_unused28;
65 	h->_unused29 = s->_unused29;
66 	h->_unused30 = s->_unused30;
67 	h->do_not_store = s->do_not_store;
68 }
69 
sdb_salt_to_Salt(const struct sdb_salt * s,Salt * h)70 static int sdb_salt_to_Salt(const struct sdb_salt *s, Salt *h)
71 {
72 	int ret;
73 
74 	h->type = s->type;
75 	ret = smb_krb5_copy_data_contents(&h->salt, s->salt.data, s->salt.length);
76 	if (ret != 0) {
77 		free_Salt(h);
78 		return ENOMEM;
79 	}
80 	h->opaque = NULL;
81 
82 	return 0;
83 }
84 
sdb_key_to_Key(const struct sdb_key * s,Key * h)85 static int sdb_key_to_Key(const struct sdb_key *s, Key *h)
86 {
87 	int rc;
88 
89 	if (s->mkvno != NULL) {
90 		h->mkvno = malloc(sizeof(unsigned int));
91 		if (h->mkvno == NULL) {
92 			goto error_nomem;
93 		}
94 		*h->mkvno = *s->mkvno;
95 	} else {
96 		h->mkvno = NULL;
97 	}
98 
99 	h->key.keytype = s->key.keytype;
100 	rc = smb_krb5_copy_data_contents(&h->key.keyvalue,
101 					 s->key.keyvalue.data,
102 					 s->key.keyvalue.length);
103 	if (rc != 0) {
104 		goto error_nomem;
105 	}
106 
107 	if (s->salt != NULL) {
108 		h->salt = malloc(sizeof(Salt));
109 		if (h->salt == NULL) {
110 			goto error_nomem;
111 		}
112 
113 		rc = sdb_salt_to_Salt(s->salt,
114 				      h->salt);
115 		if (rc != 0) {
116 			goto error_nomem;
117 		}
118 	} else {
119 		h->salt = NULL;
120 	}
121 
122 	return 0;
123 
124 error_nomem:
125 	free_Key(h);
126 	return ENOMEM;
127 }
128 
sdb_keys_to_Keys(const struct sdb_keys * s,Keys * h)129 static int sdb_keys_to_Keys(const struct sdb_keys *s, Keys *h)
130 {
131 	int ret, i;
132 
133 	h->len = s->len;
134 	if (s->val != NULL) {
135 		h->val = malloc(h->len * sizeof(Key));
136 		if (h->val == NULL) {
137 			return ENOMEM;
138 		}
139 		for (i = 0; i < h->len; i++) {
140 			ret = sdb_key_to_Key(&s->val[i],
141 					     &h->val[i]);
142 			if (ret != 0) {
143 				free_Keys(h);
144 				return ENOMEM;
145 			}
146 		}
147 	} else {
148 		h->val = NULL;
149 	}
150 
151 	return 0;
152 }
153 
sdb_event_to_Event(krb5_context context,const struct sdb_event * s,Event * h)154 static int sdb_event_to_Event(krb5_context context,
155 			      const struct sdb_event *s, Event *h)
156 {
157 	int ret;
158 
159 	if (s->principal != NULL) {
160 		ret = krb5_copy_principal(context,
161 					  s->principal,
162 					  &h->principal);
163 		if (ret != 0) {
164 			free_Event(h);
165 			return ret;
166 		}
167 	} else {
168 		h->principal = NULL;
169 	}
170 	h->time = s->time;
171 
172 	return 0;
173 }
174 
175 
sdb_entry_to_hdb_entry(krb5_context context,const struct sdb_entry * s,struct hdb_entry * h)176 static int sdb_entry_to_hdb_entry(krb5_context context,
177 				  const struct sdb_entry *s,
178 				  struct hdb_entry *h)
179 {
180 	unsigned int i;
181 	int rc;
182 
183 	ZERO_STRUCTP(h);
184 
185 	rc = krb5_copy_principal(context,
186 				 s->principal,
187 				 &h->principal);
188 	if (rc != 0) {
189 		return rc;
190 	}
191 
192 	h->kvno = s->kvno;
193 
194 	rc = sdb_keys_to_Keys(&s->keys, &h->keys);
195 	if (rc != 0) {
196 		goto error;
197 	}
198 
199 	rc = sdb_event_to_Event(context,
200 				 &s->created_by,
201 				 &h->created_by);
202 	if (rc != 0) {
203 		goto error;
204 	}
205 
206 	if (s->modified_by) {
207 		h->modified_by = malloc(sizeof(Event));
208 		if (h->modified_by == NULL) {
209 			rc = ENOMEM;
210 			goto error;
211 		}
212 
213 		rc = sdb_event_to_Event(context,
214 					 s->modified_by,
215 					 h->modified_by);
216 		if (rc != 0) {
217 			goto error;
218 		}
219 	} else {
220 		h->modified_by = NULL;
221 	}
222 
223 	if (s->valid_start != NULL) {
224 		h->valid_start = malloc(sizeof(KerberosTime));
225 		if (h->valid_start == NULL) {
226 			rc = ENOMEM;
227 			goto error;
228 		}
229 		*h->valid_start = *s->valid_start;
230 	} else {
231 		h->valid_start = NULL;
232 	}
233 
234 	if (s->valid_end != NULL) {
235 		h->valid_end = malloc(sizeof(KerberosTime));
236 		if (h->valid_end == NULL) {
237 			rc = ENOMEM;
238 			goto error;
239 		}
240 		*h->valid_end = *s->valid_end;
241 	} else {
242 		h->valid_end = NULL;
243 	}
244 
245 	if (s->pw_end != NULL) {
246 		h->pw_end = malloc(sizeof(KerberosTime));
247 		if (h->pw_end == NULL) {
248 			rc = ENOMEM;
249 			goto error;
250 		}
251 		*h->pw_end = *s->pw_end;
252 	} else {
253 		h->pw_end = NULL;
254 	}
255 
256 	if (s->max_life != NULL) {
257 		h->max_life = malloc(sizeof(unsigned int));
258 		if (h->max_life == NULL) {
259 			rc = ENOMEM;
260 			goto error;
261 		}
262 		*h->max_life = *s->max_life;
263 	} else {
264 		h->max_life = NULL;
265 	}
266 
267 	if (s->max_renew != NULL) {
268 		h->max_renew = malloc(sizeof(unsigned int));
269 		if (h->max_renew == NULL) {
270 			rc = ENOMEM;
271 			goto error;
272 		}
273 		*h->max_renew = *s->max_renew;
274 	} else {
275 		h->max_renew = NULL;
276 	}
277 
278 	sdb_flags_to_hdb_flags(&s->flags, &h->flags);
279 
280 	h->etypes = NULL;
281 	if (h->keys.val != NULL) {
282 		h->etypes = malloc(sizeof(*h->etypes));
283 		if (h->etypes == NULL) {
284 			rc = ENOMEM;
285 			goto error;
286 		}
287 
288 		h->etypes->len = s->keys.len;
289 
290 		h->etypes->val = calloc(h->etypes->len, sizeof(int));
291 		if (h->etypes->val == NULL) {
292 			rc = ENOMEM;
293 			goto error;
294 		}
295 
296 		for (i = 0; i < h->etypes->len; i++) {
297 			Key k = h->keys.val[i];
298 
299 			h->etypes->val[i] = KRB5_KEY_TYPE(&(k.key));
300 		}
301 	}
302 
303 	h->generation = NULL;
304 	h->extensions = NULL; /* really sure ? FIXME */
305 
306 	return 0;
307 error:
308 	free_hdb_entry(h);
309 	return rc;
310 }
311 
samba_kdc_hdb_entry_destructor(struct samba_kdc_entry * p)312 static int samba_kdc_hdb_entry_destructor(struct samba_kdc_entry *p)
313 {
314 	struct hdb_entry_ex *entry_ex = p->entry_ex;
315 	free_hdb_entry(&entry_ex->entry);
316 
317 	return 0;
318 }
319 
samba_kdc_free_hdb_entry(krb5_context context,struct hdb_entry_ex * entry_ex)320 static void samba_kdc_free_hdb_entry(krb5_context context,
321 				     struct hdb_entry_ex *entry_ex)
322 {
323 	/* this function is called only from hdb_free_entry().
324 	 * Make sure we neutralize the destructor or we will
325 	 * get a double free later when hdb_free_entry() will
326 	 * try to call free_hdb_entry() */
327 	talloc_set_destructor(entry_ex->ctx, NULL);
328 
329 	/* now proceed to free the talloc part */
330 	talloc_free(entry_ex->ctx);
331 }
332 
sdb_entry_ex_to_hdb_entry_ex(krb5_context context,const struct sdb_entry_ex * s,struct hdb_entry_ex * h)333 int sdb_entry_ex_to_hdb_entry_ex(krb5_context context,
334 				 const struct sdb_entry_ex *s,
335 				 struct hdb_entry_ex *h)
336 {
337 	struct samba_kdc_entry *skdc_entry;
338 
339 	ZERO_STRUCTP(h);
340 
341 	if (s->ctx != NULL) {
342 		skdc_entry = talloc_get_type(s->ctx, struct samba_kdc_entry);
343 
344 		h->ctx		= skdc_entry;
345 		h->free_entry	= samba_kdc_free_hdb_entry;
346 
347 		talloc_set_destructor(skdc_entry,
348 				      samba_kdc_hdb_entry_destructor);
349 	}
350 
351 	return sdb_entry_to_hdb_entry(context, &s->entry, &h->entry);
352 }
353