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