ldb: use #include <ldb.h> for ldb
[kai/samba.git] / source4 / ldap_server / ldap_bind.c
index f88d08e822db2bd7f0129b6e1c6eb9ef82e87f5d..0f3d0631d009df845d18c5f4eceb82a8b90e91db 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #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/socket.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)
 {
@@ -45,13 +45,16 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 
        DEBUG(10, ("BindSimple dn: %s\n",req->dn));
 
-       status = crack_dn_to_nt4_name(call, req->dn, &nt4_domain, &nt4_account);
+       status = crack_auto_name_to_nt4_name(call, call->conn->connection->event.ctx, call->conn->lp_ctx, req->dn, &nt4_domain, &nt4_account);
        if (NT_STATUS_IS_OK(status)) {
                status = authenticate_username_pw(call,
                                                  call->conn->connection->event.ctx,
                                                  call->conn->connection->msg_ctx,
+                                                 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;
+       }
 
-       ctx->conn->sockets.sasl = ctx->sasl_socket;
-       ctx->conn->connection->socket = ctx->sasl_socket;
-       packet_set_socket(ctx->conn->packet, ctx->conn->connection->socket);
+       TALLOC_FREE(context->conn->sockets.sasl);
+       context->conn->sockets.sasl = talloc_move(context->conn, &context->sasl);
+       context->conn->sockets.active = context->conn->sockets.sasl;
+
+       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,21 +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->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);
@@ -179,20 +203,13 @@ 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);
 
-               /* TODO: gensec should really handle the difference between NULL and length=0 better! */
-               if (output.data) {
-                       resp->SASL.secblob = talloc(reply, DATA_BLOB);
-                       NT_STATUS_HAVE_NO_MEMORY(resp->SASL.secblob);
-                       *resp->SASL.secblob = output;
-               } else {
-                       resp->SASL.secblob = NULL;
-               }
+               /* Windows 2000 mmc doesn't like secblob == NULL and reports a decoding error */
+               resp->SASL.secblob = talloc(reply, DATA_BLOB);
+               NT_STATUS_HAVE_NO_MEMORY(resp->SASL.secblob);
+               *resp->SASL.secblob = output;
        } else {
                resp->SASL.secblob = NULL;
        }
@@ -202,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, 
@@ -229,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);
@@ -242,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);            
                                
@@ -259,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;