r2321: add complately untested LDAP server start
authorStefan Metzmacher <metze@samba.org>
Mon, 13 Sep 2004 10:36:59 +0000 (10:36 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:58:43 +0000 (12:58 -0500)
based on volker's patch

this is compiled by default but not started by default

metze
(This used to be commit 5387bc423d4dc669cbac6626f8dd3a5498a6519d)

source4/configure.in
source4/include/includes.h
source4/ldap_server/config.m4 [new file with mode: 0644]
source4/ldap_server/config.mk [new file with mode: 0644]
source4/ldap_server/ldap_server.c [new file with mode: 0644]
source4/ldap_server/ldap_server.h [new file with mode: 0644]
source4/smbd/config.m4
source4/smbd/config.mk
source4/smbd/service.c

index 00e7662f03a7c8b46eccd67fc576133b402dc56b..eccdc1be6ebc46f561ad27fd6fc8b1a74b7ffb67 100644 (file)
@@ -27,6 +27,7 @@ SMB_INCLUDE_M4(libcli/libsmb.m4)
 SMB_INCLUDE_M4(libnet/config.m4)
 SMB_INCLUDE_M4(smbd/process_model.m4)
 SMB_INCLUDE_M4(smb_server/config.m4)
+SMB_INCLUDE_M4(ldap_server/config.m4)
 SMB_INCLUDE_M4(auth/config.m4)
 SMB_INCLUDE_M4(ntvfs/config.m4)
 SMB_INCLUDE_M4(rpc_server/config.m4)
index 7ea85b4fb94fa6a9d56065ac5d887040f46ff5aa..33806ab36f97a87c0521435085dc0c87282e7dcf 100644 (file)
@@ -668,6 +668,7 @@ extern int errno;
 #include "cli_context.h"
 #include "registry.h"
 #include "rap.h"
+#include "ldap_server/ldap_server.h"
 #include "gtk/common/gtk-smb.h"
 #include "gtk/common/select.h"
 
diff --git a/source4/ldap_server/config.m4 b/source4/ldap_server/config.m4
new file mode 100644 (file)
index 0000000..b702493
--- /dev/null
@@ -0,0 +1,3 @@
+dnl # LDAP server subsystem
+
+SMB_SUBSYSTEM_MK(LDAP,ldap_server/config.mk)
diff --git a/source4/ldap_server/config.mk b/source4/ldap_server/config.mk
new file mode 100644 (file)
index 0000000..4e51906
--- /dev/null
@@ -0,0 +1,11 @@
+# LDAP server subsystem
+
+#######################
+# Start SUBSYSTEM LDAP
+[SUBSYSTEM::LDAP]
+INIT_OBJ_FILES = \
+               ldap_server/ldap_server.o
+REQUIRED_SUBSYSTEMS = \
+               LIBCLI_LDAP
+# End SUBSYSTEM SMB
+#######################
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
new file mode 100644 (file)
index 0000000..d9c2957
--- /dev/null
@@ -0,0 +1,455 @@
+/* 
+   Unix SMB/CIFS implementation.
+   LDAP server
+   Copyright (C) Volker Lendecke 2004
+   Copyright (C) Stefan Metzmacher 2004
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+
+/*
+  close the socket and shutdown a server_context
+*/
+static void ldapsrv_terminate_connection(struct ldapsrv_connection *ldap_conn, const char *reason)
+{
+       server_terminate_connection(ldap_conn->connection, reason);
+}
+
+/*
+  add a socket address to the list of events, one event per port
+*/
+static void add_socket(struct server_service *service, 
+                      const struct model_ops *model_ops,
+                      struct socket_context *socket_ctx, 
+                      struct in_addr *ifip)
+{
+       uint16_t port = 389;
+
+       service_setup_socket(service, model_ops, socket_ctx, ifip, &port);
+}
+
+/****************************************************************************
+ Open the socket communication.
+****************************************************************************/
+static void ldapsrv_init(struct server_service *service,
+                        const struct model_ops *model_ops)
+{      
+       DEBUG(1,("ldapsrv_init\n"));
+
+       if (lp_interfaces() && lp_bind_interfaces_only()) {
+               int num_interfaces = iface_count();
+               int i;
+
+               /* We have been given an interfaces line, and been 
+                  told to only bind to those interfaces. Create a
+                  socket per interface and bind to only these.
+               */
+               for(i = 0; i < num_interfaces; i++) {
+                       struct in_addr *ifip = iface_n_ip(i);
+
+                       if (ifip == NULL) {
+                               DEBUG(0,("ldapsrv_init: interface %d has NULL "
+                                        "IP address !\n", i));
+                               continue;
+                       }
+
+                       add_socket(service, model_ops, NULL, ifip);
+               }
+       } else {
+               struct in_addr *ifip;
+               TALLOC_CTX *mem_ctx = talloc_init("ldapsrv_init");
+
+               if (!mem_ctx) {
+                       smb_panic("No memory");
+               }       
+
+               /* Just bind to lp_socket_address() (usually 0.0.0.0) */
+               ifip = interpret_addr2(mem_ctx, lp_socket_address());
+               add_socket(service, model_ops, NULL, ifip);
+
+               talloc_destroy(mem_ctx);
+       }
+}
+
+/* This rw-buf api is made to avoid memcpy. For now do that like mad...  The
+   idea is to write into a circular list of buffers where the ideal case is
+   that a read(2) holds a complete request that is then thrown away
+   completely. */
+
+static BOOL append_to_buf(struct rw_buffer *buf, uint8_t *data, size_t length)
+{
+       buf->data = realloc(buf->data, buf->length+length);
+
+       if (buf->data == NULL)
+               return False;
+
+       memcpy(buf->data+buf->length, data, length);
+
+       buf->length += length;
+       return True;
+}
+
+static BOOL read_into_buf(int fd, struct rw_buffer *buf)
+{
+       char tmp_buf[1024];
+       int len;
+
+       len = read(fd, tmp_buf, sizeof(tmp_buf));
+       if (len == 0)
+               return False;
+
+       return append_to_buf(buf, tmp_buf, len);
+}
+
+static BOOL write_from_buf(int fd, struct rw_buffer *buf)
+{
+       int len;
+
+       len = write(fd, buf->data, buf->length);
+       if (len != buf->length)
+               return False;
+
+       return True;
+}
+
+static void peek_into_read_buf(struct rw_buffer *buf, uint8_t **out,
+                              size_t *out_length)
+{
+       *out = buf->data;
+       *out_length = buf->length;
+}
+
+static void consumed_from_read_buf(struct rw_buffer *buf,
+                                  size_t length)
+{
+       memcpy(buf->data, buf->data+length, buf->length-length);
+       buf->length -= length;
+}
+
+static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
+{
+       DATA_BLOB blob;
+       BOOL res;
+
+       if (!ldap_encode(msg, &blob))
+               return False;
+
+       res = append_to_buf(buf, blob.data, blob.length);
+
+       data_blob_free(&blob);
+       return res;
+}
+
+static void reply_unwilling(struct ldapsrv_connection *ldap_conn, int error)
+{
+       struct ldap_message *msg;
+       struct ldap_ExtendedResponse *r;
+
+       msg = new_ldap_message();
+
+       if (msg == NULL) {
+               ldapsrv_terminate_connection(ldap_conn, "new_ldap_message() failed");
+               return;
+       }
+
+       msg->messageid = 0;
+       r = &msg->r.ExtendedResponse;   
+
+       /* When completely freaking out, OpenLDAP responds with an ExtResp */
+       msg->type = LDAP_TAG_ExtendedResponse;
+       r->response.resultcode = error;
+       r->response.dn = NULL;
+       r->response.errormessage = NULL;
+       r->response.referral = NULL;
+       r->name = NULL;
+       r->value.data = NULL;
+       r->value.length = 0;
+
+       ldap_append_to_buf(msg, &ldap_conn->out_buffer);
+
+       talloc_destroy(msg->mem_ctx);
+}
+
+static void ldap_reply_BindRequest(struct ldapsrv_connection *conn, 
+                                  struct ldap_message *request)
+{
+       struct ldap_BindRequest *req = &request->r.BindRequest;
+
+       struct ldap_message *msg;
+       struct ldap_BindResponse *resp;
+
+       DEBUG(5, ("Binding as %s with pw %s\n",
+                 req->dn, req->creds.password));
+
+       msg = new_ldap_message();
+
+       if (msg == NULL) {
+               ldapsrv_terminate_connection(conn, "new_ldap_message() failed");
+               return;
+       }
+
+       resp = &msg->r.BindResponse;
+
+       msg->messageid = request->messageid;
+       msg->type = LDAP_TAG_BindResponse;
+       resp->response.resultcode = 0;
+       resp->response.dn = NULL;
+       resp->response.errormessage = NULL;
+       resp->response.referral = NULL;
+       resp->SASL.secblob = data_blob(NULL, 0);
+
+       ldap_append_to_buf(msg, &conn->out_buffer);
+       talloc_destroy(msg->mem_ctx);
+}
+
+static void ldap_reply_SearchRequest(struct ldapsrv_connection *conn,
+                                    struct ldap_message *request)
+{
+       struct ldap_SearchRequest *req = &request->r.SearchRequest;
+
+       struct ldap_message *msg;
+       struct ldap_Result *resp;
+
+       DEBUG(10, ("Search filter: %s\n", req->filter));
+
+       msg = new_ldap_message();
+
+       if (msg == NULL) {
+               ldapsrv_terminate_connection(conn, "new_ldap_message() failed");
+               return;
+       }
+
+       msg->messageid = request->messageid;
+       resp = &msg->r.SearchResultDone;
+
+       /* Is this a rootdse request? */
+       if ((strlen(req->basedn) == 0) &&
+           (req->scope == LDAP_SEARCH_SCOPE_BASE) &&
+           strequal(req->filter, "(objectclass=*)")) {
+               msg->type = LDAP_TAG_SearchResultEntry;
+               msg->r.SearchResultEntry.dn = "";
+               msg->r.SearchResultEntry.num_attributes = 0;
+               msg->r.SearchResultEntry.attributes = NULL;
+               return;
+       }
+
+       msg->type = LDAP_TAG_SearchResultDone;
+       resp->resultcode = 0;
+       resp->dn = NULL;
+       resp->errormessage = NULL;
+       resp->referral = NULL;
+
+       ldap_append_to_buf(msg, &conn->out_buffer);
+       talloc_destroy(msg->mem_ctx);
+}
+
+static void switch_ldap_message(struct ldapsrv_connection *conn,
+                        struct ldap_message *msg)
+{
+       switch(msg->type) {
+       case LDAP_TAG_BindRequest:
+               ldap_reply_BindRequest(conn, msg);
+               break;
+       case LDAP_TAG_SearchRequest:
+               ldap_reply_SearchRequest(conn, msg);
+               break;
+       default:
+               reply_unwilling(conn, 2);
+               break;
+       }
+}
+
+static void ldap_queue_run(struct server_connection *conn)
+{
+       struct ldapsrv_connection *ldap_conn = conn->private_data;
+       
+       while (ldap_conn->in_queue) {
+               struct ldap_message_queue *req = ldap_conn->in_queue;
+               DLIST_REMOVE(ldap_conn->in_queue, req);
+
+               switch_ldap_message(ldap_conn, req->msg);
+               talloc_destroy(req->msg->mem_ctx);
+       }
+}
+
+/*
+  called when a LDAP socket becomes readable
+*/
+static void ldapsrv_recv(struct server_connection *conn, time_t t,
+                        uint16_t flags)
+{
+       struct ldapsrv_connection *ldap_conn = conn->private_data;
+       uint8_t *buf;
+       int buf_length, msg_length;
+       DATA_BLOB blob;
+       ASN1_DATA data;
+       struct ldap_message *msg;
+       struct ldap_message_queue *queue_entry;
+
+       DEBUG(10,("ldapsrv_recv\n"));
+
+       if (!read_into_buf(conn->event.fde->fd, &ldap_conn->in_buffer)) {
+               ldapsrv_terminate_connection(ldap_conn, "read_into_buf() failed");
+               return;
+       }
+
+       peek_into_read_buf(&ldap_conn->in_buffer, &buf, &buf_length);
+
+       while (buf_length > 0) {
+
+               /* LDAP Messages are always SEQUENCES */
+
+               if (!asn1_object_length(buf, buf_length, ASN1_SEQUENCE(0),
+                                       &msg_length)) {
+                       ldapsrv_terminate_connection(ldap_conn, "asn1_object_length() failed");
+                       return;
+               }
+
+               if (buf_length < msg_length) {
+                       /* Not enough yet */
+                       break;
+               }
+
+               /* We've got a complete LDAP request in the in-buffer, convert
+                * that to a ldap_message and put it into the incoming
+                * queue. */
+
+               blob.data = buf;
+               blob.length = msg_length;
+
+               if (!asn1_load(&data, blob)) {
+                       ldapsrv_terminate_connection(ldap_conn, "asn1_load() failed");
+                       return;
+               }
+
+               msg = new_ldap_message();
+
+               if ((msg == NULL) || !ldap_decode(&data, msg)) {
+                       ldapsrv_terminate_connection(ldap_conn, "ldap_decode() failed");
+                       return;
+               }
+
+               queue_entry = talloc_p(msg->mem_ctx, struct ldap_message_queue);
+
+               if (queue_entry == NULL) {
+                       ldapsrv_terminate_connection(ldap_conn, "alloc_p(msg->mem_ctx, struct ldap_message_queue) failed");
+                       return;
+               }
+
+               queue_entry->msg = msg;
+
+               DLIST_ADD_END(ldap_conn->in_queue, queue_entry,
+                             struct ldap_message_queue *);
+
+               consumed_from_read_buf(&ldap_conn->in_buffer, msg_length);
+
+               peek_into_read_buf(&ldap_conn->in_buffer, &buf, &buf_length);
+       }
+
+       ldap_queue_run(conn);
+
+       return;
+}
+       
+/*
+  called when a LDAP socket becomes writable
+*/
+static void ldapsrv_send(struct server_connection *conn, time_t t,
+                        uint16_t flags)
+{
+       struct ldapsrv_connection *ldap_conn = conn->private_data;
+
+       DEBUG(10,("ldapsrv_send\n"));
+
+       if (!write_from_buf(conn->event.fde->fd, &ldap_conn->out_buffer)) {
+               ldapsrv_terminate_connection(ldap_conn, "write_from_buf() failed");
+               return;
+       }
+
+       return;
+}
+
+/*
+  called when connection is idle
+*/
+static void ldapsrv_idle(struct server_connection *conn, time_t t)
+{
+       DEBUG(10,("ldapsrv_idle: not implemented!\n"));
+       return;
+}
+
+static void ldapsrv_close(struct server_connection *conn, const char *reason)
+{
+       struct ldapsrv_connection *ldap_conn = conn->private_data;
+
+       talloc_free(ldap_conn);
+
+       return;
+}
+
+/*
+  initialise a server_context from a open socket and register a event handler
+  for reading from that socket
+*/
+static void ldapsrv_accept(struct server_connection *conn)
+{
+       struct ldapsrv_connection *ldap_conn;
+
+       DEBUG(5, ("ldapsrv_accept\n"));
+
+       ldap_conn = talloc_p(NULL, struct ldapsrv_connection);
+
+       if (ldap_conn == NULL)
+               return;
+
+       ZERO_STRUCTP(ldap_conn);
+       ldap_conn->connection = conn;
+
+       conn->private_data = ldap_conn;
+       
+       return;
+}
+
+/*
+  called on a fatal error that should cause this server to terminate
+*/
+static void ldapsrv_exit(struct server_service *service, const char *reason)
+{
+       DEBUG(1,("ldapsrv_exit\n"));
+       return;
+}
+
+static const struct server_service_ops ldap_server_ops = {
+       .name                   = "ldap",
+       .service_init           = ldapsrv_init,
+       .accept_connection      = ldapsrv_accept,
+       .recv_handler           = ldapsrv_recv,
+       .send_handler           = ldapsrv_send,
+       .idle_handler           = ldapsrv_idle,
+       .close_connection       = ldapsrv_close,
+       .service_exit           = ldapsrv_exit, 
+};
+
+const struct server_service_ops *ldapsrv_get_ops(void)
+{
+       return &ldap_server_ops;
+}
+
+NTSTATUS server_service_ldap_init(void)
+{
+       return NT_STATUS_OK;    
+}
diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h
new file mode 100644 (file)
index 0000000..4c10cb3
--- /dev/null
@@ -0,0 +1,43 @@
+/* 
+   Unix SMB/CIFS implementation.
+   LDAP server
+   Copyright (C) Volker Lendecke 2004
+   Copyright (C) Stefan Metzmacher 2004
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+struct ldap_message_queue {
+       struct ldap_message_queue *prev, *next;
+       struct ldap_message *msg;
+};
+
+struct rw_buffer {
+       uint8_t *data;
+       size_t ofs, length;
+};
+
+struct ldapsrv_connection {
+       struct server_connection *connection;
+
+       struct gensec_security *gensec_ctx;
+
+       struct auth_session_info *session_info;
+
+       struct rw_buffer in_buffer;
+       struct rw_buffer out_buffer;
+       struct ldap_message_queue *in_queue;
+       struct ldap_message_queue *out_queue;
+};
index 52ccb68aa8d29e5a8dba085bf13b6fcb78e32777..5142e81f849d936e056e8b5ce2696a075c3efb8b 100644 (file)
@@ -3,6 +3,7 @@ dnl # server subsystem
 SMB_MODULE_MK(server_service_auth,SERVER_SERVICE,STATIC,smbd/config.mk)
 SMB_MODULE_MK(server_service_smb,SERVER_SERVICE,STATIC,smbd/config.mk)
 SMB_MODULE_MK(server_service_rpc,SERVER_SERVICE,STATIC,smbd/config.mk)
+SMB_MODULE_MK(server_service_ldap,SERVER_SERVICE,STATIC,smbd/config.mk)
 
 SMB_SUBSYSTEM_MK(SERVER_SERVICE,smbd/config.mk)
 SMB_SUBSYSTEM_MK(SERVER,smbd/config.mk)
index f002341a267f0df0e228893daaf3520254115222..5aa04725b4452c115d3bf691043162a1e7beba1d 100644 (file)
@@ -24,6 +24,14 @@ REQUIRED_SUBSYSTEMS = \
 # End MODULE server_rpc
 ################################################
 
+################################################
+# Start MODULE server_service_ldap
+[MODULE::server_service_ldap]
+REQUIRED_SUBSYSTEMS = \
+               LDAP
+# End MODULE server_ldap
+################################################
+
 #######################
 # Start SUBSYSTEM SERVICE
 [SUBSYSTEM::SERVER_SERVICE]
index 270eeb4f222f8da849fc7e25395dbf471b3a8210..2f4be5151d4bad8e7a0bf5935b270de916f5df9e 100644 (file)
@@ -292,6 +292,9 @@ const struct server_service_ops *server_service_byname(const char *name)
        if (strcmp("rpc",name)==0) {
                return dcesrv_get_ops();
        }
+       if (strcmp("ldap",name)==0) {
+               return ldapsrv_get_ops();
+       }
        return NULL;
 }