r4777: added a smb_composite_sesssetup() async composite function. This
[gd/samba-autobuild/.git] / source4 / libcli / raw / clisession.c
index 75b964501870a50b946562821b37f8fa4052dc91..ed50601c25433be4909bdc3e433b79fdffa21378 100644 (file)
@@ -1,7 +1,8 @@
 /* 
    Unix SMB/CIFS implementation.
    SMB client session context management functions
-   Copyright (C) Andrew Tridgell 1994-1998
+
+   Copyright (C) Andrew Tridgell 1994-2005
    Copyright (C) James Myers 2003 <myersjj@samba.org>
    
    This program is free software; you can redistribute it and/or modify
 */
 
 #include "includes.h"
+#include "libcli/raw/libcliraw.h"
+#include "auth/auth.h"
 
 #define SETUP_REQUEST_SESSION(cmd, wct, buflen) do { \
        req = smbcli_request_setup_session(session, cmd, wct, buflen); \
        if (!req) return NULL; \
 } while (0)
 
+
 /****************************************************************************
  Initialize the session context
 ****************************************************************************/
 struct smbcli_session *smbcli_session_init(struct smbcli_transport *transport)
 {
        struct smbcli_session *session;
+       uint16_t flags2;
+       uint32_t capabilities;
 
-       session = talloc_p(transport, struct smbcli_session);
+       session = talloc_zero(transport, struct smbcli_session);
        if (!session) {
                return NULL;
        }
 
-       ZERO_STRUCTP(session);
-       session->transport = transport;
+       session->transport = talloc_reference(session, transport);
        session->pid = (uint16_t)getpid();
        session->vuid = UID_FIELD_INVALID;
-       session->transport->reference_count++;
+       
+       capabilities = transport->negotiate.capabilities;
 
-       return session;
-}
+       flags2 = FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_EXTENDED_ATTRIBUTES;
 
-/****************************************************************************
-reduce reference_count and destroy is <= 0
-****************************************************************************/
-void smbcli_session_close(struct smbcli_session *session)
-{
-       session->reference_count--;
-       if (session->reference_count <= 0) {
-               smbcli_transport_close(session->transport);
-               talloc_free(session);
+       if (capabilities & CAP_UNICODE) {
+               flags2 |= FLAGS2_UNICODE_STRINGS;
+       }
+       if (capabilities & CAP_STATUS32) {
+               flags2 |= FLAGS2_32_BIT_ERROR_CODES;
        }
+       if (capabilities & CAP_EXTENDED_SECURITY) {
+               flags2 |= FLAGS2_EXTENDED_SECURITY;
+       }
+       if (session->transport->negotiate.sign_info.doing_signing) {
+               flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+       }
+
+       session->flags2 = flags2;
+
+       return session;
 }
 
 /****************************************************************************
@@ -66,11 +77,7 @@ struct smbcli_request *smb_raw_session_setup_send(struct smbcli_session *session
 {
        struct smbcli_request *req = NULL;
 
-       switch (parms->generic.level) {
-       case RAW_SESSSETUP_GENERIC:
-               /* handled elsewhere */
-               return NULL;
-
+       switch (parms->old.level) {
        case RAW_SESSSETUP_OLD:
                SETUP_REQUEST_SESSION(SMBsesssetupX, 10, 0);
                SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
@@ -143,7 +150,7 @@ NTSTATUS smb_raw_session_setup_recv(struct smbcli_request *req,
                                    union smb_sesssetup *parms) 
 {
        uint16_t len;
-       char *p;
+       uint8_t *p;
 
        if (!smbcli_request_receive(req)) {
                return smbcli_request_destroy(req);
@@ -154,11 +161,7 @@ NTSTATUS smb_raw_session_setup_recv(struct smbcli_request *req,
                return smbcli_request_destroy(req);
        }
 
-       switch (parms->generic.level) {
-       case RAW_SESSSETUP_GENERIC:
-               /* handled elsewhere */
-               return NT_STATUS_INVALID_LEVEL;
-
+       switch (parms->old.level) {
        case RAW_SESSSETUP_OLD:
                SMBCLI_CHECK_WCT(req, 3);
                ZERO_STRUCT(parms->old.out);
@@ -210,352 +213,14 @@ failed:
        return smbcli_request_destroy(req);
 }
 
-/*
-  form an encrypted lanman password from a plaintext password
-  and the server supplied challenge
-*/
-static DATA_BLOB lanman_blob(const char *pass, DATA_BLOB challenge)
-{
-       DATA_BLOB blob = data_blob(NULL, 24);
-       SMBencrypt(pass, challenge.data, blob.data);
-       return blob;
-}
 
 /*
-  form an encrypted NT password from a plaintext password
-  and the server supplied challenge
-*/
-static DATA_BLOB nt_blob(const char *pass, DATA_BLOB challenge)
-{
-       DATA_BLOB blob = data_blob(NULL, 24);
-       SMBNTencrypt(pass, challenge.data, blob.data);
-       return blob;
-}
-
-/*
-  store the user session key for a transport
-*/
-void smbcli_session_set_user_session_key(struct smbcli_session *session,
-                                  const DATA_BLOB *session_key)
-{
-       session->user_session_key = data_blob_talloc(session, 
-                                                    session_key->data, 
-                                                    session_key->length);
-}
-
-/*
-  setup signing for a NT1 style session setup
-*/
-static void use_nt1_session_keys(struct smbcli_session *session, 
-                                const char *password, const DATA_BLOB  *nt_response)
-{
-       struct smbcli_transport *transport = session->transport; 
-       uint8_t nt_hash[16];
-       DATA_BLOB session_key = data_blob(NULL, 16);
-
-       E_md4hash(password, nt_hash);
-       SMBsesskeygen_ntv1(nt_hash, session_key.data);
-
-       smbcli_transport_simple_set_signing(transport, session_key, *nt_response);
-
-       smbcli_session_set_user_session_key(session, &session_key);
-       data_blob_free(&session_key);
-}
-
-/****************************************************************************
- Perform a session setup (sync interface) using generic interface and the old
- style sesssetup call
-****************************************************************************/
-static NTSTATUS smb_raw_session_setup_generic_old(struct smbcli_session *session, 
-                                                 TALLOC_CTX *mem_ctx, 
-                                                 union smb_sesssetup *parms) 
-{
-       NTSTATUS status;
-       union smb_sesssetup s2;
-
-       /* use the old interface */
-       s2.generic.level = RAW_SESSSETUP_OLD;
-       s2.old.in.bufsize = ~0;
-       s2.old.in.mpx_max = 50;
-       s2.old.in.vc_num = 1;
-       s2.old.in.sesskey = parms->generic.in.sesskey;
-       s2.old.in.domain = parms->generic.in.domain;
-       s2.old.in.user = parms->generic.in.user;
-       s2.old.in.os = "Unix";
-       s2.old.in.lanman = "Samba";
-       
-       if (!parms->generic.in.password) {
-               s2.old.in.password = data_blob(NULL, 0);
-       } else if (session->transport->negotiate.sec_mode & 
-                  NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
-               s2.old.in.password = lanman_blob(parms->generic.in.password, 
-                                                session->transport->negotiate.secblob);
-       } else {
-               s2.old.in.password = data_blob(parms->generic.in.password, 
-                                              strlen(parms->generic.in.password));
-       }
-       
-       status = smb_raw_session_setup(session, mem_ctx, &s2);
-       
-       data_blob_free(&s2.old.in.password);
-       
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       
-       parms->generic.out.vuid = s2.old.out.vuid;
-       parms->generic.out.os = s2.old.out.os;
-       parms->generic.out.lanman = s2.old.out.lanman;
-       parms->generic.out.domain = s2.old.out.domain;
-       
-       return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Perform a session setup (sync interface) using generic interface and the NT1
- style sesssetup call
-****************************************************************************/
-static NTSTATUS smb_raw_session_setup_generic_nt1(struct smbcli_session *session, 
-                                                 TALLOC_CTX *mem_ctx,
-                                                 union smb_sesssetup *parms) 
-{
-       NTSTATUS status;
-       union smb_sesssetup s2;
-
-       s2.generic.level = RAW_SESSSETUP_NT1;
-       s2.nt1.in.bufsize = ~0;
-       s2.nt1.in.mpx_max = 50;
-       s2.nt1.in.vc_num = 1;
-       s2.nt1.in.sesskey = parms->generic.in.sesskey;
-       s2.nt1.in.capabilities = parms->generic.in.capabilities;
-       s2.nt1.in.domain = parms->generic.in.domain;
-       s2.nt1.in.user = parms->generic.in.user;
-       s2.nt1.in.os = "Unix";
-       s2.nt1.in.lanman = "Samba";
-
-       if (!parms->generic.in.password) {
-               s2.nt1.in.password1 = data_blob(NULL, 0);
-               s2.nt1.in.password2 = data_blob(NULL, 0);
-       } else if (session->transport->negotiate.sec_mode & 
-                  NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
-               s2.nt1.in.password1 = lanman_blob(parms->generic.in.password, 
-                                                 session->transport->negotiate.secblob);
-               s2.nt1.in.password2 = nt_blob(parms->generic.in.password, 
-                                             session->transport->negotiate.secblob);
-               use_nt1_session_keys(session, parms->generic.in.password, &s2.nt1.in.password2);
-
-       } else {
-               s2.nt1.in.password1 = data_blob(parms->generic.in.password, 
-                                               strlen(parms->generic.in.password));
-               s2.nt1.in.password2 = data_blob(NULL, 0);
-       }
-
-       status = smb_raw_session_setup(session, mem_ctx, &s2);
-               
-       data_blob_free(&s2.nt1.in.password1);
-       data_blob_free(&s2.nt1.in.password2);
-               
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       parms->generic.out.vuid = s2.nt1.out.vuid;
-       parms->generic.out.os = s2.nt1.out.os;
-       parms->generic.out.lanman = s2.nt1.out.lanman;
-       parms->generic.out.domain = s2.nt1.out.domain;
-
-       return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Perform a session setup (sync interface) using generic interface and the SPNEGO
- style sesssetup call
-****************************************************************************/
-static NTSTATUS smb_raw_session_setup_generic_spnego(struct smbcli_session *session, 
-                                                 TALLOC_CTX *mem_ctx,
-                                                 union smb_sesssetup *parms) 
-{
-       NTSTATUS status;
-       NTSTATUS session_key_err = NT_STATUS_NO_USER_SESSION_KEY;
-       union smb_sesssetup s2;
-       DATA_BLOB session_key = data_blob(NULL, 0);
-       DATA_BLOB null_data_blob = data_blob(NULL, 0);
-       const char *chosen_oid;
-
-       s2.generic.level = RAW_SESSSETUP_SPNEGO;
-       s2.spnego.in.bufsize = ~0;
-       s2.spnego.in.mpx_max = 50;
-       s2.spnego.in.vc_num = 1;
-       s2.spnego.in.sesskey = parms->generic.in.sesskey;
-       s2.spnego.in.capabilities = parms->generic.in.capabilities;
-       s2.spnego.in.domain = parms->generic.in.domain;
-       s2.spnego.in.os = "Unix";
-       s2.spnego.in.lanman = "Samba";
-       s2.spnego.out.vuid = session->vuid;
-
-       smbcli_temp_set_signing(session->transport);
-
-       status = gensec_client_start(session, &session->gensec);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
-               goto done;
-       }
-
-       gensec_want_feature(session->gensec, GENSEC_WANT_SESSION_KEY);
-
-       status = gensec_set_domain(session->gensec, parms->generic.in.domain);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n", 
-                         parms->generic.in.domain, nt_errstr(status)));
-               goto done;
-       }
-
-       status = gensec_set_username(session->gensec, parms->generic.in.user);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n", 
-                         parms->generic.in.user, nt_errstr(status)));
-               goto done;
-       }
-
-       status = gensec_set_password(session->gensec, parms->generic.in.password);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC client password: %s\n", 
-                         nt_errstr(status)));
-               goto done;
-       }
-
-       status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
-                         nt_errstr(status)));
-               goto done;
-       }
-
-       if (session->transport->negotiate.secblob.length) {
-               chosen_oid = OID_SPNEGO;
-       } else {
-               /* without a sec blob, means raw NTLMSSP */
-               chosen_oid = OID_NTLMSSP;
-       }
-
-       status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism %s: %s\n",
-                         gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
-               goto done;
-       }
-       
-       status = gensec_update(session->gensec, mem_ctx,
-                              session->transport->negotiate.secblob,
-                              &s2.spnego.in.secblob);
-
-       while(1) {
-               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
-                       break;
-               }
-
-               if (!NT_STATUS_IS_OK(session_key_err)) {
-                       session_key_err = gensec_session_key(session->gensec, &session_key);
-               }
-               if (NT_STATUS_IS_OK(session_key_err)) {
-                       smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob);
-               }
-               
-               if (NT_STATUS_IS_OK(status) && s2.spnego.in.secblob.length == 0) {
-                       break;
-               }
-
-               session->vuid = s2.spnego.out.vuid;
-               status = smb_raw_session_setup(session, mem_ctx, &s2);
-               session->vuid = UID_FIELD_INVALID;
-               if (!NT_STATUS_IS_OK(status) &&
-                   !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-                       break;
-               }
-
-               status = gensec_update(session->gensec, mem_ctx,
-                                      s2.spnego.out.secblob,
-                                      &s2.spnego.in.secblob);
-
-       }
-
-done:
-       if (NT_STATUS_IS_OK(status)) {
-               if (!NT_STATUS_IS_OK(session_key_err)) {
-                       DEBUG(1, ("Failed to get user session key: %s\n", nt_errstr(session_key_err)));
-                       return session_key_err;
-               }
-
-               smbcli_session_set_user_session_key(session, &session_key);
-
-               parms->generic.out.vuid = s2.spnego.out.vuid;
-               parms->generic.out.os = s2.spnego.out.os;
-               parms->generic.out.lanman = s2.spnego.out.lanman;
-               parms->generic.out.domain = s2.spnego.out.domain;
-       } else {
-               gensec_end(&session->gensec);
-               DEBUG(1, ("Failed to login with %s: %s\n", gensec_get_name_by_oid(chosen_oid), nt_errstr(status)));
-               return status;
-       }
-
-       return status;
-}
-
-/****************************************************************************
- Perform a session setup (sync interface) using generic interface
-****************************************************************************/
-static NTSTATUS smb_raw_session_setup_generic(struct smbcli_session *session, 
-                                             TALLOC_CTX *mem_ctx,
-                                             union smb_sesssetup *parms) 
-{
-       if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
-               /* no session setup at all in earliest protocols */
-               ZERO_STRUCT(parms->generic.out);
-               return NT_STATUS_OK;
-       }
-
-       /* see if we need to use the original session setup interface */
-       if (session->transport->negotiate.protocol < PROTOCOL_NT1) {
-               return smb_raw_session_setup_generic_old(session, mem_ctx, parms);
-       }
-
-       /* see if we should use the NT1 interface */
-       if (!session->transport->options.use_spnego ||
-           !(parms->generic.in.capabilities & CAP_EXTENDED_SECURITY)) {
-               return smb_raw_session_setup_generic_nt1(session, mem_ctx, parms);
-       }
-
-       /* default to using SPNEGO/NTLMSSP */
-       return smb_raw_session_setup_generic_spnego(session, mem_ctx, parms);
-}
-
-
-/****************************************************************************
  Perform a session setup (sync interface)
-this interface allows for RAW_SESSSETUP_GENERIC to auto-select session
-setup variant based on negotiated protocol options
-****************************************************************************/
+*/
 NTSTATUS smb_raw_session_setup(struct smbcli_session *session, TALLOC_CTX *mem_ctx, 
                               union smb_sesssetup *parms) 
 {
-       struct smbcli_request *req;
-
-       if (parms->generic.level == RAW_SESSSETUP_GENERIC) {
-               NTSTATUS ret = smb_raw_session_setup_generic(session, mem_ctx, parms);
-
-               if (NT_STATUS_IS_OK(ret) 
-                   && parms->generic.in.user 
-                   && *parms->generic.in.user) {
-                       if (!session->transport->negotiate.sign_info.doing_signing 
-                           && session->transport->negotiate.sign_info.mandatory_signing) {
-                               DEBUG(0, ("SMB signing required, but server does not support it\n"));
-                               return NT_STATUS_ACCESS_DENIED;
-                       }
-               }
-               return ret;
-       }
-
-       req = smb_raw_session_setup_send(session, parms);
+       struct smbcli_request *req = smb_raw_session_setup_send(session, parms);
        return smb_raw_session_setup_recv(req, mem_ctx, parms);
 }
 
@@ -591,16 +256,27 @@ NTSTATUS smb_raw_ulogoff(struct smbcli_session *session)
 
 
 /****************************************************************************
- Send a SMBexit
-****************************************************************************/
-NTSTATUS smb_raw_exit(struct smbcli_session *session)
+ Send a exit (async send)
+*****************************************************************************/
+struct smbcli_request *smb_raw_exit_send(struct smbcli_session *session)
 {
        struct smbcli_request *req;
 
-       req = smbcli_request_setup_session(session, SMBexit, 0, 0);
+       SETUP_REQUEST_SESSION(SMBexit, 0, 0);
 
-       if (smbcli_request_send(req)) {
-               smbcli_request_receive(req);
+       if (!smbcli_request_send(req)) {
+               smbcli_request_destroy(req);
+               return NULL;
        }
-       return smbcli_request_destroy(req);
+
+       return req;
+}
+
+/****************************************************************************
+ Send a exit (sync interface)
+*****************************************************************************/
+NTSTATUS smb_raw_exit(struct smbcli_session *session)
+{
+       struct smbcli_request *req = smb_raw_exit_send(session);
+       return smbcli_request_simple_recv(req);
 }