s4:kdc: split s4u2self and s4u2proxy checks
[amitay/samba.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
199         tmp_ctx = talloc_named(ctx, 0, "mit_samba_get_pac_data context");
200         if (!tmp_ctx) {
201                 return ENOMEM;
202         }
203
204         nt_status = samba_kdc_get_pac_blob(tmp_ctx, client, &pac_blob);
205         if (!NT_STATUS_IS_OK(nt_status)) {
206                 talloc_free(tmp_ctx);
207                 return EINVAL;
208         }
209
210         data->data = (uint8_t *)malloc(pac_blob->length);
211         if (!data->data) {
212                 talloc_free(tmp_ctx);
213                 return ENOMEM;
214         }
215         memcpy(data->data, pac_blob->data, pac_blob->length);
216         data->length = pac_blob->length;
217
218         talloc_free(tmp_ctx);
219         return 0;
220 }
221
222 static int mit_samba_update_pac_data(struct mit_samba_context *ctx,
223                                      hdb_entry_ex *client,
224                                      DATA_BLOB *pac_data,
225                                      DATA_BLOB *logon_data)
226 {
227         TALLOC_CTX *tmp_ctx;
228         DATA_BLOB *logon_blob;
229         krb5_error_code code;
230         NTSTATUS nt_status;
231         krb5_pac pac = NULL;
232         int ret;
233
234         /* The user account may be set not to want the PAC */
235         if (client && !samba_princ_needs_pac(client)) {
236                 return EINVAL;
237         }
238
239         tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context");
240         if (!tmp_ctx) {
241                 return ENOMEM;
242         }
243
244         logon_blob = talloc_zero(tmp_ctx, DATA_BLOB);
245         if (!logon_blob) {
246                 ret = ENOMEM;
247                 goto done;
248         }
249
250         code = krb5_pac_parse(ctx->context,
251                               pac_data->data, pac_data->length, &pac);
252         if (code) {
253                 ret = EINVAL;
254                 goto done;
255         }
256
257         nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context,
258                                               &pac, logon_blob);
259         if (!NT_STATUS_IS_OK(nt_status)) {
260                 DEBUG(0, ("Building PAC failed: %s\n",
261                           nt_errstr(nt_status)));
262                 ret = EINVAL;
263                 goto done;
264         }
265
266         logon_data->data = (uint8_t *)malloc(logon_blob->length);
267         if (!logon_data->data) {
268                 ret = ENOMEM;
269                 goto done;
270         }
271         memcpy(logon_data->data, logon_blob->data, logon_blob->length);
272         logon_data->length = logon_blob->length;
273
274         ret = 0;
275
276 done:
277         if (pac) krb5_pac_free(ctx->context, pac);
278         talloc_free(tmp_ctx);
279         return ret;
280 }
281
282 static int mit_samba_check_client_access(struct mit_samba_context *ctx,
283                                          hdb_entry_ex *client,
284                                          const char *client_name,
285                                          hdb_entry_ex *server,
286                                          const char *server_name,
287                                          const char *netbios_name,
288                                          bool password_change,
289                                          DATA_BLOB *e_data)
290 {
291         struct samba_kdc_entry *kdc_entry;
292         NTSTATUS nt_status;
293
294         kdc_entry = talloc_get_type(client->ctx, struct samba_kdc_entry);
295
296         nt_status = samba_kdc_check_client_access(kdc_entry,
297                                                   client_name,
298                                                   netbios_name,
299                                                   password_change);
300
301         if (!NT_STATUS_IS_OK(nt_status)) {
302                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
303                         return ENOMEM;
304                 }
305
306                 samba_kdc_build_edata_reply(nt_status, e_data);
307
308                 return samba_kdc_map_policy_err(nt_status);
309         }
310
311         return 0;
312 }
313
314 static int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
315                                      hdb_entry_ex *entry,
316                                      const char *target_name,
317                                      bool is_nt_enterprise_name)
318 {
319         krb5_principal target_principal;
320         int flags = 0;
321         int ret;
322
323         if (is_nt_enterprise_name) {
324                 flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
325         }
326
327         ret = krb5_parse_name_flags(ctx->context, target_name,
328                                     flags, &target_principal);
329         if (ret) {
330                 return ret;
331         }
332
333         ret = samba_kdc_check_s4u2proxy(ctx->context,
334                                         ctx->db_ctx,
335                                         entry,
336                                         target_principal);
337
338         krb5_free_principal(ctx->context, target_principal);
339
340         return ret;
341 }
342
343 struct mit_samba_function_table mit_samba_function_table = {
344         mit_samba_context_init,
345         mit_samba_context_free,
346         mit_samba_get_principal,
347         mit_samba_get_firstkey,
348         mit_samba_get_nextkey,
349         mit_samba_get_pac_data,
350         mit_samba_update_pac_data,
351         mit_samba_check_client_access,
352         mit_samba_check_s4u2proxy
353 };