r19598: Ahead of a merge to current lorikeet-heimdal:
[jelmer/samba4-debian.git] / source / libcli / smb_composite / sesssetup.c
index a62386b67212cccf557dc612522d4072f34bb283..8528ac2ef7cd72b98213a42831423a6dd326e286 100644 (file)
 #include "libcli/raw/libcliraw.h"
 #include "libcli/composite/composite.h"
 #include "libcli/smb_composite/smb_composite.h"
-#include "auth/credentials/credentials.h"
-#include "libcli/auth/proto.h"
+#include "libcli/auth/libcli_auth.h"
 #include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "auth/credentials/credentials.h"
 #include "version.h"
 
 struct sesssetup_state {
@@ -37,6 +38,18 @@ struct sesssetup_state {
        struct smbcli_request *req;
 };
 
+static NTSTATUS session_setup_old(struct composite_context *c,
+                                 struct smbcli_session *session, 
+                                 struct smb_composite_sesssetup *io,
+                                 struct smbcli_request **req); 
+static NTSTATUS session_setup_nt1(struct composite_context *c,
+                                 struct smbcli_session *session, 
+                                 struct smb_composite_sesssetup *io,
+                                 struct smbcli_request **req); 
+static NTSTATUS session_setup_spnego(struct composite_context *c,
+                                    struct smbcli_session *session, 
+                                    struct smb_composite_sesssetup *io,
+                                    struct smbcli_request **req);
 
 /*
   store the user session key for a transport
@@ -59,21 +72,68 @@ static void request_handler(struct smbcli_request *req)
        struct smbcli_session *session = req->session;
        DATA_BLOB session_key = data_blob(NULL, 0);
        DATA_BLOB null_data_blob = data_blob(NULL, 0);
-       NTSTATUS session_key_err;
+       NTSTATUS session_key_err, nt_status;
 
        c->status = smb_raw_sesssetup_recv(req, state, &state->setup);
 
        switch (state->setup.old.level) {
        case RAW_SESSSETUP_OLD:
                state->io->out.vuid = state->setup.old.out.vuid;
+               /* This doesn't work, as this only happens on old
+                * protocols, where this comparison won't match. */
+               if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
+                       /* we neet to reset the vuid for a new try */
+                       session->vuid = 0;
+                       if (cli_credentials_wrong_password(state->io->in.credentials)) {
+                               nt_status = session_setup_old(c, session, 
+                                                             state->io, 
+                                                             &state->req);
+                               if (NT_STATUS_IS_OK(nt_status)) {
+                                       c->status = nt_status;
+                                       state->req->async.fn = request_handler;
+                                       state->req->async.private = c;
+                                       return;
+                               }
+                       }
+               }
                break;
 
        case RAW_SESSSETUP_NT1:
                state->io->out.vuid = state->setup.nt1.out.vuid;
+               if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
+                       /* we neet to reset the vuid for a new try */
+                       session->vuid = 0;
+                       if (cli_credentials_wrong_password(state->io->in.credentials)) {
+                               nt_status = session_setup_nt1(c, session, 
+                                                             state->io, 
+                                                             &state->req);
+                               if (NT_STATUS_IS_OK(nt_status)) {
+                                       c->status = nt_status;
+                                       state->req->async.fn = request_handler;
+                                       state->req->async.private = c;
+                                       return;
+                               }
+                       }
+               }
                break;
 
        case RAW_SESSSETUP_SPNEGO:
-               session->vuid = state->io->out.vuid = state->setup.spnego.out.vuid;
+               state->io->out.vuid = state->setup.spnego.out.vuid;
+               if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
+                       /* we neet to reset the vuid for a new try */
+                       session->vuid = 0;
+                       if (cli_credentials_wrong_password(state->io->in.credentials)) {
+                               nt_status = session_setup_spnego(c, session, 
+                                                                     state->io, 
+                                                                     &state->req);
+                               if (NT_STATUS_IS_OK(nt_status)) {
+                                       c->status = nt_status;
+                                       state->req->async.fn = request_handler;
+                                       state->req->async.private = c;
+                                       return;
+                               }
+                       }
+               }
                if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
                    !NT_STATUS_IS_OK(c->status)) {
                        break;
@@ -108,11 +168,23 @@ static void request_handler(struct smbcli_request *req)
                }
 
                if (state->setup.spnego.in.secblob.length) {
+                       /* 
+                        * set the session->vuid value only for calling
+                        * smb_raw_sesssetup_send()
+                        */
+                       uint16_t vuid = session->vuid;
+                       session->vuid = state->io->out.vuid;
                        state->req = smb_raw_sesssetup_send(session, &state->setup);
+                       session->vuid = vuid;
                        state->req->async.fn = request_handler;
                        state->req->async.private = c;
                        return;
                }
+               break;
+
+       case RAW_SESSSETUP_SMB2:
+               c->status = NT_STATUS_INTERNAL_ERROR;
+               break;
        }
 
        /* enforce the local signing required flag */
@@ -179,6 +251,7 @@ static NTSTATUS session_setup_nt1(struct composite_context *c,
                                                              &state->setup.nt1.in.password1,
                                                              &state->setup.nt1.in.password2,
                                                              NULL, &session_key);
+               NT_STATUS_NOT_OK_RETURN(nt_status);
 
                smbcli_transport_simple_set_signing(session->transport, session_key, 
                                                    state->setup.nt1.in.password2);
@@ -242,6 +315,7 @@ static NTSTATUS session_setup_old(struct composite_context *c,
                                                              &state->setup.old.in.password,
                                                              NULL,
                                                              NULL, &session_key);
+               NT_STATUS_NOT_OK_RETURN(nt_status);
                set_user_session_key(session, &session_key);
                
                data_blob_free(&session_key);
@@ -284,8 +358,6 @@ static NTSTATUS session_setup_spnego(struct composite_context *c,
        state->setup.spnego.in.lanman       = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
        state->setup.spnego.in.workgroup    = io->in.workgroup;
 
-       state->setup.spnego.out.vuid        = session->vuid;
-
        smbcli_temp_set_signing(session->transport);
 
        status = gensec_client_start(session, &session->gensec, c->event_ctx);
@@ -403,7 +475,7 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se
        /* no session setup at all in earliest protocol varients */
        if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
                ZERO_STRUCT(io->out);
-               c->state = COMPOSITE_STATE_DONE;
+               composite_done(c);
                return c;
        }