Make sure smbtorture tests can run if someone has set their min protocol above NT1.
[nivanova/samba-autobuild/.git] / source4 / libcli / raw / rawnegotiate.c
index 5b94ef63d836cd15829855f0be7eef19317604ea..73c9123411d6101710ee0168e2234b0032dc9dec 100644 (file)
@@ -1,12 +1,14 @@
 /* 
    Unix SMB/CIFS implementation.
+
    SMB client negotiate 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"
-
-static const struct {
-       enum protocol_types prot;
-       const char *name;
-} prots[] = {
-       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
-       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
-       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
-       {PROTOCOL_LANMAN1,"LANMAN1.0"},
-       {PROTOCOL_LANMAN1,"Windows for Workgroups 3.1a"},
-       {PROTOCOL_LANMAN2,"LM1.2X002"},
-       {PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
-       {PROTOCOL_LANMAN2,"Samba"},
-       {PROTOCOL_NT1,"NT LANMAN 1.0"},
-       {PROTOCOL_NT1,"NT LM 0.12"},
+#include <tevent.h>
+#include "system/time.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "../lib/util/tevent_ntstatus.h"
+
+struct smb_raw_negotiate_state {
+       struct smbcli_transport *transport;
 };
 
-/****************************************************************************
- Send a negprot command.
-****************************************************************************/
-struct cli_request *smb_negprot_send(struct cli_transport *transport, int maxprotocol)
-{
-       struct cli_request *req;
-       int i;
+static void smb_raw_negotiate_done(struct tevent_req *subreq);
 
-       req = cli_request_setup_transport(transport, SMBnegprot, 0, 0);
-       if (!req) {
+struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx,
+                                         struct tevent_context *ev,
+                                         struct smbcli_transport *transport,
+                                         int minprotocol,
+                                         int maxprotocol)
+{
+       struct tevent_req *req;
+       struct smb_raw_negotiate_state *state;
+       struct tevent_req *subreq;
+       uint32_t timeout_msec = transport->options.request_timeout * 1000;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct smb_raw_negotiate_state);;
+       if (req == NULL) {
                return NULL;
        }
+       state->transport = transport;
 
-       /* setup the protocol strings */
-       for (i=0; i < ARRAY_SIZE(prots) && prots[i].prot <= maxprotocol; i++) {
-               cli_req_append_bytes(req, "\2", 1);
-               cli_req_append_string(req, prots[i].name, STR_TERMINATE | STR_ASCII);
+       if (maxprotocol > PROTOCOL_NT1) {
+               maxprotocol = PROTOCOL_NT1;
        }
 
-       if (!cli_request_send(req)) {
-               cli_request_destroy(req);
-               return NULL;
+       if (minprotocol > maxprotocol) {
+               minprotocol = maxprotocol;
        }
 
+       subreq = smbXcli_negprot_send(state, ev,
+                                     transport->conn,
+                                     timeout_msec,
+                                     minprotocol,
+                                     maxprotocol,
+                                     transport->options.max_credits);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, smb_raw_negotiate_done, req);
+
        return req;
 }
 
-/****************************************************************************
- Send a negprot command.
-****************************************************************************/
-NTSTATUS smb_raw_negotiate(struct cli_transport *transport) 
+static void smb_raw_negotiate_done(struct tevent_req *subreq)
 {
-       struct cli_request *req;
-       int protocol;
-
-       req = smb_negprot_send(transport, PROTOCOL_NT1);
-       if (!req) {
-               return NT_STATUS_UNSUCCESSFUL;
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct smb_raw_negotiate_state *state =
+               tevent_req_data(req,
+               struct smb_raw_negotiate_state);
+       struct smbcli_negotiate *n = &state->transport->negotiate;
+       struct smbXcli_conn *c = state->transport->conn;
+       NTSTATUS status;
+       NTTIME ntt;
+
+       status = smbXcli_negprot_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
 
-       if (!cli_request_receive(req) ||
-           cli_request_is_error(req)) {
-               return cli_request_destroy(req);
-       }
+       n->protocol = smbXcli_conn_protocol(c);
 
-       CLI_CHECK_MIN_WCT(req, 1);
+       n->sec_mode = smb1cli_conn_server_security_mode(c);
+       n->max_mux  = smbXcli_conn_max_requests(c);
+       n->max_xmit = smb1cli_conn_max_xmit(c);
+       n->sesskey  = smb1cli_conn_server_session_key(c);
+       n->capabilities = smb1cli_conn_capabilities(c);;
 
-       protocol = SVALS(req->in.vwv, VWV(0));
+       /* this time arrives in real GMT */
+       ntt = smbXcli_conn_server_system_time(c);
+       n->server_time = nt_time_to_unix(ntt);
+       n->server_zone = smb1cli_conn_server_time_zone(c);
 
-       if (protocol >= ARRAY_SIZE(prots) || protocol < 0) {
-               req->status = NT_STATUS_UNSUCCESSFUL;
-               return cli_request_destroy(req);
+       if (n->capabilities & CAP_EXTENDED_SECURITY) {
+               const DATA_BLOB *b = smbXcli_conn_server_gss_blob(c);
+               if (b) {
+                       n->secblob = *b;
+               }
+       } else {
+               const uint8_t *p = smb1cli_conn_server_challenge(c);
+               if (p) {
+                       n->secblob = data_blob_const(p, 8);
+               }
        }
 
-       transport->negotiate.protocol = prots[protocol].prot;
+       n->readbraw_supported = smb1cli_conn_server_readbraw(c);
+       n->readbraw_supported = smb1cli_conn_server_writebraw(c);
+       n->lockread_supported = smb1cli_conn_server_lockread(c);
 
-       if (transport->negotiate.protocol >= PROTOCOL_NT1) {
-               NTTIME ntt;
-
-               /* NT protocol */
-               CLI_CHECK_WCT(req, 17);
-               transport->negotiate.sec_mode = CVAL(req->in.vwv,VWV(1));
-               transport->negotiate.max_mux  = SVAL(req->in.vwv,VWV(1)+1);
-               transport->negotiate.max_xmit = IVAL(req->in.vwv,VWV(3)+1);
-               transport->negotiate.sesskey  = IVAL(req->in.vwv,VWV(7)+1);
-               transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(15)+1) * 60;
+       tevent_req_done(req);
+}
 
-               /* this time arrives in real GMT */
-               ntt = cli_pull_nttime(req->in.vwv, VWV(11)+1);
-               transport->negotiate.server_time = nt_time_to_unix(ntt);
-               transport->negotiate.capabilities = IVAL(req->in.vwv,VWV(9)+1);
+/*
+ Send a negprot command.
+*/
+NTSTATUS smb_raw_negotiate_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
 
-               transport->negotiate.secblob = cli_req_pull_blob(req, transport->mem_ctx, req->in.data, req->in.data_size);
-               if (transport->negotiate.capabilities & CAP_RAW_MODE) {
-                       transport->negotiate.readbraw_supported = True;
-                       transport->negotiate.writebraw_supported = True;
-               }
 
-               /* work out if they sent us a workgroup */
-               if ((transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) &&
-                   req->in.data_size > 16) {
-                       cli_req_pull_string(req, transport->mem_ctx, &transport->negotiate.server_domain,
-                                           req->in.data+16,
-                                           req->in.data_size-16, STR_UNICODE|STR_NOALIGN);
-               }
-       } else if (transport->negotiate.protocol >= PROTOCOL_LANMAN1) {
-               CLI_CHECK_WCT(req, 13);
-               transport->negotiate.sec_mode = SVAL(req->in.vwv,VWV(1));
-               transport->negotiate.max_xmit = SVAL(req->in.vwv,VWV(2));
-               transport->negotiate.sesskey =  IVAL(req->in.vwv,VWV(6));
-               transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(10)) * 60;
-               
-               /* this time is converted to GMT by raw_pull_dos_date */
-               transport->negotiate.server_time = raw_pull_dos_date(transport,
-                                                                    req->in.vwv+VWV(8));
-               if ((SVAL(req->in.vwv,VWV(5)) & 0x1)) {
-                       transport->negotiate.readbraw_supported = 1;
-               }
-               if ((SVAL(req->in.vwv,VWV(5)) & 0x2)) {
-                       transport->negotiate.writebraw_supported = 1;
-               }
-               transport->negotiate.secblob = cli_req_pull_blob(req, transport->mem_ctx, 
-                                                                req->in.data, req->in.data_size);
-       } else {
-               /* the old core protocol */
-               transport->negotiate.sec_mode = 0;
-               transport->negotiate.server_time = time(NULL);
-               transport->negotiate.max_xmit = ~0;
-               transport->negotiate.server_zone = get_time_zone(transport->negotiate.server_time);
+/*
+ Send a negprot command (sync interface)
+*/
+NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode,
+                          int minprotocol, int maxprotocol)
+{
+       NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+       struct tevent_req *subreq = NULL;
+       bool ok;
+
+       subreq = smb_raw_negotiate_send(transport,
+                                       transport->ev,
+                                       transport,
+                                       minprotocol,
+                                       maxprotocol);
+       if (subreq == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
 
-       /* a way to force ascii SMB */
-       if (getenv("CLI_FORCE_ASCII")) {
-               transport->negotiate.capabilities &= ~CAP_UNICODE;
+       ok = tevent_req_poll(subreq, transport->ev);
+       if (!ok) {
+               status = map_nt_error_from_unix_common(errno);
+               goto failed;
        }
 
+       status = smb_raw_negotiate_recv(subreq);
+
 failed:
-       return cli_request_destroy(req);
+       TALLOC_FREE(subreq);
+       return status;
 }