r23792: convert Samba4 to GPLv3
[garming/samba-autobuild/.git] / source4 / libcli / raw / clisession.c
index 14018f676c3914f16ffe57058ff48007f48130ce..c6c575b818211e63125637b822896cb1fb9c27a7 100644 (file)
@@ -1,12 +1,13 @@
 /* 
    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
    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 "libcli/raw/libcliraw.h"
+#include "system/filesys.h"
 
 #define SETUP_REQUEST_SESSION(cmd, wct, buflen) do { \
        req = smbcli_request_setup_session(session, cmd, wct, buflen); \
 /****************************************************************************
  Initialize the session context
 ****************************************************************************/
-struct smbcli_session *smbcli_session_init(struct smbcli_transport *transport)
+struct smbcli_session *smbcli_session_init(struct smbcli_transport *transport, 
+                                          TALLOC_CTX *parent_ctx, BOOL primary)
 {
        struct smbcli_session *session;
        uint16_t flags2;
        uint32_t capabilities;
 
-       session = talloc_p(transport, struct smbcli_session);
+       session = talloc_zero(parent_ctx, struct smbcli_session);
        if (!session) {
                return NULL;
        }
 
-       ZERO_STRUCTP(session);
-       session->transport = talloc_reference(session, transport);
+       if (primary) {
+               session->transport = talloc_steal(session, transport);
+       } else {
+               session->transport = talloc_reference(session, transport);
+       }
        session->pid = (uint16_t)getpid();
        session->vuid = UID_FIELD_INVALID;
-
        
        capabilities = transport->negotiate.capabilities;
 
-       flags2 = FLAGS2_LONG_PATH_COMPONENTS;
+       flags2 = FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_EXTENDED_ATTRIBUTES;
 
        if (capabilities & CAP_UNICODE) {
                flags2 |= FLAGS2_UNICODE_STRINGS;
@@ -73,15 +77,12 @@ struct smbcli_session *smbcli_session_init(struct smbcli_transport *transport)
 /****************************************************************************
  Perform a session setup (async send)
 ****************************************************************************/
-struct smbcli_request *smb_raw_session_setup_send(struct smbcli_session *session, union smb_sesssetup *parms) 
+struct smbcli_request *smb_raw_sesssetup_send(struct smbcli_session *session, 
+                                             union smb_sesssetup *parms) 
 {
        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);
@@ -133,8 +134,11 @@ struct smbcli_request *smb_raw_session_setup_send(struct smbcli_session *session
                smbcli_req_append_blob(req, &parms->spnego.in.secblob);
                smbcli_req_append_string(req, parms->spnego.in.os, STR_TERMINATE);
                smbcli_req_append_string(req, parms->spnego.in.lanman, STR_TERMINATE);
-               smbcli_req_append_string(req, parms->spnego.in.domain, STR_TERMINATE);
+               smbcli_req_append_string(req, parms->spnego.in.workgroup, STR_TERMINATE);
                break;
+
+       case RAW_SESSSETUP_SMB2:
+               return NULL;
        }
 
        if (!smbcli_request_send(req)) {
@@ -149,12 +153,12 @@ struct smbcli_request *smb_raw_session_setup_send(struct smbcli_session *session
 /****************************************************************************
  Perform a session setup (async recv)
 ****************************************************************************/
-NTSTATUS smb_raw_session_setup_recv(struct smbcli_request *req, 
-                                   TALLOC_CTX *mem_ctx, 
-                                   union smb_sesssetup *parms) 
+NTSTATUS smb_raw_sesssetup_recv(struct smbcli_request *req, 
+                               TALLOC_CTX *mem_ctx, 
+                               union smb_sesssetup *parms) 
 {
        uint16_t len;
-       char *p;
+       uint8_t *p;
 
        if (!smbcli_request_receive(req)) {
                return smbcli_request_destroy(req);
@@ -165,11 +169,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);
@@ -213,7 +213,11 @@ NTSTATUS smb_raw_session_setup_recv(struct smbcli_request *req,
                p += parms->spnego.out.secblob.length;
                p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE);
                p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE);
-               p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.domain, p, -1, STR_TERMINATE);
+               p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.workgroup, p, -1, STR_TERMINATE);
+               break;
+
+       case RAW_SESSSETUP_SMB2:
+               req->status = NT_STATUS_INTERNAL_ERROR;
                break;
        }
 
@@ -221,358 +225,20 @@ 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 = session->transport->options.max_xmit;
-       s2.old.in.mpx_max = session->transport->options.max_mux;
-       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 = session->transport->options.max_xmit;
-       s2.nt1.in.mpx_max = session->transport->options.max_mux;
-       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 = session->transport->options.max_xmit;
-       s2.spnego.in.mpx_max = session->transport->options.max_mux;
-       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) 
+*/
+NTSTATUS smb_raw_sesssetup(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);
-       return smb_raw_session_setup_recv(req, mem_ctx, parms);
+       struct smbcli_request *req = smb_raw_sesssetup_send(session, parms);
+       return smb_raw_sesssetup_recv(req, mem_ctx, parms);
 }
 
 
 /****************************************************************************
- Send a uloggoff (async send)
+ Send a ulogoff (async send)
 *****************************************************************************/
 struct smbcli_request *smb_raw_ulogoff_send(struct smbcli_session *session)
 {
@@ -592,7 +258,7 @@ struct smbcli_request *smb_raw_ulogoff_send(struct smbcli_session *session)
 }
 
 /****************************************************************************
- Send a uloggoff (sync interface)
+ Send a ulogoff (sync interface)
 *****************************************************************************/
 NTSTATUS smb_raw_ulogoff(struct smbcli_session *session)
 {