s3-libads: Use the configured LDAP page size.
[obnox/samba/samba-obnox.git] / source4 / kdc / mit_samba.c
1 /*
2    MIT-Samba4 library
3
4    Copyright (c) 2010, Simo Sorce <idra@samba.org>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #define TEVENT_DEPRECATED 1
21
22 #include "includes.h"
23 #include "param/param.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "system/kerberos.h"
26 #include <hdb.h>
27 #include "mit_samba_interface.h"
28 #include "auth/kerberos/kerberos.h"
29 #include "kdc/samba_kdc.h"
30 #include "kdc/pac-glue.h"
31 #include "kdc/db-glue.h"
32
33 const int mit_samba_interface_version = MIT_SAMBA_INTERFACE_VERSION;
34
35 struct mit_samba_context {
36         struct auth_session_info *session_info;
37
38         /* for compat with hdb plugin common code */
39         krb5_context context;
40         struct samba_kdc_db_context *db_ctx;
41 };
42
43 static void mit_samba_context_free(struct mit_samba_context *ctx)
44 {
45         /* free heimdal's krb5_context */
46         if (ctx->context) {
47                 krb5_free_context(ctx->context);
48         }
49
50         /* then free everything else */
51         talloc_free(ctx);
52 }
53
54 static int mit_samba_context_init(struct mit_samba_context **_ctx)
55 {
56         NTSTATUS status;
57         struct mit_samba_context *ctx;
58         const char *s4_conf_file;
59         int ret;
60         struct samba_kdc_base_context base_ctx;
61
62         ctx = talloc(NULL, struct mit_samba_context);
63         if (!ctx) {
64                 ret = ENOMEM;
65                 goto done;
66         }
67
68         base_ctx.ev_ctx = tevent_context_init(ctx);
69         if (!base_ctx.ev_ctx) {
70                 ret = ENOMEM;
71                 goto done;
72         }
73         tevent_loop_allow_nesting(base_ctx.ev_ctx);
74         base_ctx.lp_ctx = loadparm_init_global(false);
75         if (!base_ctx.lp_ctx) {
76                 ret = ENOMEM;
77                 goto done;
78         }
79         /* init s4 configuration */
80         s4_conf_file = lpcfg_configfile(base_ctx.lp_ctx);
81         if (s4_conf_file) {
82                 lpcfg_load(base_ctx.lp_ctx, s4_conf_file);
83         } else {
84                 lpcfg_load_default(base_ctx.lp_ctx);
85         }
86
87         status = samba_kdc_setup_db_ctx(ctx, &base_ctx, &ctx->db_ctx);
88         if (!NT_STATUS_IS_OK(status)) {
89                 ret = EINVAL;
90                 goto done;
91         }
92
93         /* init heimdal's krb_context and log facilities */
94         ret = smb_krb5_init_context_basic(ctx,
95                                           ctx->db_ctx->lp_ctx,
96                                           &ctx->context);
97         if (ret) {
98                 goto done;
99         }
100
101         ret = 0;
102
103 done:
104         if (ret) {
105                 mit_samba_context_free(ctx);
106         } else {
107                 *_ctx = ctx;
108         }
109         return ret;
110 }
111
112
113 static int mit_samba_get_principal(struct mit_samba_context *ctx,
114                                    char *principal_string,
115                                    unsigned int flags,
116                                    hdb_entry_ex **_hentry)
117 {
118         krb5_principal principal;
119         hdb_entry_ex *hentry;
120         int ret;
121
122         hentry = talloc(ctx, hdb_entry_ex);
123         if (!hentry) {
124                 return ENOMEM;
125         }
126
127         ret = krb5_parse_name(ctx->context, principal_string, &principal);
128         if (ret) {
129                 goto done;
130         }
131
132         ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
133                               principal, flags, 0, hentry);
134
135         krb5_free_principal(ctx->context, principal);
136
137 done:
138         if (ret) {
139                 talloc_free(hentry);
140         } else {
141                 talloc_steal(hentry->ctx, hentry);
142                 *_hentry = hentry;
143         }
144         return ret;
145 }
146
147 static int mit_samba_get_firstkey(struct mit_samba_context *ctx,
148                                   hdb_entry_ex **_hentry)
149 {
150         hdb_entry_ex *hentry;
151         int ret;
152
153         hentry = talloc(ctx, hdb_entry_ex);
154         if (!hentry) {
155                 return ENOMEM;
156         }
157
158         ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, hentry);
159
160         if (ret) {
161                 talloc_free(hentry);
162         } else {
163                 talloc_steal(hentry->ctx, hentry);
164                 *_hentry = hentry;
165         }
166         return ret;
167 }
168
169 static int mit_samba_get_nextkey(struct mit_samba_context *ctx,
170                                  hdb_entry_ex **_hentry)
171 {
172         hdb_entry_ex *hentry;
173         int ret;
174
175         hentry = talloc(ctx, hdb_entry_ex);
176         if (!hentry) {
177                 return ENOMEM;
178         }
179
180         ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, hentry);
181
182         if (ret) {
183                 talloc_free(hentry);
184         } else {
185                 talloc_steal(hentry->ctx, hentry);
186                 *_hentry = hentry;
187         }
188         return ret;
189 }
190
191 static int mit_samba_get_pac_data(struct mit_samba_context *ctx,
192                                   hdb_entry_ex *client,
193                                   DATA_BLOB *data)
194 {
195         TALLOC_CTX *tmp_ctx;
196         DATA_BLOB *pac_blob;
197         NTSTATUS nt_status;
198         struct samba_kdc_entry *skdc_entry;
199
200         skdc_entry = talloc_get_type_abort(client->ctx,
201                                            struct samba_kdc_entry);
202
203         tmp_ctx = talloc_named(ctx, 0, "mit_samba_get_pac_data context");
204         if (!tmp_ctx) {
205                 return ENOMEM;
206         }
207
208         nt_status = samba_kdc_get_pac_blob(tmp_ctx, skdc_entry, &pac_blob);
209         if (!NT_STATUS_IS_OK(nt_status)) {
210                 talloc_free(tmp_ctx);
211                 return EINVAL;
212         }
213
214         data->data = (uint8_t *)malloc(pac_blob->length);
215         if (!data->data) {
216                 talloc_free(tmp_ctx);
217                 return ENOMEM;
218         }
219         memcpy(data->data, pac_blob->data, pac_blob->length);
220         data->length = pac_blob->length;
221
222         talloc_free(tmp_ctx);
223         return 0;
224 }
225
226 static int mit_samba_update_pac_data(struct mit_samba_context *ctx,
227                                      hdb_entry_ex *client,
228                                      DATA_BLOB *pac_data,
229                                      DATA_BLOB *logon_data)
230 {
231         TALLOC_CTX *tmp_ctx;
232         DATA_BLOB *logon_blob;
233         krb5_error_code code;
234         NTSTATUS nt_status;
235         krb5_pac pac = NULL;
236         int ret;
237         struct samba_kdc_entry *skdc_entry = NULL;
238
239         if (client) {
240                 skdc_entry = talloc_get_type_abort(client->ctx,
241                                                    struct samba_kdc_entry);
242         }
243
244         /* The user account may be set not to want the PAC */
245         if (client && !samba_princ_needs_pac(skdc_entry)) {
246                 return EINVAL;
247         }
248
249         tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context");
250         if (!tmp_ctx) {
251                 return ENOMEM;
252         }
253
254         logon_blob = talloc_zero(tmp_ctx, DATA_BLOB);
255         if (!logon_blob) {
256                 ret = ENOMEM;
257                 goto done;
258         }
259
260         code = krb5_pac_parse(ctx->context,
261                               pac_data->data, pac_data->length, &pac);
262         if (code) {
263                 ret = EINVAL;
264                 goto done;
265         }
266
267         /* TODO: An implementation-specific decision will need to be
268          * made as to when to check the KDC pac signature, and how to
269          * untrust untrusted RODCs */
270         nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context,
271                                               pac, logon_blob, NULL, NULL);
272         if (!NT_STATUS_IS_OK(nt_status)) {
273                 DEBUG(0, ("Building PAC failed: %s\n",
274                           nt_errstr(nt_status)));
275                 ret = EINVAL;
276                 goto done;
277         }
278
279         logon_data->data = (uint8_t *)malloc(logon_blob->length);
280         if (!logon_data->data) {
281                 ret = ENOMEM;
282                 goto done;
283         }
284         memcpy(logon_data->data, logon_blob->data, logon_blob->length);
285         logon_data->length = logon_blob->length;
286
287         ret = 0;
288
289 done:
290         if (pac) krb5_pac_free(ctx->context, pac);
291         talloc_free(tmp_ctx);
292         return ret;
293 }
294
295 /* provide header, function is exported but there are no public headers */
296
297 krb5_error_code encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);
298
299 /* this function allocates 'data' using malloc.
300  * The caller is responsible for freeing it */
301 static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
302 {
303         krb5_error_code ret = 0;
304         krb5_pa_data pa, *ppa = NULL;
305         krb5_data *d = NULL;
306
307         if (!e_data)
308                 return;
309
310         e_data->data   = NULL;
311         e_data->length = 0;
312
313         pa.magic                = KV5M_PA_DATA;
314         pa.pa_type              = KRB5_PADATA_PW_SALT;
315         pa.length               = 12;
316         pa.contents             = malloc(pa.length);
317         if (!pa.contents) {
318                 return;
319         }
320
321         SIVAL(pa.contents, 0, NT_STATUS_V(nt_status));
322         SIVAL(pa.contents, 4, 0);
323         SIVAL(pa.contents, 8, 1);
324
325         ppa = &pa;
326
327         ret = encode_krb5_padata_sequence(&ppa, &d);
328         free(pa.contents);
329         if (ret) {
330                 return;
331         }
332
333         e_data->data   = (uint8_t *)d->data;
334         e_data->length = d->length;
335
336         /* free d, not d->data - gd */
337         free(d);
338
339         return;
340 }
341
342 static int mit_samba_check_client_access(struct mit_samba_context *ctx,
343                                          hdb_entry_ex *client,
344                                          const char *client_name,
345                                          hdb_entry_ex *server,
346                                          const char *server_name,
347                                          const char *netbios_name,
348                                          bool password_change,
349                                          DATA_BLOB *e_data)
350 {
351         struct samba_kdc_entry *kdc_entry;
352         NTSTATUS nt_status;
353
354         kdc_entry = talloc_get_type(client->ctx, struct samba_kdc_entry);
355
356         nt_status = samba_kdc_check_client_access(kdc_entry,
357                                                   client_name,
358                                                   netbios_name,
359                                                   password_change);
360
361         if (!NT_STATUS_IS_OK(nt_status)) {
362                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
363                         return ENOMEM;
364                 }
365
366                 samba_kdc_build_edata_reply(nt_status, e_data);
367
368                 return samba_kdc_map_policy_err(nt_status);
369         }
370
371         return 0;
372 }
373
374 static int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
375                                      hdb_entry_ex *entry,
376                                      const char *target_name,
377                                      bool is_nt_enterprise_name)
378 {
379 #if 1
380         /*
381          * This is disabled because mit_samba_update_pac_data() does not handle
382          * S4U_DELEGATION_INFO
383          */
384
385         return KRB5KDC_ERR_BADOPTION;
386 #else
387         krb5_principal target_principal;
388         int flags = 0;
389         int ret;
390
391         if (is_nt_enterprise_name) {
392                 flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
393         }
394
395         ret = krb5_parse_name_flags(ctx->context, target_name,
396                                     flags, &target_principal);
397         if (ret) {
398                 return ret;
399         }
400
401         ret = samba_kdc_check_s4u2proxy(ctx->context,
402                                         ctx->db_ctx,
403                                         skdc_entry,
404                                         target_principal);
405
406         krb5_free_principal(ctx->context, target_principal);
407
408         return ret;
409 #endif
410 }
411
412 struct mit_samba_function_table mit_samba_function_table = {
413         mit_samba_context_init,
414         mit_samba_context_free,
415         mit_samba_get_principal,
416         mit_samba_get_firstkey,
417         mit_samba_get_nextkey,
418         mit_samba_get_pac_data,
419         mit_samba_update_pac_data,
420         mit_samba_check_client_access,
421         mit_samba_check_s4u2proxy
422 };