ldb: use #include <ldb.h> for ldb
[kai/samba.git] / source4 / ldap_server / ldap_bind.c
index f37ef31c0adb15057e77e75bfca0a449072e5384..0f3d0631d009df845d18c5f4eceb82a8b90e91db 100644 (file)
 #include "includes.h"
 #include "ldap_server/ldap_server.h"
 #include "auth/auth.h"
-#include "libcli/ldap/ldap.h"
 #include "smbd/service.h"
-#include "lib/ldb/include/ldb.h"
-#include "lib/ldb/include/ldb_errors.h"
+#include <ldb.h>
+#include <ldb_errors.h>
 #include "dsdb/samdb/samdb.h"
 #include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_tstream.h"
 #include "param/param.h"
+#include "../lib/util/tevent_ntstatus.h"
 
 static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 {
@@ -52,6 +53,8 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
                                                  call->conn->lp_ctx,
                                                  nt4_domain, nt4_account, 
                                                  req->creds.password,
+                                                 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
+                                                 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
                                                  &session_info);
        }
 
@@ -64,12 +67,12 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
                result = LDAP_SUCCESS;
                errstr = NULL;
 
-               talloc_free(call->conn->session_info);
+               talloc_unlink(call->conn, call->conn->session_info);
                call->conn->session_info = session_info;
                talloc_steal(call->conn, session_info);
 
                /* don't leak the old LDB */
-               talloc_free(call->conn->ldb);
+               talloc_unlink(call->conn, call->conn->ldb);
 
                status = ldapsrv_backend_Init(call->conn);              
                
@@ -95,20 +98,42 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
        return NT_STATUS_OK;
 }
 
-struct ldapsrv_sasl_context {
+struct ldapsrv_sasl_postprocess_context {
        struct ldapsrv_connection *conn;
-       struct socket_context *sasl_socket;
+       struct tstream_context *sasl;
 };
 
-static void ldapsrv_set_sasl(void *private) 
+struct ldapsrv_sasl_postprocess_state {
+       uint8_t dummy;
+};
+
+static struct tevent_req *ldapsrv_sasl_postprocess_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               void *private_data)
 {
-       struct ldapsrv_sasl_context *ctx = talloc_get_type(private, struct ldapsrv_sasl_context);
-       talloc_steal(ctx->conn->connection, ctx->sasl_socket);
-       talloc_unlink(ctx->conn->connection, ctx->conn->connection->socket);
+       struct ldapsrv_sasl_postprocess_context *context =
+               talloc_get_type_abort(private_data,
+               struct ldapsrv_sasl_postprocess_context);
+       struct tevent_req *req;
+       struct ldapsrv_sasl_postprocess_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct ldapsrv_sasl_postprocess_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       TALLOC_FREE(context->conn->sockets.sasl);
+       context->conn->sockets.sasl = talloc_move(context->conn, &context->sasl);
+       context->conn->sockets.active = context->conn->sockets.sasl;
 
-       ctx->conn->sockets.sasl = ctx->sasl_socket;
-       ctx->conn->connection->socket = ctx->sasl_socket;
-       packet_set_socket(ctx->conn->packet, ctx->conn->connection->socket);
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+static NTSTATUS ldapsrv_sasl_postprocess_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
 }
 
 static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
@@ -140,22 +165,20 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
        if (!conn->gensec) {
                conn->session_info = NULL;
 
-               status = gensec_server_start(conn,
-                                            conn->connection->event.ctx,
-                                            conn->lp_ctx,
-                                            conn->connection->msg_ctx,
-                                            &conn->gensec);
+               status = samba_server_gensec_start(conn,
+                                                  conn->connection->event.ctx,
+                                                  conn->connection->msg_ctx,
+                                                  conn->lp_ctx,
+                                                  conn->server_credentials,
+                                                  "ldap",
+                                                  &conn->gensec);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
                        result = LDAP_OPERATIONS_ERROR;
                        errstr = talloc_asprintf(reply, "SASL: Failed to start authentication system: %s", 
                                                 nt_errstr(status));
                } else {
-               
-                       gensec_set_target_service(conn->gensec, "ldap");
-                       
-                       gensec_set_credentials(conn->gensec, conn->server_credentials);
-                       
+
                        gensec_want_feature(conn->gensec, GENSEC_FEATURE_SIGN);
                        gensec_want_feature(conn->gensec, GENSEC_FEATURE_SEAL);
                        gensec_want_feature(conn->gensec, GENSEC_FEATURE_ASYNC_REPLIES);
@@ -180,9 +203,6 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
                        input = *req->creds.SASL.secblob;
                }
 
-               resp->SASL.secblob = talloc(reply, DATA_BLOB);
-               NT_STATUS_HAVE_NO_MEMORY(resp->SASL.secblob);
-
                status = gensec_update(conn->gensec, reply,
                                       input, &output);
 
@@ -199,26 +219,55 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
                errstr = NULL;
        } else if (NT_STATUS_IS_OK(status)) {
                struct auth_session_info *old_session_info=NULL;
-               struct ldapsrv_sasl_context *ctx;
+               struct ldapsrv_sasl_postprocess_context *context = NULL;
 
                result = LDAP_SUCCESS;
                errstr = NULL;
 
-               ctx = talloc(call, struct ldapsrv_sasl_context); 
+               if (gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) ||
+                   gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
 
-               if (!ctx) {
-                       status = NT_STATUS_NO_MEMORY;
-               } else {
-                       ctx->conn = conn;
-                       status = gensec_socket_init(conn->gensec, 
-                                                   conn->connection->socket,
-                                                   conn->connection->event.ctx, 
-                                                   stream_io_handler_callback,
-                                                   conn->connection,
-                                                   &ctx->sasl_socket);
-               } 
-
-               if (!ctx || !NT_STATUS_IS_OK(status)) {
+                       context = talloc(call, struct ldapsrv_sasl_postprocess_context);
+
+                       if (!context) {
+                               status = NT_STATUS_NO_MEMORY;
+                       }
+               }
+
+               if (context && conn->sockets.tls) {
+                       TALLOC_FREE(context);
+                       status = NT_STATUS_NOT_SUPPORTED;
+                       result = LDAP_UNWILLING_TO_PERFORM;
+                       errstr = talloc_asprintf(reply,
+                                                "SASL:[%s]: Sign or Seal are not allowed if TLS is used",
+                                                req->creds.SASL.mechanism);
+               }
+
+               if (context && conn->sockets.sasl) {
+                       TALLOC_FREE(context);
+                       status = NT_STATUS_NOT_SUPPORTED;
+                       result = LDAP_UNWILLING_TO_PERFORM;
+                       errstr = talloc_asprintf(reply,
+                                                "SASL:[%s]: Sign or Seal are not allowed if SASL encryption has already been set up",
+                                                req->creds.SASL.mechanism);
+               }
+
+               if (context) {
+                       context->conn = conn;
+                       status = gensec_create_tstream(context,
+                                                      context->conn->gensec,
+                                                      context->conn->sockets.raw,
+                                                      &context->sasl);
+                       if (NT_STATUS_IS_OK(status)) {
+                               if (!talloc_reference(context->sasl, conn->gensec)) {
+                                       status = NT_STATUS_NO_MEMORY;
+                               }
+                       }
+               }
+
+               if (result != LDAP_SUCCESS) {
+                       conn->session_info = old_session_info;
+               } else if (!NT_STATUS_IS_OK(status)) {
                        conn->session_info = old_session_info;
                        result = LDAP_OPERATIONS_ERROR;
                        errstr = talloc_asprintf(reply, 
@@ -226,9 +275,6 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
                                                 req->creds.SASL.mechanism, nt_errstr(status));
                } else {
 
-                       call->send_callback = ldapsrv_set_sasl;
-                       call->send_private = ctx;
-               
                        old_session_info = conn->session_info;
                        conn->session_info = NULL;
                        status = gensec_session_info(conn->gensec, &conn->session_info);
@@ -239,11 +285,11 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
                                                         "SASL:[%s]: Failed to get session info: %s", 
                                                         req->creds.SASL.mechanism, nt_errstr(status));
                        } else {
-                               talloc_free(old_session_info);
+                               talloc_unlink(conn, old_session_info);
                                talloc_steal(conn, conn->session_info);
                                
                                /* don't leak the old LDB */
-                               talloc_free(conn->ldb);
+                               talloc_unlink(conn, conn->ldb);
                                
                                status = ldapsrv_backend_Init(conn);            
                                
@@ -256,12 +302,22 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
                                }
                        }
                }
+
+               if (NT_STATUS_IS_OK(status) && context) {
+                       call->postprocess_send = ldapsrv_sasl_postprocess_send;
+                       call->postprocess_recv = ldapsrv_sasl_postprocess_recv;
+                       call->postprocess_private = context;
+               }
+               talloc_unlink(conn, conn->gensec);
+               conn->gensec = NULL;
        } else {
                status = auth_nt_status_squash(status);
                if (result == 0) {
                        result = LDAP_INVALID_CREDENTIALS;
                        errstr = talloc_asprintf(reply, "SASL:[%s]: %s", req->creds.SASL.mechanism, nt_errstr(status));
                }
+               talloc_unlink(conn, conn->gensec);
+               conn->gensec = NULL;
        }
 
        resp->response.resultcode = result;