s4-kdc: Move KDC packet handling functions to kdc-server.c
[amitay/samba.git] / source4 / kdc / kdc-heimdal.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    KDC Server startup
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2008
7    Copyright (C) Andrew Tridgell        2005
8    Copyright (C) Stefan Metzmacher      2005
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
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 "smbd/process_model.h"
26 #include "lib/tsocket/tsocket.h"
27 #include "lib/messaging/irpc.h"
28 #include "librpc/gen_ndr/ndr_irpc.h"
29 #include "librpc/gen_ndr/ndr_krb5pac.h"
30 #include "lib/socket/netif.h"
31 #include "param/param.h"
32 #include "kdc/kdc-server.h"
33 #include "kdc/kdc-proxy.h"
34 #include "kdc/kdc-glue.h"
35 #include "kdc/pac-glue.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "auth/session.h"
38 #include "libds/common/roles.h"
39 #include <kdc.h>
40 #include <hdb.h>
41
42 NTSTATUS server_service_kdc_init(void);
43
44 extern struct krb5plugin_windc_ftable windc_plugin_table;
45
46 /**
47    Wrapper for krb5_kdc_process_krb5_request, converting to/from Samba
48    calling conventions
49 */
50
51 static kdc_code kdc_process(struct kdc_server *kdc,
52                             TALLOC_CTX *mem_ctx,
53                             DATA_BLOB *input,
54                             DATA_BLOB *reply,
55                             struct tsocket_address *peer_addr,
56                             struct tsocket_address *my_addr,
57                             int datagram_reply)
58 {
59         int ret;
60         char *pa;
61         struct sockaddr_storage ss;
62         krb5_data k5_reply;
63         krb5_kdc_configuration *kdc_config =
64                 (krb5_kdc_configuration *)kdc->private_data;
65
66         krb5_data_zero(&k5_reply);
67
68         krb5_kdc_update_time(NULL);
69
70         ret = tsocket_address_bsd_sockaddr(peer_addr, (struct sockaddr *) &ss,
71                                 sizeof(struct sockaddr_storage));
72         if (ret < 0) {
73                 return KDC_ERROR;
74         }
75         pa = tsocket_address_string(peer_addr, mem_ctx);
76         if (pa == NULL) {
77                 return KDC_ERROR;
78         }
79
80         DEBUG(10,("Received KDC packet of length %lu from %s\n",
81                                 (long)input->length - 4, pa));
82
83         ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context,
84                                             kdc_config,
85                                             input->data, input->length,
86                                             &k5_reply,
87                                             pa,
88                                             (struct sockaddr *) &ss,
89                                             datagram_reply);
90         if (ret == -1) {
91                 *reply = data_blob(NULL, 0);
92                 return KDC_ERROR;
93         }
94
95         if (ret == HDB_ERR_NOT_FOUND_HERE) {
96                 *reply = data_blob(NULL, 0);
97                 return KDC_PROXY_REQUEST;
98         }
99
100         if (k5_reply.length) {
101                 *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
102                 krb5_data_free(&k5_reply);
103         } else {
104                 *reply = data_blob(NULL, 0);
105         }
106         return KDC_OK;
107 }
108
109 /*
110   setup our listening sockets on the configured network interfaces
111 */
112 static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_context *lp_ctx,
113                                        struct interface *ifaces)
114 {
115         const struct model_ops *model_ops;
116         int num_interfaces;
117         TALLOC_CTX *tmp_ctx = talloc_new(kdc);
118         NTSTATUS status;
119         int i;
120         uint16_t kdc_port = lpcfg_krb5_port(lp_ctx);
121         uint16_t kpasswd_port = lpcfg_kpasswd_port(lp_ctx);
122         bool done_wildcard = false;
123
124         /* within the kdc task we want to be a single process, so
125            ask for the single process model ops and pass these to the
126            stream_setup_socket() call. */
127         model_ops = process_model_startup("single");
128         if (!model_ops) {
129                 DEBUG(0,("Can't find 'single' process model_ops\n"));
130                 return NT_STATUS_INTERNAL_ERROR;
131         }
132
133         num_interfaces = iface_list_count(ifaces);
134
135         /* if we are allowing incoming packets from any address, then
136            we need to bind to the wildcard address */
137         if (!lpcfg_bind_interfaces_only(lp_ctx)) {
138                 int num_binds = 0;
139                 char **wcard = iface_list_wildcard(kdc);
140                 NT_STATUS_HAVE_NO_MEMORY(wcard);
141                 for (i=0; wcard[i]; i++) {
142                         if (kdc_port) {
143                                 status = kdc_add_socket(kdc, model_ops,
144                                                         "kdc", wcard[i], kdc_port,
145                                                         kdc_process, false);
146                                 if (NT_STATUS_IS_OK(status)) {
147                                         num_binds++;
148                                 }
149                         }
150
151                         if (kpasswd_port) {
152                                 status = kdc_add_socket(kdc, model_ops,
153                                                         "kpasswd", wcard[i], kpasswd_port,
154                                                         kpasswdd_process, false);
155                                 if (NT_STATUS_IS_OK(status)) {
156                                         num_binds++;
157                                 }
158                         }
159                 }
160                 talloc_free(wcard);
161                 if (num_binds == 0) {
162                         return NT_STATUS_INVALID_PARAMETER_MIX;
163                 }
164                 done_wildcard = true;
165         }
166
167         for (i=0; i<num_interfaces; i++) {
168                 const char *address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
169
170                 if (kdc_port) {
171                         status = kdc_add_socket(kdc, model_ops,
172                                                 "kdc", address, kdc_port,
173                                                 kdc_process, done_wildcard);
174                         NT_STATUS_NOT_OK_RETURN(status);
175                 }
176
177                 if (kpasswd_port) {
178                         status = kdc_add_socket(kdc, model_ops,
179                                                 "kpasswd", address, kpasswd_port,
180                                                 kpasswdd_process, done_wildcard);
181                         NT_STATUS_NOT_OK_RETURN(status);
182                 }
183         }
184
185         talloc_free(tmp_ctx);
186
187         return NT_STATUS_OK;
188 }
189
190 static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
191                                  struct kdc_check_generic_kerberos *r)
192 {
193         struct PAC_Validate pac_validate;
194         DATA_BLOB srv_sig;
195         struct PAC_SIGNATURE_DATA kdc_sig;
196         struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server);
197         krb5_kdc_configuration *kdc_config =
198                 (krb5_kdc_configuration *)kdc->private_data;
199         enum ndr_err_code ndr_err;
200         int ret;
201         hdb_entry_ex ent;
202         krb5_principal principal;
203
204
205         /* There is no reply to this request */
206         r->out.generic_reply = data_blob(NULL, 0);
207
208         ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, &pac_validate,
209                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
210         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
211                 return NT_STATUS_INVALID_PARAMETER;
212         }
213
214         if (pac_validate.MessageType != NETLOGON_GENERIC_KRB5_PAC_VALIDATE) {
215                 /* We don't implement any other message types - such as certificate validation - yet */
216                 return NT_STATUS_INVALID_PARAMETER;
217         }
218
219         if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength)
220             || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength
221             || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) {
222                 return NT_STATUS_INVALID_PARAMETER;
223         }
224
225         srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
226                                   pac_validate.ChecksumLength);
227
228         ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal,
229                                   lpcfg_realm(kdc->task->lp_ctx),
230                                   "krbtgt", lpcfg_realm(kdc->task->lp_ctx),
231                                   NULL);
232
233         if (ret != 0) {
234                 return NT_STATUS_NO_MEMORY;
235         }
236
237         ret = kdc_config->db[0]->hdb_fetch_kvno(kdc->smb_krb5_context->krb5_context,
238                                                  kdc_config->db[0],
239                                                  principal,
240                                                  HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
241                                                  0,
242                                                  &ent);
243
244         if (ret != 0) {
245                 hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
246                 krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
247
248                 return NT_STATUS_LOGON_FAILURE;
249         }
250
251         kdc_sig.type = pac_validate.SignatureType;
252         kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
253                                             pac_validate.SignatureLength);
254
255         ret = kdc_check_pac(kdc->smb_krb5_context->krb5_context, srv_sig, &kdc_sig, &ent);
256
257         hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
258         krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
259
260         if (ret != 0) {
261                 return NT_STATUS_LOGON_FAILURE;
262         }
263
264         return NT_STATUS_OK;
265 }
266
267
268 /*
269   startup the kdc task
270 */
271 static void kdc_task_init(struct task_server *task)
272 {
273         struct kdc_server *kdc;
274         krb5_kdc_configuration *kdc_config = NULL;
275         NTSTATUS status;
276         krb5_error_code ret;
277         struct interface *ifaces;
278         int ldb_ret;
279
280         switch (lpcfg_server_role(task->lp_ctx)) {
281         case ROLE_STANDALONE:
282                 task_server_terminate(task, "kdc: no KDC required in standalone configuration", false);
283                 return;
284         case ROLE_DOMAIN_MEMBER:
285                 task_server_terminate(task, "kdc: no KDC required in member server configuration", false);
286                 return;
287         case ROLE_DOMAIN_PDC:
288         case ROLE_DOMAIN_BDC:
289                 task_server_terminate(task, "Cannot start KDC as a 'classic Samba' DC", true);
290                 return;
291         case ROLE_ACTIVE_DIRECTORY_DC:
292                 /* Yes, we want a KDC */
293                 break;
294         }
295
296         load_interface_list(task, task->lp_ctx, &ifaces);
297
298         if (iface_list_count(ifaces) == 0) {
299                 task_server_terminate(task, "kdc: no network interfaces configured", false);
300                 return;
301         }
302
303         task_server_set_title(task, "task[kdc]");
304
305         kdc = talloc_zero(task, struct kdc_server);
306         if (kdc == NULL) {
307                 task_server_terminate(task, "kdc: out of memory", true);
308                 return;
309         }
310
311         kdc->task = task;
312
313
314         /* get a samdb connection */
315         kdc->samdb = samdb_connect(kdc, kdc->task->event_ctx, kdc->task->lp_ctx,
316                                    system_session(kdc->task->lp_ctx), 0);
317         if (!kdc->samdb) {
318                 DEBUG(1,("kdc_task_init: unable to connect to samdb\n"));
319                 task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true);
320                 return;
321         }
322
323         ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc);
324         if (ldb_ret != LDB_SUCCESS) {
325                 DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n",
326                           ldb_errstring(kdc->samdb)));
327                 task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true);
328                 return;
329         }
330
331         kdc->proxy_timeout = lpcfg_parm_int(kdc->task->lp_ctx, NULL, "kdc", "proxy timeout", 5);
332
333         initialize_krb5_error_table();
334
335         ret = smb_krb5_init_context(kdc, task->lp_ctx, &kdc->smb_krb5_context);
336         if (ret) {
337                 DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
338                          error_message(ret)));
339                 task_server_terminate(task, "kdc: krb5_init_context failed", true);
340                 return;
341         }
342
343         krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
344
345         ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context,
346                                   &kdc_config);
347         if(ret) {
348                 task_server_terminate(task, "kdc: failed to get KDC configuration", true);
349                 return;
350         }
351
352         kdc_config->logf = (krb5_log_facility *)kdc->smb_krb5_context->pvt_log_data;
353         kdc_config->db = talloc(kdc, struct HDB *);
354         if (!kdc_config->db) {
355                 task_server_terminate(task, "kdc: out of memory", true);
356                 return;
357         }
358         kdc_config->num_db = 1;
359
360         /*
361          * This restores the behavior before
362          * commit 255e3e18e00f717d99f3bc57c8a8895ff624f3c3
363          * s4:heimdal: import lorikeet-heimdal-201107150856
364          * (commit 48936803fae4a2fb362c79365d31f420c917b85b)
365          *
366          * as_use_strongest_session_key,preauth_use_strongest_session_key
367          * and tgs_use_strongest_session_key are input to the
368          * _kdc_find_etype() function. The old bahavior is in
369          * the use_strongest_session_key=FALSE code path.
370          * (The only remaining difference in _kdc_find_etype()
371          *  is the is_preauth parameter.)
372          *
373          * The old behavior in the _kdc_get_preferred_key()
374          * function is use_strongest_server_key=TRUE.
375          */
376         kdc_config->as_use_strongest_session_key = false;
377         kdc_config->preauth_use_strongest_session_key = false;
378         kdc_config->tgs_use_strongest_session_key = false;
379         kdc_config->use_strongest_server_key = true;
380
381         /* Register hdb-samba4 hooks for use as a keytab */
382
383         kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context);
384         if (!kdc->base_ctx) {
385                 task_server_terminate(task, "kdc: out of memory", true);
386                 return;
387         }
388
389         kdc->base_ctx->ev_ctx = task->event_ctx;
390         kdc->base_ctx->lp_ctx = task->lp_ctx;
391
392         status = hdb_samba4_create_kdc(kdc->base_ctx,
393                                        kdc->smb_krb5_context->krb5_context,
394                                        &kdc_config->db[0]);
395         if (!NT_STATUS_IS_OK(status)) {
396                 task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true);
397                 return;
398         }
399
400         ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
401                                    PLUGIN_TYPE_DATA, "hdb",
402                                    &hdb_samba4_interface);
403         if(ret) {
404                 task_server_terminate(task, "kdc: failed to register hdb plugin", true);
405                 return;
406         }
407
408         ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
409         if(ret) {
410                 task_server_terminate(task, "kdc: failed to register keytab plugin", true);
411                 return;
412         }
413
414         /* Register WinDC hooks */
415         ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
416                                    PLUGIN_TYPE_DATA, "windc",
417                                    &windc_plugin_table);
418         if(ret) {
419                 task_server_terminate(task, "kdc: failed to register windc plugin", true);
420                 return;
421         }
422
423         ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
424
425         if(ret) {
426                 task_server_terminate(task, "kdc: failed to init windc plugin", true);
427                 return;
428         }
429
430         ret = krb5_kdc_pkinit_config(kdc->smb_krb5_context->krb5_context, kdc_config);
431
432         if(ret) {
433                 task_server_terminate(task, "kdc: failed to init kdc pkinit subsystem", true);
434                 return;
435         }
436         kdc->private_data = kdc_config;
437
438         /* start listening on the configured network interfaces */
439         status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces);
440         if (!NT_STATUS_IS_OK(status)) {
441                 task_server_terminate(task, "kdc failed to setup interfaces", true);
442                 return;
443         }
444
445         status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS,
446                                kdc_check_generic_kerberos, kdc);
447         if (!NT_STATUS_IS_OK(status)) {
448                 task_server_terminate(task, "kdc failed to setup monitoring", true);
449                 return;
450         }
451
452         irpc_add_name(task->msg_ctx, "kdc_server");
453 }
454
455
456 /* called at smbd startup - register ourselves as a server service */
457 NTSTATUS server_service_kdc_init(void)
458 {
459         return register_server_service("kdc", kdc_task_init);
460 }