s4:kdc/*.c - minimise includes
[metze/samba/wip.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 #include "includes.h"
21 #include "param/param.h"
22 #include "dsdb/samdb/samdb.h"
23 #include "system/kerberos.h"
24 #include <hdb.h>
25 #include "mit_samba_interface.h"
26 #include "auth/kerberos/kerberos.h"
27 #include "kdc/samba_kdc.h"
28 #include "kdc/pac-glue.h"
29 #include "kdc/db-glue.h"
30
31 const int mit_samba_interface_version = MIT_SAMBA_INTERFACE_VERSION;
32
33 struct mit_samba_context {
34         struct auth_session_info *session_info;
35
36         /* for compat with hdb plugin common code */
37         krb5_context context;
38         struct samba_kdc_db_context *db_ctx;
39 };
40
41 static void mit_samba_context_free(struct mit_samba_context *ctx)
42 {
43         /* free heimdal's krb5_context */
44         if (ctx->context) {
45                 krb5_free_context(ctx->context);
46         }
47
48         /* then free everything else */
49         talloc_free(ctx);
50 }
51
52 static int mit_samba_context_init(struct mit_samba_context **_ctx)
53 {
54         NTSTATUS status;
55         struct mit_samba_context *ctx;
56         const char *s4_conf_file;
57         int ret;
58         struct samba_kdc_base_context base_ctx;
59
60         ctx = talloc(NULL, struct mit_samba_context);
61         if (!ctx) {
62                 ret = ENOMEM;
63                 goto done;
64         }
65
66         base_ctx.ev_ctx = tevent_context_init(ctx);
67         if (!base_ctx.ev_ctx) {
68                 ret = ENOMEM;
69                 goto done;
70         }
71         base_ctx.lp_ctx = loadparm_init_global(false);
72         if (!base_ctx.lp_ctx) {
73                 ret = ENOMEM;
74                 goto done;
75         }
76         /* init s4 configuration */
77         s4_conf_file = lpcfg_configfile(base_ctx.lp_ctx);
78         if (s4_conf_file) {
79                 lpcfg_load(base_ctx.lp_ctx, s4_conf_file);
80         } else {
81                 lpcfg_load_default(base_ctx.lp_ctx);
82         }
83
84         status = samba_kdc_setup_db_ctx(ctx, &base_ctx, &ctx->db_ctx);
85         if (!NT_STATUS_IS_OK(status)) {
86                 ret = EINVAL;
87                 goto done;
88         }
89
90         /* init heimdal's krb_context and log facilities */
91         ret = smb_krb5_init_context_basic(ctx,
92                                           ctx->db_ctx->lp_ctx,
93                                           &ctx->context);
94         if (ret) {
95                 goto done;
96         }
97
98         ret = 0;
99
100 done:
101         if (ret) {
102                 mit_samba_context_free(ctx);
103         } else {
104                 *_ctx = ctx;
105         }
106         return ret;
107 }
108
109
110 static int mit_samba_get_principal(struct mit_samba_context *ctx,
111                                    char *principal_string,
112                                    unsigned int flags,
113                                    hdb_entry_ex **_hentry)
114 {
115         krb5_principal principal;
116         hdb_entry_ex *hentry;
117         int ret;
118
119         hentry = talloc(ctx, hdb_entry_ex);
120         if (!hentry) {
121                 return ENOMEM;
122         }
123
124         ret = krb5_parse_name(ctx->context, principal_string, &principal);
125         if (ret) {
126                 goto done;
127         }
128
129         ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
130                               principal, flags, 0, hentry);
131
132         krb5_free_principal(ctx->context, principal);
133
134 done:
135         if (ret) {
136                 talloc_free(hentry);
137         } else {
138                 talloc_steal(hentry->ctx, hentry);
139                 *_hentry = hentry;
140         }
141         return ret;
142 }
143
144 static int mit_samba_get_firstkey(struct mit_samba_context *ctx,
145                                   hdb_entry_ex **_hentry)
146 {
147         hdb_entry_ex *hentry;
148         int ret;
149
150         hentry = talloc(ctx, hdb_entry_ex);
151         if (!hentry) {
152                 return ENOMEM;
153         }
154
155         ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, hentry);
156
157         if (ret) {
158                 talloc_free(hentry);
159         } else {
160                 talloc_steal(hentry->ctx, hentry);
161                 *_hentry = hentry;
162         }
163         return ret;
164 }
165
166 static int mit_samba_get_nextkey(struct mit_samba_context *ctx,
167                                  hdb_entry_ex **_hentry)
168 {
169         hdb_entry_ex *hentry;
170         int ret;
171
172         hentry = talloc(ctx, hdb_entry_ex);
173         if (!hentry) {
174                 return ENOMEM;
175         }
176
177         ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, hentry);
178
179         if (ret) {
180                 talloc_free(hentry);
181         } else {
182                 talloc_steal(hentry->ctx, hentry);
183                 *_hentry = hentry;
184         }
185         return ret;
186 }
187
188 static int mit_samba_get_pac_data(struct mit_samba_context *ctx,
189                                   hdb_entry_ex *client,
190                                   DATA_BLOB *data)
191 {
192         TALLOC_CTX *tmp_ctx;
193         DATA_BLOB *pac_blob;
194         NTSTATUS nt_status;
195
196         tmp_ctx = talloc_named(ctx, 0, "mit_samba_get_pac_data context");
197         if (!tmp_ctx) {
198                 return ENOMEM;
199         }
200
201         nt_status = samba_kdc_get_pac_blob(tmp_ctx, client, &pac_blob);
202         if (!NT_STATUS_IS_OK(nt_status)) {
203                 talloc_free(tmp_ctx);
204                 return EINVAL;
205         }
206
207         data->data = (uint8_t *)malloc(pac_blob->length);
208         if (!data->data) {
209                 talloc_free(tmp_ctx);
210                 return ENOMEM;
211         }
212         memcpy(data->data, pac_blob->data, pac_blob->length);
213         data->length = pac_blob->length;
214
215         talloc_free(tmp_ctx);
216         return 0;
217 }
218
219 static int mit_samba_update_pac_data(struct mit_samba_context *ctx,
220                                      hdb_entry_ex *client,
221                                      DATA_BLOB *pac_data,
222                                      DATA_BLOB *logon_data)
223 {
224         TALLOC_CTX *tmp_ctx;
225         DATA_BLOB *logon_blob;
226         krb5_error_code code;
227         NTSTATUS nt_status;
228         krb5_pac pac = NULL;
229         int ret;
230
231         /* The user account may be set not to want the PAC */
232         if (client && !samba_princ_needs_pac(client)) {
233                 return EINVAL;
234         }
235
236         tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context");
237         if (!tmp_ctx) {
238                 return ENOMEM;
239         }
240
241         logon_blob = talloc_zero(tmp_ctx, DATA_BLOB);
242         if (!logon_blob) {
243                 ret = ENOMEM;
244                 goto done;
245         }
246
247         code = krb5_pac_parse(ctx->context,
248                               pac_data->data, pac_data->length, &pac);
249         if (code) {
250                 ret = EINVAL;
251                 goto done;
252         }
253
254         nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context,
255                                               &pac, logon_blob);
256         if (!NT_STATUS_IS_OK(nt_status)) {
257                 DEBUG(0, ("Building PAC failed: %s\n",
258                           nt_errstr(nt_status)));
259                 ret = EINVAL;
260                 goto done;
261         }
262
263         logon_data->data = (uint8_t *)malloc(logon_blob->length);
264         if (!logon_data->data) {
265                 ret = ENOMEM;
266                 goto done;
267         }
268         memcpy(logon_data->data, logon_blob->data, logon_blob->length);
269         logon_data->length = logon_blob->length;
270
271         ret = 0;
272
273 done:
274         if (pac) krb5_pac_free(ctx->context, pac);
275         talloc_free(tmp_ctx);
276         return ret;
277 }
278
279 static int mit_samba_check_client_access(struct mit_samba_context *ctx,
280                                          hdb_entry_ex *client,
281                                          const char *client_name,
282                                          hdb_entry_ex *server,
283                                          const char *server_name,
284                                          const char *netbios_name,
285                                          bool password_change,
286                                          DATA_BLOB *e_data)
287 {
288         struct samba_kdc_entry *kdc_entry;
289         NTSTATUS nt_status;
290
291         kdc_entry = talloc_get_type(client->ctx, struct samba_kdc_entry);
292
293         nt_status = samba_kdc_check_client_access(kdc_entry,
294                                                   client_name,
295                                                   netbios_name,
296                                                   password_change);
297
298         if (!NT_STATUS_IS_OK(nt_status)) {
299                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
300                         return ENOMEM;
301                 }
302
303                 samba_kdc_build_edata_reply(nt_status, e_data);
304
305                 return samba_kdc_map_policy_err(nt_status);
306         }
307
308         return 0;
309 }
310
311 static int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
312                                      hdb_entry_ex *entry,
313                                      const char *target_name,
314                                      bool is_nt_enterprise_name)
315 {
316         krb5_principal target_principal;
317         int flags = 0;
318         int ret;
319
320         if (is_nt_enterprise_name) {
321                 flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
322         }
323
324         ret = krb5_parse_name_flags(ctx->context, target_name,
325                                     flags, &target_principal);
326         if (ret) {
327                 return ret;
328         }
329
330         ret = samba_kdc_check_identical_client_and_server(ctx->context,
331                                                           ctx->db_ctx,
332                                                           entry,
333                                                           target_principal);
334
335         krb5_free_principal(ctx->context, target_principal);
336
337         return ret;
338 }
339
340 struct mit_samba_function_table mit_samba_function_table = {
341         mit_samba_context_init,
342         mit_samba_context_free,
343         mit_samba_get_principal,
344         mit_samba_get_firstkey,
345         mit_samba_get_nextkey,
346         mit_samba_get_pac_data,
347         mit_samba_update_pac_data,
348         mit_samba_check_client_access,
349         mit_samba_check_s4u2proxy
350 };