s4:libcli/ldap: add support for ADS_AUTH_SASL_{STARTTLS,LDAPS}
authorStefan Metzmacher <metze@samba.org>
Wed, 24 Jan 2024 09:43:42 +0000 (10:43 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Apr 2024 23:50:34 +0000 (23:50 +0000)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/libcli/ldap/ldap_client.c
source4/libcli/ldap/ldap_client.h

index 61a49d345028b5adab3b75dc9c15908d09366c16..96521518584d79d03a14a1b9382b0e01a3befa1f 100644 (file)
@@ -38,6 +38,7 @@
 #include "system/time.h"
 #include "param/param.h"
 #include "libcli/resolve/resolve.h"
+#include "librpc/gen_ndr/ads.h"
 
 static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
 
@@ -503,9 +504,30 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
        }
 
        if ((proto == LDAP_PROTO_LDAP) || (proto == LDAP_PROTO_LDAPS)) {
+               int wrap_flags = lpcfg_client_ldap_sasl_wrapping(conn->lp_ctx);
 
                conn->ldaps = (proto == LDAP_PROTO_LDAPS);
 
+               if (wrap_flags & ADS_AUTH_SASL_LDAPS) {
+                       if (proto == LDAP_PROTO_LDAP) {
+                               if (port == 389) {
+                                       port = 636;
+                                       proto = LDAP_PROTO_LDAPS;
+                               } else if (port == 3268) {
+                                       port = 3269;
+                                       proto = LDAP_PROTO_LDAPS;
+                               } else {
+                                       conn->starttls = true;
+                               }
+                       }
+                       conn->ldaps = true;
+               } else if (wrap_flags & ADS_AUTH_SASL_STARTTLS) {
+                       if (proto == LDAP_PROTO_LDAP) {
+                               conn->starttls = true;
+                       }
+                       conn->ldaps = true;
+               }
+
                conn->host = talloc_move(conn, &dest);
                conn->port = port;
 
@@ -538,6 +560,7 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
        return NULL;
 }
 
+static void ldap_connect_starttls_done(struct ldap_request *ldap_req);
 static void ldap_connect_got_tls(struct tevent_req *subreq);
 
 static void ldap_connect_got_sock(struct composite_context *ctx, 
@@ -570,15 +593,77 @@ static void ldap_connect_got_sock(struct composite_context *ctx,
                return;
        }
 
+       conn->sockets.raw = talloc_move(conn, &state->raw);
+       conn->sockets.active = conn->sockets.raw;
+
        if (!conn->ldaps) {
-               conn->sockets.raw = talloc_move(conn, &state->raw);
-               conn->sockets.active = conn->sockets.raw;
                composite_done(state->ctx);
                return;
        }
 
+       if (conn->starttls) {
+               struct ldap_message msg = {
+                       .type = LDAP_TAG_ExtendedRequest,
+                       .r.ExtendedRequest.oid = LDB_EXTENDED_START_TLS_OID,
+               };
+               struct ldap_request *ldap_req = NULL;
+
+               ldap_req = ldap_request_send(conn, &msg);
+               if (composite_nomem(ldap_req, state->ctx)) {
+                       return;
+               }
+               ldap_req->async.fn = ldap_connect_starttls_done;
+               ldap_req->async.private_data = state;
+               return;
+       }
+
+       subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
+                                         conn->sockets.raw, state->tls_params);
+       if (composite_nomem(subreq, state->ctx)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
+}
+
+static void ldap_connect_starttls_done(struct ldap_request *ldap_req)
+{
+       struct ldap_connect_state *state =
+               talloc_get_type_abort(ldap_req->async.private_data,
+               struct ldap_connect_state);
+       struct ldap_connection *conn = state->conn;
+       NTSTATUS status = ldap_req->status;
+       struct tevent_req *subreq = NULL;
+
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(ldap_req);
+               composite_error(state->ctx, status);
+               return;
+       }
+
+       if (ldap_req->num_replies != 1) {
+               TALLOC_FREE(ldap_req);
+               status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+               composite_error(state->ctx, status);
+               return;
+       }
+
+       if (ldap_req->replies[0]->type != LDAP_TAG_ExtendedResponse) {
+               TALLOC_FREE(ldap_req);
+               status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+               composite_error(state->ctx, status);
+               return;
+       }
+
+       status = ldap_check_response(conn,
+                                    &ldap_req->replies[0]->r.GeneralResult);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(ldap_req);
+               composite_error(state->ctx, status);
+               return;
+       }
+
        subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
-                                         state->raw, state->tls_params);
+                                         conn->sockets.raw, state->tls_params);
        if (composite_nomem(subreq, state->ctx)) {
                return;
        }
@@ -603,7 +688,6 @@ static void ldap_connect_got_tls(struct tevent_req *subreq)
 
        talloc_steal(state->tls, state->tls_params);
 
-       state->conn->sockets.raw = talloc_move(state->conn, &state->raw);
        state->conn->sockets.tls = talloc_move(state->conn->sockets.raw,
                                               &state->tls);
        state->conn->sockets.active = state->conn->sockets.tls;
index e2b1b30e49395227efd65e89181a6db4d68e838b..f09bacc30058ba7303cf56eb0e77af14a8246dc4 100644 (file)
@@ -68,6 +68,7 @@ struct ldap_connection {
        char *host;
        uint16_t port;
        bool ldaps;
+       bool starttls;
 
        const char *auth_dn;
        const char *simple_pw;