Rework service init functions to pass down service name. This is
[ira/wip.git] / source / kdc / kdc.c
index a79dc8457e6f3d0cf507cf5a63e5a00509c2e773..d820f0abe97668b14f304d9c3e908591745bf11b 100644 (file)
@@ -9,7 +9,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "smbd/service_task.h"
+#include "smbd/service.h"
 #include "smbd/service_stream.h"
+#include "smbd/process_model.h"
 #include "lib/events/events.h"
 #include "lib/socket/socket.h"
 #include "kdc/kdc.h"
 #include "system/network.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
 #include "lib/messaging/irpc.h"
 #include "lib/stream/packet.h"
+#include "librpc/gen_ndr/samr.h"
+#include "lib/socket/netif.h"
+#include "heimdal/kdc/windc_plugin.h"
+#include "heimdal/lib/krb5/krb5_locl.h"
+#include "heimdal/kdc/kdc_locl.h"
+#include "param/param.h"
+
+
+/* Disgusting hack to get a mem_ctx into the hdb plugin, when used as a keytab */
+TALLOC_CTX *kdc_mem_ctx;
 
 /* hold all the info needed to send a reply */
 struct kdc_reply {
        struct kdc_reply *next, *prev;
-       const char *dest_address;
-       int dest_port;
+       struct socket_address *dest;
        DATA_BLOB packet;
 };
 
+typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc,
+                                TALLOC_CTX *mem_ctx, 
+                                DATA_BLOB *input, 
+                                DATA_BLOB *reply,
+                                struct socket_address *peer_addr, 
+                                struct socket_address *my_addr, 
+                                int datagram);
+
 /* hold information about one kdc socket */
 struct kdc_socket {
        struct socket_context *sock;
@@ -50,12 +68,7 @@ struct kdc_socket {
        /* a queue of outgoing replies that have been deferred */
        struct kdc_reply *send_queue;
 
-       BOOL (*process)(struct kdc_server *kdc,
-                       TALLOC_CTX *mem_ctx, 
-                       DATA_BLOB *input, 
-                       DATA_BLOB *reply,
-                       const char *from,
-                       int src_port);
+       kdc_process_fn_t process;
 };
 /*
   state of an open tcp connection
@@ -69,12 +82,7 @@ struct kdc_tcp_connection {
 
        struct packet_context *packet;
 
-       BOOL (*process)(struct kdc_server *kdc,
-                        TALLOC_CTX *mem_ctx, 
-                        DATA_BLOB *input, 
-                        DATA_BLOB *reply,
-                        const char *from,
-                        int src_port);
+       kdc_process_fn_t process;
 };
 
 /*
@@ -87,8 +95,8 @@ static void kdc_send_handler(struct kdc_socket *kdc_socket)
                NTSTATUS status;
                size_t sendlen;
 
-               status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen, 0,
-                                      rep->dest_address, rep->dest_port);
+               status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen,
+                                      rep->dest);
                if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
                        break;
                }
@@ -117,8 +125,8 @@ static void kdc_recv_handler(struct kdc_socket *kdc_socket)
        struct kdc_reply *rep;
        DATA_BLOB reply;
        size_t nread, dsize;
-       const char *src_addr;
-       int src_port;
+       struct socket_address *src;
+       struct socket_address *my_addr;
        int ret;
 
        status = socket_pending(kdc_socket->sock, &dsize);
@@ -127,31 +135,38 @@ static void kdc_recv_handler(struct kdc_socket *kdc_socket)
                return;
        }
 
-       blob = data_blob_talloc(kdc_socket, NULL, dsize);
+       blob = data_blob_talloc(tmp_ctx, NULL, dsize);
        if (blob.data == NULL) {
                /* hope this is a temporary low memory condition */
                talloc_free(tmp_ctx);
                return;
        }
 
-       status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread, 0,
-                                &src_addr, &src_port);
+       status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread,
+                                tmp_ctx, &src);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(tmp_ctx);
                return;
        }
-       talloc_steal(tmp_ctx, src_addr);
        blob.length = nread;
        
-       DEBUG(2,("Received krb5 UDP packet of length %u from %s:%u\n", 
-                blob.length, src_addr, (uint16_t)src_port));
+       DEBUG(10,("Received krb5 UDP packet of length %lu from %s:%u\n", 
+                (long)blob.length, src->addr, (uint16_t)src->port));
        
+       my_addr = socket_get_my_addr(kdc_socket->sock, tmp_ctx);
+       if (!my_addr) {
+               talloc_free(tmp_ctx);
+               return;
+       }
+
+
        /* Call krb5 */
        ret = kdc_socket->process(kdc_socket->kdc, 
                                  tmp_ctx, 
                                  &blob,  
                                  &reply,
-                                 src_addr, src_port);
+                                 src, my_addr,
+                                 1 /* Datagram */);
        if (!ret) {
                talloc_free(tmp_ctx);
                return;
@@ -163,8 +178,7 @@ static void kdc_recv_handler(struct kdc_socket *kdc_socket)
                talloc_free(tmp_ctx);
                return;
        }
-       rep->dest_address = talloc_steal(rep, src_addr);
-       rep->dest_port    = src_port;
+       rep->dest         = talloc_steal(rep, src);
        rep->packet       = reply;
        talloc_steal(rep, reply.data);
 
@@ -204,22 +218,28 @@ static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, con
 */
 static NTSTATUS kdc_tcp_recv(void *private, DATA_BLOB blob)
 {
-       struct kdc_tcp_connection *kdcconn = talloc_get_type(private, struct kdc_tcp_connection);
+       struct kdc_tcp_connection *kdcconn = talloc_get_type(private, 
+                                                            struct kdc_tcp_connection);
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
        TALLOC_CTX *tmp_ctx = talloc_new(kdcconn);
-       const char *src_addr;
-       int src_port;
        int ret;
        DATA_BLOB input, reply;
+       struct socket_address *src_addr;
+       struct socket_address *my_addr;
 
        talloc_steal(tmp_ctx, blob.data);
 
        src_addr = socket_get_peer_addr(kdcconn->conn->socket, tmp_ctx);
-       if (!src_addr) goto nomem;
-       src_port = socket_get_peer_port(kdcconn->conn->socket);
+       if (!src_addr) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       DEBUG(2,("Received krb5 TCP packet of length %u from %s:%u\n", 
-                blob.length - 4, src_addr, src_port));
+       my_addr = socket_get_my_addr(kdcconn->conn->socket, tmp_ctx);
+       if (!my_addr) {
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* Call krb5 */
        input = data_blob_const(blob.data + 4, blob.length - 4); 
@@ -228,16 +248,19 @@ static NTSTATUS kdc_tcp_recv(void *private, DATA_BLOB blob)
                               tmp_ctx,
                               &input,
                               &reply,
-                              src_addr, src_port);
+                              src_addr,
+                              my_addr,
+                              0 /* Not datagram */);
        if (!ret) {
-               status = NT_STATUS_INTERNAL_ERROR;
-               goto failed;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_INTERNAL_ERROR;
        }
 
        /* and now encode the reply */
        blob = data_blob_talloc(kdcconn, NULL, reply.length + 4);
        if (!blob.data) {
-               goto nomem;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
        }
 
        RSIVAL(blob.data, 0, reply.length);
@@ -245,18 +268,13 @@ static NTSTATUS kdc_tcp_recv(void *private, DATA_BLOB blob)
 
        status = packet_send(kdcconn->packet, blob);
        if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
+               talloc_free(tmp_ctx);
+               return status;
        }
 
        /* the call isn't needed any more */
        talloc_free(tmp_ctx);
        return NT_STATUS_OK;
-nomem:
-       status = NT_STATUS_NO_MEMORY;
-
-failed:
-       kdc_tcp_terminate_connection(kdcconn, nt_errstr(status));
-       return NT_STATUS_OK;
 }
 
 /*
@@ -293,48 +311,47 @@ static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags)
    calling conventions
 */
 
-static BOOL kdc_process(struct kdc_server *kdc,
+static bool kdc_process(struct kdc_server *kdc,
                        TALLOC_CTX *mem_ctx, 
                        DATA_BLOB *input, 
                        DATA_BLOB *reply,
-                       const char *src_addr,
-                       int src_port)
+                       struct socket_address *peer_addr, 
+                       struct socket_address *my_addr,
+                       int datagram_reply)
 {
        int ret;        
        krb5_data k5_reply;
-       struct ipv4_addr addr;
-       struct sockaddr_in src_sock_addr;
-
-       /* TODO:  This really should be in a utility function somewhere */
-       ZERO_STRUCT(src_sock_addr);
-#ifdef HAVE_SOCK_SIN_LEN
-       src_sock_addr.sin_len           = sizeof(src_sock_addr);
-#endif
-       addr                            = interpret_addr2(src_addr);
-       src_sock_addr.sin_addr.s_addr   = addr.addr;
-       src_sock_addr.sin_port          = htons(src_port);
-       src_sock_addr.sin_family        = PF_INET;
+       krb5_data_zero(&k5_reply);
+
+       krb5_kdc_update_time(NULL);
+
+       DEBUG(10,("Received KDC packet of length %lu from %s:%d\n", 
+                 (long)input->length - 4, peer_addr->addr, peer_addr->port));
 
-       
        ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context, 
                                            kdc->config,
                                            input->data, input->length,
                                            &k5_reply,
-                                           src_addr,
-                                           (struct sockaddr *)&src_sock_addr);
+                                           peer_addr->addr,
+                                           peer_addr->sockaddr,
+                                           datagram_reply);
        if (ret == -1) {
                *reply = data_blob(NULL, 0);
-               return False;
+               return false;
        }
-       *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
-       krb5_data_free(&k5_reply);
-       return True;
+       if (k5_reply.length) {
+               *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
+               krb5_free_data_contents(kdc->smb_krb5_context->krb5_context, &k5_reply);
+       } else {
+               *reply = data_blob(NULL, 0);    
+       }
+       return true;
 }
 
 /*
   called when we get a new connection
 */
-static void kdc_tcp_accept(struct stream_connection *conn)
+static void kdc_tcp_generic_accept(struct stream_connection *conn, kdc_process_fn_t process_fn)
 {
        struct kdc_server *kdc = talloc_get_type(conn->private, struct kdc_server);
        struct kdc_tcp_connection *kdcconn;
@@ -346,12 +363,12 @@ static void kdc_tcp_accept(struct stream_connection *conn)
        }
        kdcconn->conn    = conn;
        kdcconn->kdc     = kdc;
-       kdcconn->process = kdc_process;
+       kdcconn->process = process_fn;
        conn->private    = kdcconn;
 
        kdcconn->packet = packet_init(kdcconn);
        if (kdcconn->packet == NULL) {
-               stream_terminate_connection(conn, "kdc_tcp_accept: out of memory");
+               kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory");
                return;
        }
        packet_set_private(kdcconn->packet, kdcconn);
@@ -360,7 +377,13 @@ static void kdc_tcp_accept(struct stream_connection *conn)
        packet_set_full_request(kdcconn->packet, packet_full_request_u32);
        packet_set_error_handler(kdcconn->packet, kdc_tcp_recv_error);
        packet_set_event_context(kdcconn->packet, conn->event.ctx);
-       packet_set_serialise(kdcconn->packet, conn->event.fde);
+       packet_set_fde(kdcconn->packet, conn->event.fde);
+       packet_set_serialise(kdcconn->packet);
+}
+
+static void kdc_tcp_accept(struct stream_connection *conn)
+{
+       kdc_tcp_generic_accept(conn, kdc_process);
 }
 
 static const struct stream_server_ops kdc_tcp_stream_ops = {
@@ -370,23 +393,9 @@ static const struct stream_server_ops kdc_tcp_stream_ops = {
        .send_handler           = kdc_tcp_send
 };
 
-/*
-  called when we get a new connection
-*/
-void kpasswdd_tcp_accept(struct stream_connection *conn)
+static void kpasswdd_tcp_accept(struct stream_connection *conn)
 {
-       struct kdc_server *kdc = talloc_get_type(conn->private, struct kdc_server);
-       struct kdc_tcp_connection *kdcconn;
-
-       kdcconn = talloc_zero(conn, struct kdc_tcp_connection);
-       if (!kdcconn) {
-               stream_terminate_connection(conn, "kdc_tcp_accept: out of memory");
-               return;
-       }
-       kdcconn->conn    = conn;
-       kdcconn->kdc     = kdc;
-       kdcconn->process = kpasswdd_process;
-       conn->private    = kdcconn;
+       kdc_tcp_generic_accept(conn, kpasswdd_process);
 }
 
 static const struct stream_server_ops kpasswdd_tcp_stream_ops = {
@@ -399,14 +408,14 @@ static const struct stream_server_ops kpasswdd_tcp_stream_ops = {
 /*
   start listening on the given address
 */
-static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address)
+static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address,
+                              uint16_t kdc_port, uint16_t kpasswd_port)
 {
        const struct model_ops *model_ops;
        struct kdc_socket *kdc_socket;
        struct kdc_socket *kpasswd_socket;
+       struct socket_address *kdc_address, *kpasswd_address;
        NTSTATUS status;
-       uint16_t kdc_port = lp_krb5_port();
-       uint16_t kpasswd_port = lp_kpasswd_port();
 
        kdc_socket = talloc(kdc, struct kdc_socket);
        NT_STATUS_HAVE_NO_MEMORY(kdc_socket);
@@ -436,7 +445,11 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address)
                                       socket_get_fd(kdc_socket->sock), EVENT_FD_READ,
                                       kdc_socket_handler, kdc_socket);
 
-       status = socket_listen(kdc_socket->sock, address, kdc_port, 0, 0);
+       kdc_address = socket_address_from_strings(kdc_socket, kdc_socket->sock->backend_name, 
+                                                 address, kdc_port);
+       NT_STATUS_HAVE_NO_MEMORY(kdc_address);
+
+       status = socket_listen(kdc_socket->sock, kdc_address, 0, 0);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("Failed to bind to %s:%d UDP for kdc - %s\n", 
                         address, kdc_port, nt_errstr(status)));
@@ -454,7 +467,11 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address)
                                           socket_get_fd(kpasswd_socket->sock), EVENT_FD_READ,
                                           kdc_socket_handler, kpasswd_socket);
        
-       status = socket_listen(kpasswd_socket->sock, address, kpasswd_port, 0, 0);
+       kpasswd_address = socket_address_from_strings(kpasswd_socket, kpasswd_socket->sock->backend_name, 
+                                                     address, kpasswd_port);
+       NT_STATUS_HAVE_NO_MEMORY(kpasswd_address);
+
+       status = socket_listen(kpasswd_socket->sock, kpasswd_address, 0, 0);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("Failed to bind to %s:%d UDP for kpasswd - %s\n", 
                         address, kpasswd_port, nt_errstr(status)));
@@ -472,9 +489,13 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address)
                return NT_STATUS_INTERNAL_ERROR;
        }
 
-       status = stream_setup_socket(kdc->task->event_ctx, model_ops, 
+       status = stream_setup_socket(kdc->task->event_ctx, 
+                                    kdc->task->lp_ctx,
+                                    model_ops, 
                                     &kdc_tcp_stream_ops, 
-                                    "ip", address, &kdc_port, kdc);
+                                    "ip", address, &kdc_port, 
+                                    lp_socket_options(kdc->task->lp_ctx), 
+                                    kdc);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
                         address, kdc_port, nt_errstr(status)));
@@ -482,9 +503,13 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address)
                return status;
        }
 
-       status = stream_setup_socket(kdc->task->event_ctx, model_ops, 
+       status = stream_setup_socket(kdc->task->event_ctx, 
+                                    kdc->task->lp_ctx,
+                                    model_ops, 
                                     &kpasswdd_tcp_stream_ops, 
-                                    "ip", address, &kpasswd_port, kdc);
+                                    "ip", address, &kpasswd_port, 
+                                    lp_socket_options(kdc->task->lp_ctx), 
+                                    kdc);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
                         address, kpasswd_port, nt_errstr(status)));
@@ -499,25 +524,21 @@ static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address)
 /*
   setup our listening sockets on the configured network interfaces
 */
-static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc)
+static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_context *lp_ctx,
+                                      struct interface *ifaces)
 {
-       int num_interfaces = iface_count();
+       int num_interfaces;
        TALLOC_CTX *tmp_ctx = talloc_new(kdc);
        NTSTATUS status;
+       int i;
 
-       /* if we are allowing incoming packets from any address, then
-          we need to bind to the wildcard address */
-       if (!lp_bind_interfaces_only()) {
-               status = kdc_add_socket(kdc, "0.0.0.0");
+       num_interfaces = iface_count(ifaces);
+       
+       for (i=0; i<num_interfaces; i++) {
+               const char *address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
+               status = kdc_add_socket(kdc, address, lp_krb5_port(lp_ctx), 
+                                       lp_kpasswd_port(lp_ctx));
                NT_STATUS_NOT_OK_RETURN(status);
-       } else {
-               int i;
-
-               for (i=0; i<num_interfaces; i++) {
-                       const char *address = talloc_strdup(tmp_ctx, iface_n_ip(i));
-                       status = kdc_add_socket(kdc, address);
-                       NT_STATUS_NOT_OK_RETURN(status);
-               }
        }
 
        talloc_free(tmp_ctx);
@@ -525,6 +546,16 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc)
        return NT_STATUS_OK;
 }
 
+static struct krb5plugin_windc_ftable windc_plugin_table = {
+       .minor_version = KRB5_WINDC_PLUGING_MINOR,
+       .init = samba_kdc_plugin_init,
+       .fini = samba_kdc_plugin_fini,
+       .pac_generate = samba_kdc_get_pac,
+       .pac_verify = samba_kdc_reget_pac,
+       .client_access = samba_kdc_check_client_access,
+};
+
+
 /*
   startup the kdc task
 */
@@ -533,34 +564,40 @@ static void kdc_task_init(struct task_server *task)
        struct kdc_server *kdc;
        NTSTATUS status;
        krb5_error_code ret;
+       struct interface *ifaces;
 
-       if (iface_count() == 0) {
-               task_server_terminate(task, "kdc: no network interfaces configured");
+       switch (lp_server_role(task->lp_ctx)) {
+       case ROLE_STANDALONE:
+               task_server_terminate(task, "kdc: no KDC required in standalone configuration");
                return;
+       case ROLE_DOMAIN_MEMBER:
+               task_server_terminate(task, "kdc: no KDC required in member server configuration");
+               return;
+       case ROLE_DOMAIN_CONTROLLER:
+               /* Yes, we want a KDC */
+               break;
        }
 
-       kdc = talloc(task, struct kdc_server);
-       if (kdc == NULL) {
-               task_server_terminate(task, "kdc: out of memory");
+       load_interfaces(task, lp_interfaces(task->lp_ctx), &ifaces);
+
+       if (iface_count(ifaces) == 0) {
+               task_server_terminate(task, "kdc: no network interfaces configured");
                return;
        }
 
-       kdc->task = task;
+       task_server_set_title(task, "task[kdc]");
 
-       /* Setup the KDC configuration */
-       kdc->config = talloc(kdc, krb5_kdc_configuration);
-       if (!kdc->config) {
+       kdc = talloc(task, struct kdc_server);
+       if (kdc == NULL) {
                task_server_terminate(task, "kdc: out of memory");
                return;
        }
-       krb5_kdc_default_config(kdc->config);
 
-       /* NAT and the like make this pointless, and painful */
-       kdc->config->check_ticket_addresses = FALSE;
+       kdc->task = task;
 
        initialize_krb5_error_table();
 
-       ret = smb_krb5_init_context(kdc, &kdc->smb_krb5_context);
+       ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context);
        if (ret) {
                DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", 
                         error_message(ret)));
@@ -570,25 +607,50 @@ static void kdc_task_init(struct task_server *task)
 
        krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
 
+       ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, 
+                                 &kdc->config);
+       if(ret) {
+               task_server_terminate(task, "kdc: failed to get KDC configuration");
+               return;
+       }
+
        kdc->config->logf = kdc->smb_krb5_context->logf;
-       kdc->config->db = talloc(kdc->config, struct HDB *);
+       kdc->config->db = talloc(kdc, struct HDB *);
        if (!kdc->config->db) {
                task_server_terminate(task, "kdc: out of memory");
                return;
        }
        kdc->config->num_db = 1;
                
-       ret = hdb_ldb_create(kdc, kdc->smb_krb5_context->krb5_context, 
-                            &kdc->config->db[0], NULL);
-       if (ret != 0) {
-               DEBUG(1, ("kdc_task_init: hdb_ldb_create fails: %s\n", 
-                         smb_get_krb5_error_message(kdc->smb_krb5_context->krb5_context, ret, kdc))); 
-               task_server_terminate(task, "kdc: hdb_ldb_create failed");
+       status = kdc_hdb_ldb_create(kdc, task->lp_ctx, 
+                                   kdc->smb_krb5_context->krb5_context, 
+                                   &kdc->config->db[0], NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               task_server_terminate(task, "kdc: hdb_ldb_create (setup KDC database) failed");
                return; 
        }
 
+       ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
+       if(ret) {
+               task_server_terminate(task, "kdc: failed to register hdb keytab");
+               return;
+       }
+
+       /* Registar WinDC hooks */
+       ret = _krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 
+                                   PLUGIN_TYPE_DATA, "windc",
+                                   &windc_plugin_table);
+       if(ret) {
+               task_server_terminate(task, "kdc: failed to register hdb keytab");
+               return;
+       }
+
+       krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
+
+       kdc_mem_ctx = kdc->smb_krb5_context;
+
        /* start listening on the configured network interfaces */
-       status = kdc_startup_interfaces(kdc);
+       status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces);
        if (!NT_STATUS_IS_OK(status)) {
                task_server_terminate(task, "kdc failed to setup interfaces");
                return;
@@ -602,9 +664,10 @@ static void kdc_task_init(struct task_server *task)
   called on startup of the KDC service 
 */
 static NTSTATUS kdc_init(struct event_context *event_ctx, 
+                        struct loadparm_context *lp_ctx,
                         const struct model_ops *model_ops)
 {      
-       return task_server_startup(event_ctx, model_ops, kdc_task_init);
+       return task_server_startup(event_ctx, lp_ctx, "kdc", model_ops, kdc_task_init);
 }
 
 /* called at smbd startup - register ourselves as a server service */