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