#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;
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;
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");
return;
/* 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 && port != 3269) {
ldapsrv_call_read_next(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 {
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;
};
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;
}
if (!NT_STATUS_IS_OK(status)) goto failed;
}
} else {
- const char **wcard;
+ char **wcard;
int i;
- wcard = iface_list_wildcard(task, task->lp_ctx);
+ 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)) goto failed;
+ if (NT_STATUS_IS_OK(status)) {
+ num_binds++;
+ }
}
talloc_free(wcard);
+ if (num_binds == 0) {
+ goto failed;
+ }
}
ldapi_path = lpcfg_private_path(ldap_service, task->lp_ctx, "ldapi");
* 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;
}
#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);
}