s4: Add TALLOC_CTX * to register_server_service().
[samba.git] / source4 / ldap_server / ldap_server.c
index eec505fdc5a7790ba2b5ff115ad3ce08b03e4aab..347a17dde5a62b2a8de26b1d6b27521e266b066d 100644 (file)
@@ -36,8 +36,8 @@
 #include "smbd/process_model.h"
 #include "lib/tls/tls.h"
 #include "lib/messaging/irpc.h"
-#include "lib/ldb/include/ldb.h"
-#include "lib/ldb/include/ldb_errors.h"
+#include <ldb.h>
+#include <ldb_errors.h>
 #include "libcli/ldap/ldap_proto.h"
 #include "system/network.h"
 #include "lib/socket/netif.h"
@@ -46,6 +46,7 @@
 #include "../lib/tsocket/tsocket.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "../libcli/util/tstream.h"
+#include "libds/common/roles.h"
 
 static void ldapsrv_terminate_connection_done(struct tevent_req *subreq);
 
@@ -61,9 +62,12 @@ static void ldapsrv_terminate_connection(struct ldapsrv_connection *conn,
                return;
        }
 
+       DLIST_REMOVE(conn->service->connections, conn);
+
        conn->limits.endtime = timeval_current_ofs(0, 500);
 
        tevent_queue_stop(conn->sockets.send_queue);
+       TALLOC_FREE(conn->sockets.read_req);
        if (conn->active_call) {
                tevent_req_cancel(conn->active_call);
                conn->active_call = NULL;
@@ -99,10 +103,9 @@ static void ldapsrv_terminate_connection_done(struct tevent_req *subreq)
        struct ldapsrv_connection *conn =
                tevent_req_callback_data(subreq,
                struct ldapsrv_connection);
-       int ret;
        int sys_errno;
 
-       ret = tstream_disconnect_recv(subreq, &sys_errno);
+       tstream_disconnect_recv(subreq, &sys_errno);
        TALLOC_FREE(subreq);
 
        if (conn->sockets.active == conn->sockets.raw) {
@@ -166,6 +169,7 @@ static int ldapsrv_load_limits(struct ldapsrv_connection *conn)
        conn->limits.initial_timeout = 120;
        conn->limits.conn_idle_time = 900;
        conn->limits.max_page_size = 1000;
+       conn->limits.max_notifications = 5;
        conn->limits.search_timeout = 120;
 
 
@@ -175,7 +179,7 @@ static int ldapsrv_load_limits(struct ldapsrv_connection *conn)
        }
 
        basedn = ldb_dn_new(tmp_ctx, conn->ldb, NULL);
-       if ( ! ldb_dn_validate(basedn)) {
+       if (basedn == NULL) {
                goto failed;
        }
 
@@ -218,9 +222,8 @@ static int ldapsrv_load_limits(struct ldapsrv_connection *conn)
                int policy_value, s;
 
                s = sscanf((const char *)el->values[i].data, "%255[^=]=%d", policy_name, &policy_value);
-               if (ret != 2 || policy_value == 0)
+               if (s != 2 || policy_value == 0)
                        continue;
-
                if (strcasecmp("InitRecvTimeout", policy_name) == 0) {
                        conn->limits.initial_timeout = policy_value;
                        continue;
@@ -233,6 +236,10 @@ static int ldapsrv_load_limits(struct ldapsrv_connection *conn)
                        conn->limits.max_page_size = policy_value;
                        continue;
                }
+               if (strcasecmp("MaxNotificationPerConn", policy_name) == 0) {
+                       conn->limits.max_notifications = policy_value;
+                       continue;
+               }
                if (strcasecmp("MaxQueryDuration", policy_name) == 0) {
                        conn->limits.search_timeout = policy_value;
                        continue;
@@ -261,7 +268,8 @@ static void ldapsrv_accept_tls_done(struct tevent_req *subreq);
   for reading from that socket
 */
 static void ldapsrv_accept(struct stream_connection *c,
-                          struct auth_session_info *session_info)
+                          struct auth_session_info *session_info,
+                          bool is_privileged)
 {
        struct ldapsrv_service *ldapsrv_service = 
                talloc_get_type(c->private_data, struct ldapsrv_service);
@@ -279,6 +287,7 @@ static void ldapsrv_accept(struct stream_connection *c,
                stream_terminate_connection(c, "ldapsrv_accept: out of memory");
                return;
        }
+       conn->is_privileged = is_privileged;
 
        conn->sockets.send_queue = tevent_queue_create(conn, "ldapsev send queue");
        if (conn->sockets.send_queue == NULL) {
@@ -312,7 +321,7 @@ static void ldapsrv_accept(struct stream_connection *c,
        }
        port = socket_address->port;
        talloc_free(socket_address);
-       if (port == 3268) /* Global catalog */ {
+       if (port == 3268 || port == 3269) /* Global catalog */ {
                conn->global_catalog = true;
        }
 
@@ -330,7 +339,15 @@ static void ldapsrv_accept(struct stream_connection *c,
        }
        conn->server_credentials = server_credentials;
 
-       conn->session_info = talloc_move(conn, &session_info);
+       conn->session_info = session_info;
+
+       conn->sockets.active = conn->sockets.raw;
+
+       if (conn->is_privileged) {
+               conn->require_strong_auth = LDAP_SERVER_REQUIRE_STRONG_AUTH_NO;
+       } else {
+               conn->require_strong_auth = lpcfg_ldap_server_require_strong_auth(conn->lp_ctx);
+       }
 
        if (!NT_STATUS_IS_OK(ldapsrv_backend_Init(conn))) {
                ldapsrv_terminate_connection(conn, "backend Init failed");
@@ -343,9 +360,9 @@ static void ldapsrv_accept(struct stream_connection *c,
        /* register the server */       
        irpc_add_name(c->msg_ctx, "ldap_server");
 
-       conn->sockets.active = conn->sockets.raw;
+       DLIST_ADD_END(ldapsrv_service->connections, conn);
 
-       if (port != 636) {
+       if (port != 636 && port != 3269) {
                ldapsrv_call_read_next(conn);
                return;
        }
@@ -403,7 +420,11 @@ static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
 {
        struct tevent_req *subreq;
 
-       if (timeval_is_zero(&conn->limits.endtime)) {
+       if (conn->pending_calls != NULL) {
+               conn->limits.endtime = timeval_zero();
+
+               ldapsrv_notification_retry_setup(conn->service, false);
+       } else if (timeval_is_zero(&conn->limits.endtime)) {
                conn->limits.endtime =
                        timeval_current_ofs(conn->limits.initial_timeout, 0);
        } else {
@@ -411,8 +432,12 @@ static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
                        timeval_current_ofs(conn->limits.conn_idle_time, 0);
        }
 
+       if (conn->sockets.read_req != NULL) {
+               return true;
+       }
+
        /*
-        * The minimun size of a LDAP pdu is 7 bytes
+        * The minimum size of a LDAP pdu is 7 bytes
         *
         * dumpasn1 -hh ldap-unbind-min.dat
         *
@@ -450,10 +475,13 @@ static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
                                "no memory for tstream_read_pdu_blob_send");
                return false;
        }
-       tevent_req_set_endtime(subreq,
-                              conn->connection->event.ctx,
-                              conn->limits.endtime);
+       if (!timeval_is_zero(&conn->limits.endtime)) {
+               tevent_req_set_endtime(subreq,
+                                      conn->connection->event.ctx,
+                                      conn->limits.endtime);
+       }
        tevent_req_set_callback(subreq, ldapsrv_call_read_done, conn);
+       conn->sockets.read_req = subreq;
        return true;
 }
 
@@ -469,6 +497,8 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
        struct asn1_data *asn1;
        DATA_BLOB blob;
 
+       conn->sockets.read_req = NULL;
+
        call = talloc_zero(conn, struct ldapsrv_call);
        if (!call) {
                ldapsrv_terminate_connection(conn, "no memory");
@@ -535,6 +565,7 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
        conn->active_call = subreq;
 }
 
+
 static void ldapsrv_call_writev_done(struct tevent_req *subreq);
 
 static void ldapsrv_call_process_done(struct tevent_req *subreq)
@@ -581,7 +612,9 @@ static void ldapsrv_call_process_done(struct tevent_req *subreq)
        }
 
        if (blob.length == 0) {
-               TALLOC_FREE(call);
+               if (!call->notification.busy) {
+                       TALLOC_FREE(call);
+               }
 
                ldapsrv_call_read_next(conn);
                return;
@@ -645,7 +678,9 @@ static void ldapsrv_call_writev_done(struct tevent_req *subreq)
                return;
        }
 
-       TALLOC_FREE(call);
+       if (!call->notification.busy) {
+               TALLOC_FREE(call);
+       }
 
        ldapsrv_call_read_next(conn);
 }
@@ -679,6 +714,112 @@ static void ldapsrv_call_postprocess_done(struct tevent_req *subreq)
        ldapsrv_call_read_next(conn);
 }
 
+static void ldapsrv_notification_retry_done(struct tevent_req *subreq);
+
+void ldapsrv_notification_retry_setup(struct ldapsrv_service *service, bool force)
+{
+       struct ldapsrv_connection *conn = NULL;
+       struct timeval retry;
+       size_t num_pending = 0;
+       size_t num_active = 0;
+
+       if (force) {
+               TALLOC_FREE(service->notification.retry);
+               service->notification.generation += 1;
+       }
+
+       if (service->notification.retry != NULL) {
+               return;
+       }
+
+       for (conn = service->connections; conn != NULL; conn = conn->next) {
+               if (conn->pending_calls == NULL) {
+                       continue;
+               }
+
+               num_pending += 1;
+
+               if (conn->pending_calls->notification.generation !=
+                   service->notification.generation)
+               {
+                       num_active += 1;
+               }
+       }
+
+       if (num_pending == 0) {
+               return;
+       }
+
+       if (num_active != 0) {
+               retry = timeval_current_ofs(0, 100);
+       } else {
+               retry = timeval_current_ofs(5, 0);
+       }
+
+       service->notification.retry = tevent_wakeup_send(service,
+                                                        service->task->event_ctx,
+                                                        retry);
+       if (service->notification.retry == NULL) {
+               /* retry later */
+               return;
+       }
+
+       tevent_req_set_callback(service->notification.retry,
+                               ldapsrv_notification_retry_done,
+                               service);
+}
+
+static void ldapsrv_notification_retry_done(struct tevent_req *subreq)
+{
+       struct ldapsrv_service *service =
+               tevent_req_callback_data(subreq,
+               struct ldapsrv_service);
+       struct ldapsrv_connection *conn = NULL;
+       struct ldapsrv_connection *conn_next = NULL;
+       bool ok;
+
+       service->notification.retry = NULL;
+
+       ok = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ok) {
+               /* ignore */
+       }
+
+       for (conn = service->connections; conn != NULL; conn = conn_next) {
+               struct ldapsrv_call *call = conn->pending_calls;
+
+               conn_next = conn->next;
+
+               if (conn->pending_calls == NULL) {
+                       continue;
+               }
+
+               if (conn->active_call != NULL) {
+                       continue;
+               }
+
+               DLIST_DEMOTE(conn->pending_calls, call);
+               call->notification.generation =
+                               service->notification.generation;
+
+               /* queue the call in the global queue */
+               subreq = ldapsrv_process_call_send(call,
+                                                  conn->connection->event.ctx,
+                                                  conn->service->call_queue,
+                                                  call);
+               if (subreq == NULL) {
+                       ldapsrv_terminate_connection(conn,
+                                       "ldapsrv_process_call_send failed");
+                       continue;
+               }
+               tevent_req_set_callback(subreq, ldapsrv_call_process_done, call);
+               conn->active_call = subreq;
+       }
+
+       ldapsrv_notification_retry_setup(service, false);
+}
+
 struct ldapsrv_process_call_state {
        struct ldapsrv_call *call;
 };
@@ -706,7 +847,7 @@ static struct tevent_req *ldapsrv_process_call_send(TALLOC_CTX *mem_ctx,
        ok = tevent_queue_add(call_queue, ev, req,
                              ldapsrv_process_call_trigger, NULL);
        if (!ok) {
-               tevent_req_nomem(NULL, req);
+               tevent_req_oom(req);
                return tevent_req_post(req, ev);
        }
 
@@ -758,7 +899,7 @@ static void ldapsrv_accept_nonpriv(struct stream_connection *c)
                                            "session info");
                return;
        }
-       ldapsrv_accept(c, session_info);
+       ldapsrv_accept(c, session_info, false);
 }
 
 static const struct stream_server_ops ldap_stream_nonpriv_ops = {
@@ -786,7 +927,7 @@ static void ldapsrv_accept_priv(struct stream_connection *c)
                                            "session info");
                return;
        }
-       ldapsrv_accept(c, session_info);
+       ldapsrv_accept(c, session_info, true);
 }
 
 static const struct stream_server_ops ldap_stream_priv_ops = {
@@ -797,10 +938,12 @@ static const struct stream_server_ops ldap_stream_priv_ops = {
 };
 
 #endif
+
+
 /*
   add a socket address to the list of events, one event per port
 */
-static NTSTATUS add_socket(struct tevent_context *event_context,
+static NTSTATUS add_socket(struct task_server *task,
                           struct loadparm_context *lp_ctx,
                           const struct model_ops *model_ops,
                           const char *address, struct ldapsrv_service *ldap_service)
@@ -809,9 +952,9 @@ static NTSTATUS add_socket(struct tevent_context *event_context,
        NTSTATUS status;
        struct ldb_context *ldb;
 
-       status = stream_setup_socket(event_context, lp_ctx,
+       status = stream_setup_socket(task, task->event_ctx, lp_ctx,
                                     model_ops, &ldap_stream_nonpriv_ops,
-                                    "ipv4", address, &port, 
+                                    "ip", address, &port,
                                     lpcfg_socket_options(lp_ctx),
                                     ldap_service);
        if (!NT_STATUS_IS_OK(status)) {
@@ -823,10 +966,10 @@ static NTSTATUS add_socket(struct tevent_context *event_context,
        if (tstream_tls_params_enabled(ldap_service->tls_params)) {
                /* add ldaps server */
                port = 636;
-               status = stream_setup_socket(event_context, lp_ctx,
+               status = stream_setup_socket(task, task->event_ctx, lp_ctx,
                                             model_ops,
                                             &ldap_stream_nonpriv_ops,
-                                            "ipv4", address, &port, 
+                                            "ip", address, &port,
                                             lpcfg_socket_options(lp_ctx),
                                             ldap_service);
                if (!NT_STATUS_IS_OK(status)) {
@@ -845,10 +988,10 @@ static NTSTATUS add_socket(struct tevent_context *event_context,
 
        if (samdb_is_gc(ldb)) {
                port = 3268;
-               status = stream_setup_socket(event_context, lp_ctx,
+               status = stream_setup_socket(task, task->event_ctx, lp_ctx,
                                             model_ops,
                                             &ldap_stream_nonpriv_ops,
-                                            "ipv4", address, &port, 
+                                            "ip", address, &port,
                                             lpcfg_socket_options(lp_ctx),
                                             ldap_service);
                if (!NT_STATUS_IS_OK(status)) {
@@ -856,9 +999,24 @@ static NTSTATUS add_socket(struct tevent_context *event_context,
                                 address, port, nt_errstr(status)));
                        return status;
                }
+               if (tstream_tls_params_enabled(ldap_service->tls_params)) {
+                       /* add ldaps server for the global catalog */
+                       port = 3269;
+                       status = stream_setup_socket(task, task->event_ctx, lp_ctx,
+                                                    model_ops,
+                                                    &ldap_stream_nonpriv_ops,
+                                                    "ip", address, &port,
+                                                    lpcfg_socket_options(lp_ctx),
+                                                    ldap_service);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0,("ldapsrv failed to bind to %s:%u - %s\n",
+                                        address, port, nt_errstr(status)));
+                               return status;
+                       }
+               }
        }
 
-       /* And once we are bound, free the tempoary ldb, it will
+       /* And once we are bound, free the temporary ldb, it will
         * connect again on each incoming LDAP connection */
        talloc_unlink(ldap_service, ldb);
 
@@ -888,7 +1046,7 @@ static void ldapsrv_task_init(struct task_server *task)
                task_server_terminate(task, "ldap_server: no LDAP server required in member server configuration", 
                                      false);
                return;
-       case ROLE_DOMAIN_CONTROLLER:
+       case ROLE_ACTIVE_DIRECTORY_DC:
                /* Yes, we want an LDAP server */
                break;
        }
@@ -917,9 +1075,10 @@ static void ldapsrv_task_init(struct task_server *task)
                                           lpcfg_tls_cafile(ldap_service, task->lp_ctx),
                                           lpcfg_tls_crlfile(ldap_service, task->lp_ctx),
                                           lpcfg_tls_dhpfile(ldap_service, task->lp_ctx),
+                                          lpcfg_tls_priority(task->lp_ctx),
                                           &ldap_service->tls_params);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("ldapsrv failed tstream_tls_patams_server - %s\n",
+               DEBUG(0,("ldapsrv failed tstream_tls_params_server - %s\n",
                         nt_errstr(status)));
                goto failed;
        }
@@ -932,30 +1091,45 @@ static void ldapsrv_task_init(struct task_server *task)
                int num_interfaces;
                int i;
 
-               load_interfaces(task, lpcfg_interfaces(task->lp_ctx), &ifaces);
-               num_interfaces = iface_count(ifaces);
+               load_interface_list(task, task->lp_ctx, &ifaces);
+               num_interfaces = iface_list_count(ifaces);
 
                /* 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++) {
-                       const char *address = iface_n_ip(ifaces, i);
-                       status = add_socket(task->event_ctx, task->lp_ctx, model_ops, address, ldap_service);
+                       const char *address = iface_list_n_ip(ifaces, i);
+                       status = add_socket(task, task->lp_ctx, model_ops, address, ldap_service);
                        if (!NT_STATUS_IS_OK(status)) goto failed;
                }
        } else {
-               status = add_socket(task->event_ctx, task->lp_ctx, model_ops,
-                                   lpcfg_socket_address(task->lp_ctx), ldap_service);
-               if (!NT_STATUS_IS_OK(status)) goto failed;
+               char **wcard;
+               int i;
+               int num_binds = 0;
+               wcard = iface_list_wildcard(task);
+               if (wcard == NULL) {
+                       DEBUG(0,("No wildcard addresses available\n"));
+                       goto failed;
+               }
+               for (i=0; wcard[i]; i++) {
+                       status = add_socket(task, task->lp_ctx, model_ops, wcard[i], ldap_service);
+                       if (NT_STATUS_IS_OK(status)) {
+                               num_binds++;
+                       }
+               }
+               talloc_free(wcard);
+               if (num_binds == 0) {
+                       goto failed;
+               }
        }
 
-       ldapi_path = private_path(ldap_service, task->lp_ctx, "ldapi");
+       ldapi_path = lpcfg_private_path(ldap_service, task->lp_ctx, "ldapi");
        if (!ldapi_path) {
                goto failed;
        }
 
-       status = stream_setup_socket(task->event_ctx, task->lp_ctx,
+       status = stream_setup_socket(task, task->event_ctx, task->lp_ctx,
                                     model_ops, &ldap_stream_nonpriv_ops,
                                     "unix", ldapi_path, NULL, 
                                     lpcfg_socket_options(task->lp_ctx),
@@ -967,7 +1141,7 @@ static void ldapsrv_task_init(struct task_server *task)
        }
 
 #ifdef WITH_LDAPI_PRIV_SOCKET
-       priv_dir = private_path(ldap_service, task->lp_ctx, "ldap_priv");
+       priv_dir = lpcfg_private_path(ldap_service, task->lp_ctx, "ldap_priv");
        if (priv_dir == NULL) {
                goto failed;
        }
@@ -975,7 +1149,7 @@ static void ldapsrv_task_init(struct task_server *task)
         * Make sure the directory for the privileged ldapi socket exists, and
         * is of the correct permissions
         */
-       if (!directory_create_or_exist(priv_dir, geteuid(), 0750)) {
+       if (!directory_create_or_exist(priv_dir, 0750)) {
                task_server_terminate(task, "Cannot create ldap "
                                      "privileged ldapi directory", true);
                return;
@@ -986,7 +1160,7 @@ static void ldapsrv_task_init(struct task_server *task)
                goto failed;
        }
 
-       status = stream_setup_socket(task->event_ctx, task->lp_ctx,
+       status = stream_setup_socket(task, task->event_ctx, task->lp_ctx,
                                     model_ops, &ldap_stream_priv_ops,
                                     "unix", ldapi_path, NULL,
                                     lpcfg_socket_options(task->lp_ctx),
@@ -998,6 +1172,9 @@ static void ldapsrv_task_init(struct task_server *task)
        }
 
 #endif
+
+       /* register the server */
+       irpc_add_name(task->msg_ctx, "ldap_server");
        return;
 
 failed:
@@ -1005,7 +1182,7 @@ failed:
 }
 
 
-NTSTATUS server_service_ldap_init(void)
+NTSTATUS server_service_ldap_init(TALLOC_CTX *ctx)
 {
-       return register_server_service("ldap", ldapsrv_task_init);
+       return register_server_service(ctx, "ldap", ldapsrv_task_init);
 }