r26233: Pass loadparm context when creating krb5 contexts.
[jelmer/samba4-debian.git] / source / kdc / kdc.c
index 2fd5674f79456bcc0d2441b4001ce58a3e94f428..6c1f20bf134a3f32c66b5408be3f56af3eba52b3 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,
@@ -18,8 +18,7 @@
    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 "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 "netif/netif.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 {
@@ -44,12 +51,13 @@ struct kdc_reply {
        DATA_BLOB packet;
 };
 
-typedef BOOL (*kdc_process_fn_t)(struct kdc_server *kdc,
+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);
+                                struct socket_address *my_addr, 
+                                int datagram);
 
 /* hold information about one kdc socket */
 struct kdc_socket {
@@ -87,7 +95,7 @@ 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,
+               status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen,
                                       rep->dest);
                if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
                        break;
@@ -127,14 +135,14 @@ 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,
+       status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread,
                                 tmp_ctx, &src);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(tmp_ctx);
@@ -157,7 +165,8 @@ static void kdc_recv_handler(struct kdc_socket *kdc_socket)
                                  tmp_ctx, 
                                  &blob,  
                                  &reply,
-                                 src, my_addr);
+                                 src, my_addr,
+                                 1 /* Datagram */);
        if (!ret) {
                talloc_free(tmp_ctx);
                return;
@@ -240,7 +249,8 @@ static NTSTATUS kdc_tcp_recv(void *private, DATA_BLOB blob)
                               &input,
                               &reply,
                               src_addr,
-                              my_addr);
+                              my_addr,
+                              0 /* Not datagram */);
        if (!ret) {
                talloc_free(tmp_ctx);
                return NT_STATUS_INTERNAL_ERROR;
@@ -301,15 +311,19 @@ 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,
                        struct socket_address *peer_addr, 
-                       struct socket_address *my_addr)
+                       struct socket_address *my_addr,
+                       int datagram_reply)
 {
        int ret;        
        krb5_data k5_reply;
+       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));
@@ -319,14 +333,19 @@ static BOOL kdc_process(struct kdc_server *kdc,
                                            input->data, input->length,
                                            &k5_reply,
                                            peer_addr->addr,
-                                           peer_addr->sockaddr);
+                                           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;
 }
 
 /*
@@ -389,15 +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);
@@ -498,7 +516,7 @@ 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)
 {
        int num_interfaces = iface_count();
        TALLOC_CTX *tmp_ctx = talloc_new(kdc);
@@ -508,7 +526,8 @@ static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc)
        
        for (i=0; i<num_interfaces; i++) {
                const char *address = talloc_strdup(tmp_ctx, iface_n_ip(i));
-               status = kdc_add_socket(kdc, address);
+               status = kdc_add_socket(kdc, address, lp_krb5_port(lp_ctx), 
+                                       lp_kpasswd_port(lp_ctx));
                NT_STATUS_NOT_OK_RETURN(status);
        }
 
@@ -517,6 +536,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
 */
@@ -526,15 +555,14 @@ static void kdc_task_init(struct task_server *task)
        NTSTATUS status;
        krb5_error_code ret;
 
-       switch (lp_server_role()) {
+       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_PDC:
-       case ROLE_DOMAIN_BDC:
+       case ROLE_DOMAIN_CONTROLLER:
                /* Yes, we want a KDC */
                break;
        }
@@ -554,17 +582,9 @@ static void kdc_task_init(struct task_server *task)
 
        kdc->task = task;
 
-       /* Setup the KDC configuration */
-       kdc->config = talloc(kdc, krb5_kdc_configuration);
-       if (!kdc->config) {
-               task_server_terminate(task, "kdc: out of memory");
-               return;
-       }
-       krb5_kdc_default_config(kdc->config);
-
        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)));
@@ -574,8 +594,15 @@ 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;
@@ -594,8 +621,22 @@ static void kdc_task_init(struct task_server *task)
                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);
        if (!NT_STATUS_IS_OK(status)) {
                task_server_terminate(task, "kdc failed to setup interfaces");
                return;