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