#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"
#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);
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;
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) {
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;
}
basedn = ldb_dn_new(tmp_ctx, conn->ldb, NULL);
- if ( ! ldb_dn_validate(basedn)) {
+ if (basedn == NULL) {
goto failed;
}
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;
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;
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);
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) {
}
port = socket_address->port;
talloc_free(socket_address);
- if (port == 3268) /* Global catalog */ {
+ if (port == 3268 || port == 3269) /* Global catalog */ {
conn->global_catalog = true;
}
}
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");
/* 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;
}
{
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 {
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
*
"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;
}
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");
conn->active_call = subreq;
}
+
static void ldapsrv_call_writev_done(struct tevent_req *subreq);
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;
return;
}
- TALLOC_FREE(call);
+ if (!call->notification.busy) {
+ TALLOC_FREE(call);
+ }
ldapsrv_call_read_next(conn);
}
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;
};
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);
}
"session info");
return;
}
- ldapsrv_accept(c, session_info);
+ ldapsrv_accept(c, session_info, false);
}
static const struct stream_server_ops ldap_stream_nonpriv_ops = {
"session info");
return;
}
- ldapsrv_accept(c, session_info);
+ ldapsrv_accept(c, session_info, true);
}
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)
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)) {
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)) {
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)) {
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);
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;
}
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;
}
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),
}
#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;
}
* 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;
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),
}
#endif
+
+ /* register the server */
+ irpc_add_name(task->msg_ctx, "ldap_server");
return;
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);
}