r5729: partial fixes for BUG 2308; libsmbclient patches from Derrell Lipman <derrell...
[gd/samba/.git] / source3 / libsmb / cliconnect.c
index adfeec229049259d2e76222948a4c0f0bf03fd41..aa37a29391c53e131116e1ce1d2a200f8a850973 100644 (file)
@@ -40,6 +40,18 @@ static const struct {
        {-1,NULL}
 };
 
+/**
+ * Set the user session key for a connection
+ * @param cli The cli structure to add it too
+ * @param session_key The session key used.  (A copy of this is taken for the cli struct)
+ *
+ */
+
+static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key) 
+{
+       cli->user_session_key = data_blob(session_key.data, session_key.length);
+}
+
 /****************************************************************************
  Do an old lanman2 style session setup.
 ****************************************************************************/
@@ -47,6 +59,8 @@ static const struct {
 static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user, 
                                      const char *pass, size_t passlen, const char *workgroup)
 {
+       DATA_BLOB session_key = data_blob(NULL, 0);
+       DATA_BLOB lm_response = data_blob(NULL, 0);
        fstring pword;
        char *p;
 
@@ -66,14 +80,18 @@ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
 
        if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
                /* Encrypted mode needed, and non encrypted password supplied. */
-               passlen = 24;
-               SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
+               lm_response = data_blob(NULL, 24);
+               if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
+                       DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
+                       return False;
+               }
        } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
                /* Encrypted mode needed, and encrypted password supplied. */
-               memcpy(pword, pass, passlen);
+               lm_response = data_blob(pass, passlen);
        } else if (passlen > 0) {
                /* Plaintext mode needed, assume plaintext supplied. */
                passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+               lm_response = data_blob(pass, passlen);
        }
 
        /* send a session setup command */
@@ -87,11 +105,11 @@ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
        SSVAL(cli->outbuf,smb_vwv3,2);
        SSVAL(cli->outbuf,smb_vwv4,1);
        SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
-       SSVAL(cli->outbuf,smb_vwv7,passlen);
+       SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
 
        p = smb_buf(cli->outbuf);
-       memcpy(p,pword,passlen);
-       p += passlen;
+       memcpy(p,lm_response.data,lm_response.length);
+       p += lm_response.length;
        p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
        p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
        p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
@@ -111,6 +129,11 @@ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
        cli->vuid = SVAL(cli->inbuf,smb_uid);   
        fstrcpy(cli->user_name, user);
 
+       if (session_key.data) {
+               /* Have plaintext orginal */
+               cli_set_session_key(cli, session_key);
+       }
+
        return True;
 }
 
@@ -128,12 +151,7 @@ static uint32 cli_session_setup_capabilities(struct cli_state *cli)
        if (cli->use_level_II_oplocks)
                capabilities |= CAP_LEVEL_II_OPLOCKS;
 
-       if (cli->capabilities & CAP_UNICODE)
-               capabilities |= CAP_UNICODE;
-
-       if (cli->capabilities & CAP_LARGE_FILES)
-               capabilities |= CAP_LARGE_FILES;
-
+       capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
        return capabilities;
 }
 
@@ -248,18 +266,6 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user,
        return True;
 }
 
-/**
- * Set the user session key for a connection
- * @param cli The cli structure to add it too
- * @param session_key The session key used.  (A copy of this is taken for the cli struct)
- *
- */
-
-static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key) 
-{
-       cli->user_session_key = data_blob(session_key.data, session_key.length);
-}
-
 /****************************************************************************
    do a NT1 NTLM/LM encrypted session setup - for when extended security
    is not negotiated.
@@ -310,22 +316,39 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
                        uchar nt_hash[16];
                        E_md4hash(pass, nt_hash);
 
+#ifdef LANMAN_ONLY
+                       nt_response = data_blob(NULL, 0);
+#else
                        nt_response = data_blob(NULL, 24);
                        SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
-
+#endif
                        /* non encrypted password supplied. Ignore ntpass. */
                        if (lp_client_lanman_auth()) {
                                lm_response = data_blob(NULL, 24);
-                               SMBencrypt(pass,cli->secblob.data, lm_response.data);
+                               if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
+                                       /* Oops, the LM response is invalid, just put 
+                                          the NT response there instead */
+                                       data_blob_free(&lm_response);
+                                       lm_response = data_blob(nt_response.data, nt_response.length);
+                               }
                        } else {
                                /* LM disabled, place NT# in LM field instead */
                                lm_response = data_blob(nt_response.data, nt_response.length);
                        }
 
                        session_key = data_blob(NULL, 16);
+#ifdef LANMAN_ONLY
+                       E_deshash(pass, session_key.data);
+                       memset(&session_key.data[8], '\0', 8);
+#else
                        SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+#endif
                }
+#ifdef LANMAN_ONLY
+               cli_simple_set_signing(cli, session_key, lm_response); 
+#else
                cli_simple_set_signing(cli, session_key, nt_response); 
+#endif
        } else {
                /* pre-encrypted password supplied.  Only used for 
                   security=server, can't do
@@ -396,9 +419,7 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
 end:   
        data_blob_free(&lm_response);
        data_blob_free(&nt_response);
-
-       if (!ret)
-               data_blob_free(&session_key);
+       data_blob_free(&session_key);
        return ret;
 }
 
@@ -533,6 +554,7 @@ static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *
        cli_set_session_key(cli, session_key_krb5);
 
        data_blob_free(&negTokenTarg);
+       data_blob_free(&session_key_krb5);
 
        if (cli_is_error(cli)) {
                if (NT_STATUS_IS_OK(cli_nt_error(cli))) {
@@ -555,9 +577,9 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
        NTSTATUS nt_status;
        int turn = 1;
        DATA_BLOB msg1;
-       DATA_BLOB blob;
+       DATA_BLOB blob = data_blob(NULL, 0);
        DATA_BLOB blob_in = data_blob(NULL, 0);
-       DATA_BLOB blob_out;
+       DATA_BLOB blob_out = data_blob(NULL, 0);
 
        cli_temp_set_signing(cli);
 
@@ -590,7 +612,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                
                        /* now send that blob on its way */
                        if (!cli_session_setup_blob_send(cli, msg1)) {
-                               DEBUG(3, ("Failed to send NTLMSSP/SPENGO blob to server!\n"));
+                               DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
                                nt_status = NT_STATUS_UNSUCCESSFUL;
                        } else {
                                data_blob_free(&msg1);
@@ -641,17 +663,22 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
                                          ntlmssp_state->session_key.length);
                DATA_BLOB null_blob = data_blob(NULL, 0);
+               BOOL res;
 
                fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
                cli_set_session_key(cli, ntlmssp_state->session_key);
 
-               if (cli_simple_set_signing(cli, key, null_blob)) {
+               res = cli_simple_set_signing(cli, key, null_blob);
+
+               data_blob_free(&key);
+
+               if (res) {
                        
                        /* 'resign' the last message, so we get the right sequence numbers
                           for checking the first reply from the server */
                        cli_calculate_sign_mac(cli);
                        
-                       if (!cli_check_sign_mac(cli, False)) {
+                       if (!cli_check_sign_mac(cli)) {
                                nt_status = NT_STATUS_ACCESS_DENIED;
                        }
                }
@@ -719,23 +746,32 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
         * and do not store results */
 
        if (got_kerberos_mechanism && cli->use_kerberos) {
+               ADS_STATUS rc;
+
                if (pass && *pass) {
                        int ret;
                        
                        use_in_memory_ccache();
-                       ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
+                       ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL, NULL);
                        
                        if (ret){
+                               SAFE_FREE(principal);
                                DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
+                               if (cli->fallback_after_kerberos)
+                                       goto ntlmssp;
                                return ADS_ERROR_KRB5(ret);
                        }
                }
                
-               return cli_session_setup_kerberos(cli, principal, domain);
+               rc = cli_session_setup_kerberos(cli, principal, domain);
+               if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
+                       SAFE_FREE(principal);
+                       return rc;
+               }
        }
 #endif
 
-       free(principal);
+       SAFE_FREE(principal);
 
 ntlmssp:
 
@@ -822,7 +858,7 @@ BOOL cli_session_setup(struct cli_state *cli,
        if (cli->capabilities & CAP_EXTENDED_SECURITY) {
                ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup);
                if (!ADS_ERR_OK(status)) {
-                       DEBUG(3, ("SPENGO login failed: %s\n", ads_errstr(status)));
+                       DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
                        return False;
                }
                return True;
@@ -852,7 +888,12 @@ BOOL cli_ulogoff(struct cli_state *cli)
        if (!cli_receive_smb(cli))
                return False;
 
-       return !cli_is_error(cli);
+       if (cli_is_error(cli)) {
+               return False;
+       }
+
+        cli->cnum = -1;
+        return True;
 }
 
 /****************************************************************************
@@ -936,6 +977,9 @@ BOOL cli_send_tconX(struct cli_state *cli,
                /* almost certainly win95 - enable bug fixes */
                cli->win95 = True;
        }
+       
+       if ( cli->protocol >= PROTOCOL_LANMAN2 )
+               cli->dfsroot = (SVAL( cli->inbuf, smb_vwv2 ) & SMB_SHARE_IN_DFS);
 
        cli->cnum = SVAL(cli->inbuf,smb_tid);
        return True;
@@ -957,7 +1001,12 @@ BOOL cli_tdis(struct cli_state *cli)
        if (!cli_receive_smb(cli))
                return False;
        
-       return !cli_is_error(cli);
+       if (cli_is_error(cli)) {
+               return False;
+       }
+
+       cli->cnum = -1;
+       return True;
 }
 
 /****************************************************************************
@@ -1097,10 +1146,19 @@ BOOL cli_negprot(struct cli_state *cli)
                        cli->sign_info.negotiated_smb_signing = True;
                }
 
+               if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
+                       SAFE_FREE(cli->outbuf);
+                       SAFE_FREE(cli->inbuf);
+                       cli->outbuf = (char *)SMB_MALLOC(CLI_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
+                       cli->inbuf = (char *)SMB_MALLOC(CLI_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
+                       cli->bufsize = CLI_MAX_LARGE_READX_SIZE;
+               }
+
        } else if (cli->protocol >= PROTOCOL_LANMAN1) {
                cli->use_spnego = False;
                cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
                cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
+               cli->max_mux = SVAL(cli->inbuf, smb_vwv3); 
                cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
                cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
                cli->serverzone *= 60;