2ee14f551d6d5f94b5bef5a2f50fc64569c68911
[ira/wip.git] / source4 / kdc / kdc.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/service_task.h"
26 #include "smbd/service.h"
27 #include "smbd/service_stream.h"
28 #include "smbd/process_model.h"
29 #include "lib/events/events.h"
30 #include "lib/socket/socket.h"
31 #include "lib/tsocket/tsocket.h"
32 #include "system/network.h"
33 #include "../lib/util/dlinklist.h"
34 #include "lib/messaging/irpc.h"
35 #include "lib/stream/packet.h"
36 #include "librpc/gen_ndr/samr.h"
37 #include "librpc/gen_ndr/ndr_irpc.h"
38 #include "librpc/gen_ndr/ndr_krb5pac.h"
39 #include "lib/socket/netif.h"
40 #include "param/param.h"
41 #include "kdc/kdc.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43
44
45 /* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when 
46  * used as a keytab */
47 TALLOC_CTX *hdb_samba4_mem_ctx;
48 struct tevent_context *hdb_samba4_ev_ctx;
49 struct loadparm_context *hdb_samba4_lp_ctx;
50
51 typedef bool (*kdc_process_fn_t)(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);
58
59 /* hold information about one kdc socket */
60 struct kdc_socket {
61         struct kdc_server *kdc;
62         struct tsocket_address *local_address;
63         kdc_process_fn_t process;
64 };
65
66 /*
67   state of an open tcp connection
68 */
69 struct kdc_tcp_connection {
70         /* stream connection we belong to */
71         struct stream_connection *conn;
72
73         /* the kdc_server the connection belongs to */
74         struct kdc_server *kdc;
75
76         struct packet_context *packet;
77
78         kdc_process_fn_t process;
79 };
80
81 static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason)
82 {
83         stream_terminate_connection(kdcconn->conn, reason);
84 }
85
86 /*
87   receive a full packet on a KDC connection
88 */
89 static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob)
90 {
91         struct kdc_tcp_connection *kdcconn = talloc_get_type(private_data,
92                                                              struct kdc_tcp_connection);
93         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
94         TALLOC_CTX *tmp_ctx = talloc_new(kdcconn);
95         int ret;
96         DATA_BLOB input, reply;
97         struct socket_address *src_addr;
98         struct socket_address *my_addr;
99         struct tsocket_address *tsrcaddr;
100         struct tsocket_address *tmyaddr;
101
102         talloc_steal(tmp_ctx, blob.data);
103
104         src_addr = socket_get_peer_addr(kdcconn->conn->socket, tmp_ctx);
105         if (!src_addr) {
106                 talloc_free(tmp_ctx);
107                 return NT_STATUS_NO_MEMORY;
108         }
109
110         my_addr = socket_get_my_addr(kdcconn->conn->socket, tmp_ctx);
111         if (!my_addr) {
112                 talloc_free(tmp_ctx);
113                 return NT_STATUS_NO_MEMORY;
114         }
115
116         ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, src_addr->sockaddr,
117                                 src_addr->sockaddrlen, &tsrcaddr);
118         if (ret < 0) {
119                 talloc_free(tmp_ctx);
120                 return NT_STATUS_NO_MEMORY;
121         }
122
123         ret = tsocket_address_bsd_from_sockaddr(tmp_ctx, my_addr->sockaddr,
124                                 my_addr->sockaddrlen, &tmyaddr);
125         if (ret < 0) {
126                 talloc_free(tmp_ctx);
127                 return NT_STATUS_NO_MEMORY;
128         }
129
130         /* Call krb5 */
131         input = data_blob_const(blob.data + 4, blob.length - 4); 
132
133         ret = kdcconn->process(kdcconn->kdc, 
134                                tmp_ctx,
135                                &input,
136                                &reply,
137                                tsrcaddr,
138                                tmyaddr,
139                                0 /* Not datagram */);
140         if (!ret) {
141                 talloc_free(tmp_ctx);
142                 return NT_STATUS_INTERNAL_ERROR;
143         }
144
145         /* and now encode the reply */
146         blob = data_blob_talloc(kdcconn, NULL, reply.length + 4);
147         if (!blob.data) {
148                 talloc_free(tmp_ctx);
149                 return NT_STATUS_NO_MEMORY;
150         }
151
152         RSIVAL(blob.data, 0, reply.length);
153         memcpy(blob.data + 4, reply.data, reply.length);        
154
155         status = packet_send(kdcconn->packet, blob);
156         if (!NT_STATUS_IS_OK(status)) {
157                 talloc_free(tmp_ctx);
158                 return status;
159         }
160
161         /* the call isn't needed any more */
162         talloc_free(tmp_ctx);
163         return NT_STATUS_OK;
164 }
165
166 /*
167   receive some data on a KDC connection
168 */
169 static void kdc_tcp_recv_handler(struct stream_connection *conn, uint16_t flags)
170 {
171         struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
172                                                              struct kdc_tcp_connection);
173         packet_recv(kdcconn->packet);
174 }
175
176 /*
177   called on a tcp recv error
178 */
179 static void kdc_tcp_recv_error(void *private_data, NTSTATUS status)
180 {
181         struct kdc_tcp_connection *kdcconn = talloc_get_type(private_data,
182                                              struct kdc_tcp_connection);
183         kdc_tcp_terminate_connection(kdcconn, nt_errstr(status));
184 }
185
186 /*
187   called when we can write to a connection
188 */
189 static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags)
190 {
191         struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
192                                                              struct kdc_tcp_connection);
193         packet_queue_run(kdcconn->packet);
194 }
195
196 /**
197    Wrapper for krb5_kdc_process_krb5_request, converting to/from Samba
198    calling conventions
199 */
200
201 static bool kdc_process(struct kdc_server *kdc,
202                         TALLOC_CTX *mem_ctx, 
203                         DATA_BLOB *input, 
204                         DATA_BLOB *reply,
205                         struct tsocket_address *peer_addr,
206                         struct tsocket_address *my_addr,
207                         int datagram_reply)
208 {
209         int ret;
210         char *pa;
211         struct sockaddr_storage ss;
212         krb5_data k5_reply;
213         krb5_data_zero(&k5_reply);
214
215         krb5_kdc_update_time(NULL);
216
217         ret = tsocket_address_bsd_sockaddr(peer_addr, (struct sockaddr *) &ss,
218                                 sizeof(struct sockaddr_storage));
219         if (ret < 0) {
220                 return false;
221         }
222         pa = tsocket_address_string(peer_addr, mem_ctx);
223         if (pa == NULL) {
224                 return false;
225         }
226
227         DEBUG(10,("Received KDC packet of length %lu from %s\n",
228                                 (long)input->length - 4, pa));
229
230         ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context, 
231                                             kdc->config,
232                                             input->data, input->length,
233                                             &k5_reply,
234                                             pa,
235                                             (struct sockaddr *) &ss,
236                                             datagram_reply);
237         if (ret == -1) {
238                 *reply = data_blob(NULL, 0);
239                 return false;
240         }
241         if (k5_reply.length) {
242                 *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
243                 krb5_data_free(&k5_reply);
244         } else {
245                 *reply = data_blob(NULL, 0);    
246         }
247         return true;
248 }
249
250 /*
251   called when we get a new connection
252 */
253 static void kdc_tcp_accept(struct stream_connection *conn)
254 {
255         struct kdc_socket *kdc_socket = talloc_get_type(conn->private_data, struct kdc_socket);
256         struct kdc_tcp_connection *kdcconn;
257
258         kdcconn = talloc_zero(conn, struct kdc_tcp_connection);
259         if (!kdcconn) {
260                 stream_terminate_connection(conn, "kdc_tcp_accept: out of memory");
261                 return;
262         }
263         kdcconn->conn    = conn;
264         kdcconn->kdc     = kdc_socket->kdc;
265         kdcconn->process = kdc_socket->process;
266         conn->private_data    = kdcconn;
267
268         kdcconn->packet = packet_init(kdcconn);
269         if (kdcconn->packet == NULL) {
270                 kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory");
271                 return;
272         }
273         packet_set_private(kdcconn->packet, kdcconn);
274         packet_set_socket(kdcconn->packet, conn->socket);
275         packet_set_callback(kdcconn->packet, kdc_tcp_recv);
276         packet_set_full_request(kdcconn->packet, packet_full_request_u32);
277         packet_set_error_handler(kdcconn->packet, kdc_tcp_recv_error);
278         packet_set_event_context(kdcconn->packet, conn->event.ctx);
279         packet_set_fde(kdcconn->packet, conn->event.fde);
280         packet_set_serialise(kdcconn->packet);
281 }
282
283 static const struct stream_server_ops kdc_tcp_stream_ops = {
284         .name                   = "kdc_tcp",
285         .accept_connection      = kdc_tcp_accept,
286         .recv_handler           = kdc_tcp_recv_handler,
287         .send_handler           = kdc_tcp_send
288 };
289
290 /* hold information about one kdc/kpasswd udp socket */
291 struct kdc_udp_socket {
292         struct kdc_socket *kdc_socket;
293         struct tdgram_context *dgram;
294         struct tevent_queue *send_queue;
295 };
296
297 struct kdc_udp_call {
298         struct tsocket_address *src;
299         DATA_BLOB in;
300         DATA_BLOB out;
301 };
302
303 static void kdc_udp_call_sendto_done(struct tevent_req *subreq);
304
305 static void kdc_udp_call_loop(struct tevent_req *subreq)
306 {
307         struct kdc_udp_socket *sock = tevent_req_callback_data(subreq,
308                                       struct kdc_udp_socket);
309         struct kdc_udp_call *call;
310         uint8_t *buf;
311         ssize_t len;
312         int sys_errno;
313         int ret;
314
315         call = talloc(sock, struct kdc_udp_call);
316         if (call == NULL) {
317                 talloc_free(call);
318                 goto done;
319         }
320
321         len = tdgram_recvfrom_recv(subreq, &sys_errno,
322                                    call, &buf, &call->src);
323         TALLOC_FREE(subreq);
324         if (len == -1) {
325                 talloc_free(call);
326                 goto done;
327         }
328
329         call->in.data = buf;
330         call->in.length = len;
331
332         DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n",
333                  (long)call->in.length,
334                  tsocket_address_string(call->src, call)));
335
336         /* Call krb5 */
337         ret = sock->kdc_socket->process(sock->kdc_socket->kdc,
338                                         call,
339                                         &call->in,
340                                         &call->out,
341                                         call->src,
342                                         sock->kdc_socket->local_address,
343                                         1 /* Datagram */);
344         if (!ret) {
345                 talloc_free(call);
346                 goto done;
347         }
348
349         subreq = tdgram_sendto_queue_send(call,
350                                           sock->kdc_socket->kdc->task->event_ctx,
351                                           sock->dgram,
352                                           sock->send_queue,
353                                           call->out.data,
354                                           call->out.length,
355                                           call->src);
356         if (subreq == NULL) {
357                 talloc_free(call);
358                 goto done;
359         }
360         tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call);
361
362 done:
363         subreq = tdgram_recvfrom_send(sock,
364                                       sock->kdc_socket->kdc->task->event_ctx,
365                                       sock->dgram);
366         if (subreq == NULL) {
367                 task_server_terminate(sock->kdc_socket->kdc->task,
368                                       "no memory for tdgram_recvfrom_send",
369                                       true);
370                 return;
371         }
372         tevent_req_set_callback(subreq, kdc_udp_call_loop, sock);
373 }
374
375 static void kdc_udp_call_sendto_done(struct tevent_req *subreq)
376 {
377         struct kdc_udp_call *call = tevent_req_callback_data(subreq,
378                                        struct kdc_udp_call);
379         ssize_t ret;
380         int sys_errno;
381
382         ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
383
384         /* We don't care about errors */
385
386         talloc_free(call);
387 }
388
389 /*
390   start listening on the given address
391 */
392 static NTSTATUS kdc_add_socket(struct kdc_server *kdc,
393                                const struct model_ops *model_ops,
394                                const char *name,
395                                const char *address,
396                                uint16_t port,
397                                kdc_process_fn_t process)
398 {
399         struct kdc_socket *kdc_socket;
400         struct kdc_udp_socket *kdc_udp_socket;
401         struct tevent_req *udpsubreq;
402         NTSTATUS status;
403         int ret;
404
405         kdc_socket = talloc(kdc, struct kdc_socket);
406         NT_STATUS_HAVE_NO_MEMORY(kdc_socket);
407
408         kdc_socket->kdc = kdc;
409         kdc_socket->process = process;
410
411         ret = tsocket_address_inet_from_strings(kdc_socket, "ip",
412                                                 address, port,
413                                                 &kdc_socket->local_address);
414         if (ret != 0) {
415                 status = map_nt_error_from_unix(errno);
416                 return status;
417         }
418
419         status = stream_setup_socket(kdc->task->event_ctx, 
420                                      kdc->task->lp_ctx,
421                                      model_ops, 
422                                      &kdc_tcp_stream_ops, 
423                                      "ip", address, &port, 
424                                      lp_socket_options(kdc->task->lp_ctx), 
425                                      kdc_socket);
426         if (!NT_STATUS_IS_OK(status)) {
427                 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
428                          address, port, nt_errstr(status)));
429                 talloc_free(kdc_socket);
430                 return status;
431         }
432
433         kdc_udp_socket = talloc(kdc_socket, struct kdc_udp_socket);
434         NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket);
435
436         kdc_udp_socket->kdc_socket = kdc_socket;
437
438         ret = tdgram_inet_udp_socket(kdc_socket->local_address,
439                                      NULL,
440                                      kdc_udp_socket,
441                                      &kdc_udp_socket->dgram);
442         if (ret != 0) {
443                 status = map_nt_error_from_unix(errno);
444                 DEBUG(0,("Failed to bind to %s:%u UDP - %s\n",
445                          address, port, nt_errstr(status)));
446                 return status;
447         }
448
449         kdc_udp_socket->send_queue = tevent_queue_create(kdc_udp_socket,
450                                                          "kdc_udp_send_queue");
451         NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket->send_queue);
452
453         udpsubreq = tdgram_recvfrom_send(kdc_udp_socket,
454                                          kdc->task->event_ctx,
455                                          kdc_udp_socket->dgram);
456         NT_STATUS_HAVE_NO_MEMORY(udpsubreq);
457         tevent_req_set_callback(udpsubreq, kdc_udp_call_loop, kdc_udp_socket);
458
459         return NT_STATUS_OK;
460 }
461
462
463 /*
464   setup our listening sockets on the configured network interfaces
465 */
466 static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_context *lp_ctx,
467                                        struct interface *ifaces)
468 {
469         const struct model_ops *model_ops;
470         int num_interfaces;
471         TALLOC_CTX *tmp_ctx = talloc_new(kdc);
472         NTSTATUS status;
473         int i;
474
475         /* within the kdc task we want to be a single process, so
476            ask for the single process model ops and pass these to the
477            stream_setup_socket() call. */
478         model_ops = process_model_startup(kdc->task->event_ctx, "single");
479         if (!model_ops) {
480                 DEBUG(0,("Can't find 'single' process model_ops\n"));
481                 return NT_STATUS_INTERNAL_ERROR;
482         }
483
484         num_interfaces = iface_count(ifaces);
485         
486         for (i=0; i<num_interfaces; i++) {
487                 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
488                 uint16_t kdc_port = lp_krb5_port(lp_ctx);
489                 uint16_t kpasswd_port = lp_kpasswd_port(lp_ctx);
490
491                 if (kdc_port) {
492                         status = kdc_add_socket(kdc, model_ops,
493                                         "kdc", address, kdc_port,
494                                         kdc_process);
495                         NT_STATUS_NOT_OK_RETURN(status);
496                 }
497
498                 if (kpasswd_port) {
499                         status = kdc_add_socket(kdc, model_ops,
500                                         "kpasswd", address, kpasswd_port,
501                                         kpasswdd_process);
502                         NT_STATUS_NOT_OK_RETURN(status);
503                 }
504         }
505
506         talloc_free(tmp_ctx);
507
508         return NT_STATUS_OK;
509 }
510
511
512 static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, 
513                                  struct kdc_check_generic_kerberos *r)
514 {
515         struct PAC_Validate pac_validate;
516         DATA_BLOB srv_sig;
517         struct PAC_SIGNATURE_DATA kdc_sig;
518         struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server);
519         enum ndr_err_code ndr_err;
520         krb5_enctype etype;
521         int ret;
522         hdb_entry_ex ent;
523         krb5_principal principal;
524         krb5_keyblock keyblock;
525         Key *key;
526
527         /* There is no reply to this request */
528         r->out.generic_reply = data_blob(NULL, 0);
529
530         ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, 
531                                        lp_iconv_convenience(kdc->task->lp_ctx), 
532                                        &pac_validate,
533                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
534         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
535                 return NT_STATUS_INVALID_PARAMETER;
536         }
537         
538         if (pac_validate.MessageType != 3) {
539                 /* We don't implement any other message types - such as certificate validation - yet */
540                 return NT_STATUS_INVALID_PARAMETER;
541         }
542
543         if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength)
544             || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength
545             || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) {
546                 return NT_STATUS_INVALID_PARAMETER;
547         }
548         
549         srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, 
550                                   pac_validate.ChecksumLength);
551         
552         if (pac_validate.SignatureType == CKSUMTYPE_HMAC_MD5) {
553                 etype = ETYPE_ARCFOUR_HMAC_MD5;
554         } else {
555                 ret = krb5_cksumtype_to_enctype(kdc->smb_krb5_context->krb5_context, pac_validate.SignatureType,
556                                                 &etype);
557                 if (ret != 0) {
558                         return NT_STATUS_LOGON_FAILURE;
559                 }
560         }
561
562         ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal, 
563                                   lp_realm(kdc->task->lp_ctx),
564                                   "krbtgt", lp_realm(kdc->task->lp_ctx), 
565                                   NULL);
566
567         if (ret != 0) {
568                 return NT_STATUS_NO_MEMORY;
569         }
570
571         ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context, 
572                                             kdc->config->db[0],
573                                             principal,
574                                             HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
575                                             &ent);
576
577         if (ret != 0) {
578                 hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
579                 krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
580         
581                 return NT_STATUS_LOGON_FAILURE;
582         }
583         
584         ret = hdb_enctype2key(kdc->smb_krb5_context->krb5_context, &ent.entry, etype, &key);
585
586         if (ret != 0) {
587                 hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
588                 krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
589                 return NT_STATUS_LOGON_FAILURE;
590         }
591
592         keyblock = key->key;
593         
594         kdc_sig.type = pac_validate.SignatureType;
595         kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
596                                             pac_validate.SignatureLength);
597         ret = check_pac_checksum(msg, srv_sig, &kdc_sig, 
598                            kdc->smb_krb5_context->krb5_context, &keyblock);
599
600         hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
601         krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
602
603         if (ret != 0) {
604                 return NT_STATUS_LOGON_FAILURE;
605         }
606         
607         return NT_STATUS_OK;
608 }
609
610
611 /*
612   startup the kdc task
613 */
614 static void kdc_task_init(struct task_server *task)
615 {
616         struct kdc_server *kdc;
617         NTSTATUS status;
618         krb5_error_code ret;
619         struct interface *ifaces;
620
621         switch (lp_server_role(task->lp_ctx)) {
622         case ROLE_STANDALONE:
623                 task_server_terminate(task, "kdc: no KDC required in standalone configuration", false);
624                 return;
625         case ROLE_DOMAIN_MEMBER:
626                 task_server_terminate(task, "kdc: no KDC required in member server configuration", false);
627                 return;
628         case ROLE_DOMAIN_CONTROLLER:
629                 /* Yes, we want a KDC */
630                 break;
631         }
632
633         load_interfaces(task, lp_interfaces(task->lp_ctx), &ifaces);
634
635         if (iface_count(ifaces) == 0) {
636                 task_server_terminate(task, "kdc: no network interfaces configured", false);
637                 return;
638         }
639
640         task_server_set_title(task, "task[kdc]");
641
642         kdc = talloc(task, struct kdc_server);
643         if (kdc == NULL) {
644                 task_server_terminate(task, "kdc: out of memory", true);
645                 return;
646         }
647
648         kdc->task = task;
649
650         initialize_krb5_error_table();
651
652         ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context);
653         if (ret) {
654                 DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", 
655                          error_message(ret)));
656                 task_server_terminate(task, "kdc: krb5_init_context failed", true);
657                 return; 
658         }
659
660         krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
661
662         ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, 
663                                   &kdc->config);
664         if(ret) {
665                 task_server_terminate(task, "kdc: failed to get KDC configuration", true);
666                 return;
667         }
668  
669         kdc->config->logf = kdc->smb_krb5_context->logf;
670         kdc->config->db = talloc(kdc, struct HDB *);
671         if (!kdc->config->db) {
672                 task_server_terminate(task, "kdc: out of memory", true);
673                 return;
674         }
675         kdc->config->num_db = 1;
676                 
677         status = hdb_samba4_create_kdc(kdc, task->event_ctx, task->lp_ctx, 
678                                        kdc->smb_krb5_context->krb5_context, 
679                                        &kdc->config->db[0]);
680         if (!NT_STATUS_IS_OK(status)) {
681                 task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true);
682                 return; 
683         }
684
685         /* Register hdb-samba4 hooks for use as a keytab */
686
687         kdc->hdb_samba4_context = talloc(kdc, struct hdb_samba4_context);
688         if (!kdc->hdb_samba4_context) {
689                 task_server_terminate(task, "kdc: out of memory", true);
690                 return; 
691         }
692
693         kdc->hdb_samba4_context->ev_ctx = task->event_ctx;
694         kdc->hdb_samba4_context->lp_ctx = task->lp_ctx;
695
696         ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 
697                                    PLUGIN_TYPE_DATA, "hdb",
698                                    &hdb_samba4);
699         if(ret) {
700                 task_server_terminate(task, "kdc: failed to register hdb keytab", true);
701                 return;
702         }
703
704         ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
705         if(ret) {
706                 task_server_terminate(task, "kdc: failed to register hdb keytab", true);
707                 return;
708         }
709
710         /* Registar WinDC hooks */
711         ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 
712                                    PLUGIN_TYPE_DATA, "windc",
713                                    &windc_plugin_table);
714         if(ret) {
715                 task_server_terminate(task, "kdc: failed to register hdb keytab", true);
716                 return;
717         }
718
719         krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
720
721         /* start listening on the configured network interfaces */
722         status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces);
723         if (!NT_STATUS_IS_OK(status)) {
724                 task_server_terminate(task, "kdc failed to setup interfaces", true);
725                 return;
726         }
727
728         status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, 
729                                kdc_check_generic_kerberos, kdc);
730         if (!NT_STATUS_IS_OK(status)) {
731                 task_server_terminate(task, "nbtd failed to setup monitoring", true);
732                 return;
733         }
734
735         irpc_add_name(task->msg_ctx, "kdc_server");
736 }
737
738
739 /* called at smbd startup - register ourselves as a server service */
740 NTSTATUS server_service_kdc_init(void)
741 {
742         return register_server_service("kdc", kdc_task_init);
743 }