r23779: Change from v2 or later to v3 or later.
[samba.git] / source3 / libsmb / cliconnect.c
index 2742d70194b4949d5445cac9567724ba83ce0055..7c72c006733e0a0ebe3b1e2c9c44eb98821792c0 100644 (file)
@@ -6,7 +6,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,
@@ -61,8 +61,8 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
                                          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);
+       DATA_BLOB session_key = data_blob_null;
+       DATA_BLOB lm_response = data_blob_null;
        fstring pword;
        char *p;
 
@@ -99,7 +99,7 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
 
        /* send a session setup command */
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,10, 0, True);
+       set_message(NULL,cli->outbuf,10, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
        
@@ -169,7 +169,7 @@ static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
        uint32 capabilities = cli_session_setup_capabilities(cli);
 
        memset(cli->outbuf, '\0', smb_size);
-       set_message(cli->outbuf,13,0,True);
+       set_message(NULL,cli->outbuf,13,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
                        
@@ -229,7 +229,7 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
        fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
 
        memset(cli->outbuf, '\0', smb_size);
-       set_message(cli->outbuf,13,0,True);
+       set_message(NULL,cli->outbuf,13,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
                        
@@ -299,9 +299,9 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
                                      const char *workgroup)
 {
        uint32 capabilities = cli_session_setup_capabilities(cli);
-       DATA_BLOB lm_response = data_blob(NULL, 0);
-       DATA_BLOB nt_response = data_blob(NULL, 0);
-       DATA_BLOB session_key = data_blob(NULL, 0);
+       DATA_BLOB lm_response = data_blob_null;
+       DATA_BLOB nt_response = data_blob_null;
+       DATA_BLOB session_key = data_blob_null;
        NTSTATUS result;
        char *p;
 
@@ -334,7 +334,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
                        E_md4hash(pass, nt_hash);
 
 #ifdef LANMAN_ONLY
-                       nt_response = data_blob(NULL, 0);
+                       nt_response = data_blob_null;
 #else
                        nt_response = data_blob(NULL, 24);
                        SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
@@ -378,7 +378,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
        /* send a session setup command */
        memset(cli->outbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,13,0,True);
+       set_message(NULL,cli->outbuf,13,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
        cli_setup_packet(cli);
                        
@@ -458,7 +458,7 @@ static BOOL cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
        /* send a session setup command */
        memset(cli->outbuf,'\0',smb_size);
 
-       set_message(cli->outbuf,12,0,True);
+       set_message(NULL,cli->outbuf,12,0,True);
        SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
 
        cli_setup_packet(cli);
@@ -485,7 +485,7 @@ static BOOL cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
 
 static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
 {
-       DATA_BLOB blob2 = data_blob(NULL, 0);
+       DATA_BLOB blob2 = data_blob_null;
        char *p;
        size_t len;
 
@@ -517,19 +517,78 @@ static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
 }
 
 #ifdef HAVE_KRB5
-
 /****************************************************************************
  Send a extended security session setup blob, returning a reply blob.
 ****************************************************************************/
 
-static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
+/* The following is calculated from :
+ * (smb_size-4) = 35
+ * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
+ * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
+ * end of packet.
+ */
+
+#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
+
+static BOOL cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob, DATA_BLOB session_key_krb5)
 {
-       DATA_BLOB blob2 = data_blob(NULL, 0);
-       if (!cli_session_setup_blob_send(cli, blob)) {
-               return blob2;
+       int32 remaining = blob.length;
+       int32 cur = 0;
+       DATA_BLOB send_blob = data_blob_null;
+       int32 max_blob_size = 0;
+       DATA_BLOB receive_blob = data_blob_null;
+
+       if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
+               DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small "
+                       "(was %u, need minimum %u)\n",
+                       (unsigned int)cli->max_xmit,
+                       BASE_SESSSETUP_BLOB_PACKET_SIZE));
+               cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER);
+               return False;
        }
-               
-       return cli_session_setup_blob_receive(cli);
+
+       max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE;
+
+       while ( remaining > 0) {
+               if (remaining >= max_blob_size) {
+                       send_blob.length = max_blob_size;
+                       remaining -= max_blob_size;
+               } else {
+                       DATA_BLOB null_blob = data_blob_null;
+
+                       send_blob.length = remaining; 
+                        remaining = 0;
+
+                       /* This is the last packet in the sequence - turn signing on. */
+                       cli_simple_set_signing(cli, session_key_krb5, null_blob); 
+               }
+
+               send_blob.data =  &blob.data[cur];
+               cur += send_blob.length;
+
+               DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n", 
+                       (unsigned int)remaining,
+                       (unsigned int)send_blob.length,
+                       (unsigned int)cur ));
+
+               if (!cli_session_setup_blob_send(cli, send_blob)) {
+                       DEBUG(0, ("cli_session_setup_blob: send failed\n"));
+                       return False;
+               }
+
+               receive_blob = cli_session_setup_blob_receive(cli);
+               data_blob_free(&receive_blob);
+
+               if (cli_is_error(cli) &&
+                               !NT_STATUS_EQUAL( cli_get_nt_error(cli), 
+                                       NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+                       DEBUG(0, ("cli_session_setup_blob: recieve failed (%s)\n",
+                               nt_errstr(cli_get_nt_error(cli)) ));
+                       return False;
+               }
+       }
+
+       return True;
 }
 
 /****************************************************************************
@@ -546,9 +605,8 @@ static void use_in_memory_ccache(void) {
 
 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
 {
-       DATA_BLOB blob2, negTokenTarg;
+       DATA_BLOB negTokenTarg;
        DATA_BLOB session_key_krb5;
-       DATA_BLOB null_blob = data_blob(NULL, 0);
        int rc;
 
        DEBUG(2,("Doing kerberos session setup\n"));
@@ -557,7 +615,8 @@ static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *
        rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
 
        if (rc) {
-               DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc)));
+               DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n",
+                       error_message(rc)));
                return ADS_ERROR_KRB5(rc);
        }
 
@@ -565,12 +624,11 @@ static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *
        file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
 #endif
 
-       cli_simple_set_signing(cli, session_key_krb5, null_blob); 
-                       
-       blob2 = cli_session_setup_blob(cli, negTokenTarg);
-
-       /* we don't need this blob for kerberos */
-       data_blob_free(&blob2);
+       if (!cli_session_setup_blob(cli, negTokenTarg, session_key_krb5)) {
+               data_blob_free(&negTokenTarg);
+               data_blob_free(&session_key_krb5);
+               ADS_ERROR_NT(cli_nt_error(cli));
+       }
 
        cli_set_session_key(cli, session_key_krb5);
 
@@ -598,9 +656,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(NULL, 0);
-       DATA_BLOB blob_in = data_blob(NULL, 0);
-       DATA_BLOB blob_out = data_blob(NULL, 0);
+       DATA_BLOB blob = data_blob_null;
+       DATA_BLOB blob_in = data_blob_null;
+       DATA_BLOB blob_out = data_blob_null;
 
        cli_temp_set_signing(cli);
 
@@ -637,8 +695,6 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                                DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
                                nt_status = NT_STATUS_UNSUCCESSFUL;
                        } else {
-                               data_blob_free(&msg1);
-                               
                                blob = cli_session_setup_blob_receive(cli);
                                
                                nt_status = cli_nt_error(cli);
@@ -650,6 +706,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                                        }
                                }
                        }
+                       data_blob_free(&msg1);
                }
                
                if (!blob.length) {
@@ -658,7 +715,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                        }
                } else if ((turn == 1) && 
                           NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-                       DATA_BLOB tmp_blob = data_blob(NULL, 0);
+                       DATA_BLOB tmp_blob = data_blob_null;
                        /* the server might give us back two challenges */
                        if (!spnego_parse_challenge(blob, &blob_in, 
                                                    &tmp_blob)) {
@@ -667,7 +724,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                        }
                        data_blob_free(&tmp_blob);
                } else {
-                       if (!spnego_parse_auth_response(blob, nt_status, 
+                       if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP, 
                                                        &blob_in)) {
                                DEBUG(3,("Failed to parse auth response\n"));
                                if (NT_STATUS_IS_OK(nt_status) 
@@ -680,11 +737,13 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                turn++;
        } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
 
+       data_blob_free(&blob_in);
+
        if (NT_STATUS_IS_OK(nt_status)) {
 
                DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
                                          ntlmssp_state->session_key.length);
-               DATA_BLOB null_blob = data_blob(NULL, 0);
+               DATA_BLOB null_blob = data_blob_null;
                BOOL res;
 
                fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
@@ -706,7 +765,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
                }
        }
 
-       /* we have a reference conter on ntlmssp_state, if we are signing
+       /* we have a reference counter on ntlmssp_state, if we are signing
           then the state will be kept by the signing engine */
 
        ntlmssp_end(&ntlmssp_state);
@@ -916,7 +975,6 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
        }
 
        return NT_STATUS_OK;
-
 }
 
 /****************************************************************************
@@ -926,7 +984,7 @@ NTSTATUS cli_session_setup(struct cli_state *cli,
 BOOL cli_ulogoff(struct cli_state *cli)
 {
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,2,0,True);
+       set_message(NULL,cli->outbuf,2,0,True);
        SCVAL(cli->outbuf,smb_com,SMBulogoffX);
        cli_setup_packet(cli);
        SSVAL(cli->outbuf,smb_vwv0,0xFF);
@@ -1003,11 +1061,12 @@ BOOL cli_send_tconX(struct cli_state *cli,
        slprintf(fullshare, sizeof(fullshare)-1,
                 "\\\\%s\\%s", cli->desthost, share);
 
-       set_message(cli->outbuf,4, 0, True);
+       set_message(NULL,cli->outbuf,4, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBtconX);
        cli_setup_packet(cli);
 
        SSVAL(cli->outbuf,smb_vwv0,0xFF);
+       SSVAL(cli->outbuf,smb_vwv2,TCONX_FLAG_EXTENDED_RESPONSE);
        SSVAL(cli->outbuf,smb_vwv3,passlen);
 
        p = smb_buf(cli->outbuf);
@@ -1053,7 +1112,7 @@ BOOL cli_send_tconX(struct cli_state *cli,
 BOOL cli_tdis(struct cli_state *cli)
 {
        memset(cli->outbuf,'\0',smb_size);
-       set_message(cli->outbuf,0,0,True);
+       set_message(NULL,cli->outbuf,0,0,True);
        SCVAL(cli->outbuf,smb_com,SMBtdis);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
        cli_setup_packet(cli);
@@ -1085,7 +1144,7 @@ void cli_negprot_send(struct cli_state *cli)
        memset(cli->outbuf,'\0',smb_size);
 
        /* setup the protocol strings */
-       set_message(cli->outbuf,0,0,True);
+       set_message(NULL,cli->outbuf,0,0,True);
 
        p = smb_buf(cli->outbuf);
        for (numprots=0;
@@ -1125,7 +1184,7 @@ BOOL cli_negprot(struct cli_state *cli)
             numprots++)
                plength += strlen(prots[numprots].name)+2;
     
-       set_message(cli->outbuf,0,plength,True);
+       set_message(NULL,cli->outbuf,0,plength,True);
 
        p = smb_buf(cli->outbuf);
        for (numprots=0;
@@ -1342,7 +1401,7 @@ BOOL cli_session_request(struct cli_state *cli,
  Open the client sockets.
 ****************************************************************************/
 
-BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
+NTSTATUS cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
 {
        int name_type = 0x20;
        char *p;
@@ -1360,7 +1419,7 @@ BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
        
        if (!ip || is_zero_ip(*ip)) {
                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
-                        return False;
+                       return NT_STATUS_BAD_NETWORK_NAME;
                 }
                if (ip) *ip = cli->dest_ip;
        } else {
@@ -1385,12 +1444,12 @@ BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
        if (cli->fd == -1) {
                DEBUG(1,("Error connecting to %s (%s)\n",
                         ip?inet_ntoa(*ip):host,strerror(errno)));
-               return False;
+               return map_nt_error_from_unix(errno);
        }
 
        set_socket_options(cli->fd,user_socket_options);
 
-       return True;
+       return NT_STATUS_OK;
 }
 
 /**
@@ -1444,15 +1503,12 @@ again:
 
        DEBUG(3,("Connecting to host=%s\n", dest_host));
        
-       if (!cli_connect(cli, dest_host, &ip)) {
-               DEBUG(1,("cli_start_connection: failed to connect to %s (%s)\n",
-                        nmb_namestr(&called), inet_ntoa(ip)));
+       nt_status = cli_connect(cli, dest_host, &ip);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
+                        nmb_namestr(&called), inet_ntoa(ip), nt_errstr(nt_status) ));
                cli_shutdown(cli);
-               if (is_zero_ip(ip)) {
-                       return NT_STATUS_BAD_NETWORK_NAME;
-               } else {
-                       return NT_STATUS_CONNECTION_REFUSED;
-               }
+               return nt_status;
        }
 
        if (retry)
@@ -1597,6 +1653,7 @@ BOOL attempt_netbios_session_request(struct cli_state **ppcli, const char *srcho
        }
 
        if (!cli_session_request(*ppcli, &calling, &called)) {
+               NTSTATUS status;
                struct nmb_name smbservername;
 
                make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
@@ -1626,7 +1683,8 @@ with error %s.\n", desthost, cli_errstr(*ppcli) ));
                        return False;
                }
 
-               if (!cli_connect(*ppcli, desthost, pdest_ip) ||
+               status = cli_connect(*ppcli, desthost, pdest_ip);
+               if (!NT_STATUS_IS_OK(status) ||
                                !cli_session_request(*ppcli, &calling, &smbservername)) {
                        DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
@@ -1659,7 +1717,7 @@ NTSTATUS cli_raw_tcon(struct cli_state *cli,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(cli->outbuf, 0, 0, True);
+       set_message(NULL,cli->outbuf, 0, 0, True);
        SCVAL(cli->outbuf,smb_com,SMBtcon);
        cli_setup_packet(cli);