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 <kdb.h>
26 #include "sdb.h"
27 #include "sdb_kdb.h"
28 #include "kdc/samba_kdc.h"
29 #include "lib/krb5_wrap/krb5_samba.h"
30 
SDBFlags_to_kflags(const struct SDBFlags * s,krb5_flags * k)31 static int SDBFlags_to_kflags(const struct SDBFlags *s,
32 			      krb5_flags *k)
33 {
34 	*k = 0;
35 
36 	if (s->initial) {
37 		*k |= KRB5_KDB_DISALLOW_TGT_BASED;
38 	}
39 	/* The forwardable and proxiable flags are set according to client and
40 	 * server attributes. */
41 	if (!s->forwardable) {
42 		*k |= KRB5_KDB_DISALLOW_FORWARDABLE;
43 	}
44 	if (!s->proxiable) {
45 		*k |= KRB5_KDB_DISALLOW_PROXIABLE;
46 	}
47 	if (s->renewable) {
48 		;
49 	}
50 	if (s->postdate) {
51 		;
52 	}
53 	if (s->server) {
54 		;
55 	}
56 	if (s->client) {
57 		;
58 	}
59 	if (s->invalid) {
60 		*k |= KRB5_KDB_DISALLOW_ALL_TIX;
61 	}
62 	if (s->require_preauth) {
63 		*k |= KRB5_KDB_REQUIRES_PRE_AUTH;
64 	}
65 	if (s->change_pw) {
66 		*k |= KRB5_KDB_PWCHANGE_SERVICE;
67 	}
68 	if (s->require_hwauth) {
69 		*k |= KRB5_KDB_REQUIRES_HW_AUTH;
70 	}
71 	if (s->ok_as_delegate) {
72 		*k |= KRB5_KDB_OK_AS_DELEGATE;
73 	}
74 	if (s->user_to_user) {
75 		;
76 	}
77 	if (s->immutable) {
78 		;
79 	}
80 	if (s->trusted_for_delegation) {
81 		*k |= KRB5_KDB_OK_TO_AUTH_AS_DELEGATE;
82 	}
83 	if (s->allow_kerberos4) {
84 		;
85 	}
86 	if (s->allow_digest) {
87 		;
88 	}
89 
90 	return 0;
91 }
92 
sdb_event_to_kmod(krb5_context context,const struct sdb_event * s,krb5_db_entry * k)93 static int sdb_event_to_kmod(krb5_context context,
94 			     const struct sdb_event *s,
95 			     krb5_db_entry *k)
96 {
97 	krb5_error_code ret;
98 	krb5_principal principal = NULL;
99 
100 	if (s->principal != NULL) {
101 		ret = krb5_copy_principal(context,
102 					  s->principal,
103 					  &principal);
104 		if (ret != 0) {
105 			return ret;
106 		}
107 	}
108 
109 	ret = krb5_dbe_update_mod_princ_data(context,
110 					     k, s->time,
111 					     principal);
112 
113 	krb5_free_principal(context, principal);
114 
115 	return ret;
116 }
117 
118 /* sets up salt on the 2nd array position */
119 
sdb_salt_to_krb5_key_data(const struct sdb_salt * s,krb5_key_data * k)120 static int sdb_salt_to_krb5_key_data(const struct sdb_salt *s,
121 				     krb5_key_data *k)
122 {
123 	switch (s->type) {
124 #if 0
125 	/* for now use the special mechanism where the MIT KDC creates the salt
126 	 * on its own */
127 	case 3: /* FIXME KRB5_PW_SALT */
128 		k->key_data_type[1] = KRB5_KDB_SALTTYPE_NORMAL;
129 		break;
130 	/*
131 	case hdb_afs3_salt:
132 		k->key_data_type[1] = KRB5_KDB_SALTTYPE_AFS3;
133 		break;
134 	*/
135 #endif
136 	default:
137 		k->key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
138 		break;
139 	}
140 
141 	k->key_data_contents[1] = malloc(s->salt.length);
142 	if (k->key_data_contents[1] == NULL) {
143 		return ENOMEM;
144 	}
145 	memcpy(k->key_data_contents[1],
146 	       s->salt.data,
147 	       s->salt.length);
148 	k->key_data_length[1] = s->salt.length;
149 
150 	return 0;
151 }
152 
sdb_key_to_krb5_key_data(const struct sdb_key * s,int kvno,krb5_key_data * k)153 static int sdb_key_to_krb5_key_data(const struct sdb_key *s,
154 				    int kvno,
155 				    krb5_key_data *k)
156 {
157 	int ret = 0;
158 
159 	ZERO_STRUCTP(k);
160 
161 	k->key_data_ver = KRB5_KDB_V1_KEY_DATA_ARRAY;
162 	k->key_data_kvno = kvno;
163 
164 	k->key_data_type[0] = KRB5_KEY_TYPE(&s->key);
165 	k->key_data_length[0] = KRB5_KEY_LENGTH(&s->key);
166 	k->key_data_contents[0] = malloc(k->key_data_length[0]);
167 	if (k->key_data_contents[0] == NULL) {
168 		return ENOMEM;
169 	}
170 
171 	memcpy(k->key_data_contents[0],
172 	       KRB5_KEY_DATA(&s->key),
173 	       k->key_data_length[0]);
174 
175 	if (s->salt != NULL) {
176 		ret = sdb_salt_to_krb5_key_data(s->salt, k);
177 		if (ret) {
178 			memset(k->key_data_contents[0], 0, k->key_data_length[0]);
179 			free(k->key_data_contents[0]);
180 		}
181 	}
182 
183 	return ret;
184 }
185 
free_krb5_db_entry(krb5_context context,krb5_db_entry * k)186 static void free_krb5_db_entry(krb5_context context,
187 			       krb5_db_entry *k)
188 {
189 	krb5_tl_data *tl_data_next = NULL;
190 	krb5_tl_data *tl_data = NULL;
191 	int i, j;
192 
193 	if (k == NULL) {
194 		return;
195 	}
196 
197 	krb5_free_principal(context, k->princ);
198 
199 	for (tl_data = k->tl_data; tl_data; tl_data = tl_data_next) {
200 		tl_data_next = tl_data->tl_data_next;
201 		if (tl_data->tl_data_contents != NULL) {
202 			free(tl_data->tl_data_contents);
203 		}
204 		free(tl_data);
205 	}
206 
207 	if (k->key_data != NULL) {
208 		for (i = 0; i < k->n_key_data; i++) {
209 			for (j = 0; j < k->key_data[i].key_data_ver; j++) {
210 				if (k->key_data[i].key_data_length[j] != 0) {
211 					if (k->key_data[i].key_data_contents[j] != NULL) {
212 						memset(k->key_data[i].key_data_contents[j], 0, k->key_data[i].key_data_length[j]);
213 						free(k->key_data[i].key_data_contents[j]);
214 					}
215 				}
216 				k->key_data[i].key_data_contents[j] = NULL;
217 				k->key_data[i].key_data_length[j] = 0;
218 				k->key_data[i].key_data_type[j] = 0;
219 			}
220 		}
221 		free(k->key_data);
222 	}
223 
224 	ZERO_STRUCTP(k);
225 }
226 
sdb_entry_ex_to_krb5_db_entry(krb5_context context,const struct sdb_entry * s,krb5_db_entry * k)227 static int sdb_entry_ex_to_krb5_db_entry(krb5_context context,
228 					 const struct sdb_entry *s,
229 					 krb5_db_entry *k)
230 {
231 	krb5_error_code ret;
232 	int i;
233 
234 	k->magic = KRB5_KDB_MAGIC_NUMBER;
235 	k->len = KRB5_KDB_V1_BASE_LENGTH;
236 
237 	ret = krb5_copy_principal(context,
238 				  s->principal,
239 				  &k->princ);
240 	if (ret) {
241 		free_krb5_db_entry(context, k);
242 		return ret;
243 	}
244 
245 	ret = SDBFlags_to_kflags(&s->flags,
246 				 &k->attributes);
247 	if (ret) {
248 		free_krb5_db_entry(context, k);
249 		return ret;
250 	}
251 
252 	if (s->max_life != NULL) {
253 		k->max_life = *s->max_life;
254 	}
255 	if (s->max_renew != NULL) {
256 		k->max_renewable_life = *s->max_renew;
257 	}
258 	if (s->valid_end != NULL) {
259 		k->expiration = *s->valid_end;
260 	}
261 	if (s->pw_end != NULL) {
262 		k->pw_expiration = *s->pw_end;
263 	}
264 
265 	/* last_success */
266 	/* last_failed */
267 	/* fail_auth_count */
268 	/* n_tl_data */
269 
270 	/*
271 	 * If we leave early when looking up the realm, we do not have all
272 	 * information about a principal. We need to construct a db entry
273 	 * with minimal information, so skip this part.
274 	 */
275 	if (s->created_by.time != 0) {
276 		ret = sdb_event_to_kmod(context,
277 					s->modified_by ? s->modified_by : &s->created_by,
278 					k);
279 		if (ret) {
280 			free_krb5_db_entry(context, k);
281 			return ret;
282 		}
283 	}
284 
285 	/* FIXME: TODO HDB Extensions */
286 
287 	if (s->keys.len > 0) {
288 		k->key_data = malloc(s->keys.len * sizeof(krb5_key_data));
289 		if (k->key_data == NULL) {
290 			free_krb5_db_entry(context, k);
291 			return ret;
292 		}
293 
294 		for (i=0; i < s->keys.len; i++) {
295 			ret = sdb_key_to_krb5_key_data(&s->keys.val[i],
296 						       s->kvno,
297 						       &k->key_data[i]);
298 			if (ret) {
299 				free_krb5_db_entry(context, k);
300 				return ret;
301 			}
302 
303 			k->n_key_data++;
304 		}
305 	}
306 
307 	return 0;
308 }
309 
samba_kdc_kdb_entry_destructor(struct samba_kdc_entry * p)310 static int samba_kdc_kdb_entry_destructor(struct samba_kdc_entry *p)
311 {
312 	krb5_db_entry *entry_ex = p->entry_ex;
313 	krb5_error_code ret;
314 	krb5_context context;
315 
316 	if (entry_ex->e_data != NULL) {
317 		struct samba_kdc_entry *skdc_entry;
318 
319 		skdc_entry = talloc_get_type(entry_ex->e_data,
320 					     struct samba_kdc_entry);
321 		talloc_set_destructor(skdc_entry, NULL);
322 		entry_ex->e_data = NULL;
323 	}
324 
325 	ret = smb_krb5_init_context_common(&context);
326 	if (ret) {
327 		DBG_ERR("kerberos init context failed (%s)\n",
328 			error_message(ret));
329 		return ret;
330 	}
331 
332 	krb5_db_free_principal(context, entry_ex);
333 	krb5_free_context(context);
334 
335 	return 0;
336 }
337 
sdb_entry_ex_to_kdb_entry_ex(krb5_context context,const struct sdb_entry_ex * s,krb5_db_entry * k)338 int sdb_entry_ex_to_kdb_entry_ex(krb5_context context,
339 				 const struct sdb_entry_ex *s,
340 				 krb5_db_entry *k)
341 {
342 	ZERO_STRUCTP(k);
343 
344 	if (s->ctx != NULL) {
345 		struct samba_kdc_entry *skdc_entry;
346 
347 		skdc_entry = talloc_get_type(s->ctx, struct samba_kdc_entry);
348 
349 		k->e_data	= (void *)skdc_entry;
350 
351 		talloc_set_destructor(skdc_entry,
352 				      samba_kdc_kdb_entry_destructor);
353 	}
354 
355 	return sdb_entry_ex_to_krb5_db_entry(context, &s->entry, k);
356 }
357