CVE-2016-2115: s4:libcli/raw: pass the minprotocol to smb_raw_negotiate*()
[samba.git] / source4 / libcli / raw / rawnegotiate.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SMB client negotiate context management functions
5
6    Copyright (C) Andrew Tridgell 1994-2005
7    Copyright (C) James Myers 2003 <myersjj@samba.org>
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include <tevent.h>
25 #include "system/time.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
28 #include "../libcli/smb/smbXcli_base.h"
29 #include "../lib/util/tevent_ntstatus.h"
30
31 struct smb_raw_negotiate_state {
32         struct smbcli_transport *transport;
33 };
34
35 static void smb_raw_negotiate_done(struct tevent_req *subreq);
36
37 struct tevent_req *smb_raw_negotiate_send(TALLOC_CTX *mem_ctx,
38                                           struct tevent_context *ev,
39                                           struct smbcli_transport *transport,
40                                           int minprotocol,
41                                           int maxprotocol)
42 {
43         struct tevent_req *req;
44         struct smb_raw_negotiate_state *state;
45         struct tevent_req *subreq;
46         uint32_t timeout_msec = transport->options.request_timeout * 1000;
47
48         req = tevent_req_create(mem_ctx, &state,
49                                 struct smb_raw_negotiate_state);;
50         if (req == NULL) {
51                 return NULL;
52         }
53         state->transport = transport;
54
55         if (maxprotocol > PROTOCOL_NT1) {
56                 maxprotocol = PROTOCOL_NT1;
57         }
58
59         subreq = smbXcli_negprot_send(state, ev,
60                                       transport->conn,
61                                       timeout_msec,
62                                       minprotocol,
63                                       maxprotocol);
64         if (tevent_req_nomem(subreq, req)) {
65                 return tevent_req_post(req, ev);
66         }
67         tevent_req_set_callback(subreq, smb_raw_negotiate_done, req);
68
69         return req;
70 }
71
72 static void smb_raw_negotiate_done(struct tevent_req *subreq)
73 {
74         struct tevent_req *req =
75                 tevent_req_callback_data(subreq,
76                 struct tevent_req);
77         struct smb_raw_negotiate_state *state =
78                 tevent_req_data(req,
79                 struct smb_raw_negotiate_state);
80         struct smbcli_negotiate *n = &state->transport->negotiate;
81         struct smbXcli_conn *c = state->transport->conn;
82         NTSTATUS status;
83         NTTIME ntt;
84
85         status = smbXcli_negprot_recv(subreq);
86         TALLOC_FREE(subreq);
87         if (tevent_req_nterror(req, status)) {
88                 return;
89         }
90
91         n->protocol = smbXcli_conn_protocol(c);
92
93         n->sec_mode = smb1cli_conn_server_security_mode(c);
94         n->max_mux  = smbXcli_conn_max_requests(c);
95         n->max_xmit = smb1cli_conn_max_xmit(c);
96         n->sesskey  = smb1cli_conn_server_session_key(c);
97         n->capabilities = smb1cli_conn_capabilities(c);;
98
99         /* this time arrives in real GMT */
100         ntt = smbXcli_conn_server_system_time(c);
101         n->server_time = nt_time_to_unix(ntt);
102         n->server_zone = smb1cli_conn_server_time_zone(c);
103
104         if (n->capabilities & CAP_EXTENDED_SECURITY) {
105                 const DATA_BLOB *b = smbXcli_conn_server_gss_blob(c);
106                 if (b) {
107                         n->secblob = *b;
108                 }
109         } else {
110                 const uint8_t *p = smb1cli_conn_server_challenge(c);
111                 if (p) {
112                         n->secblob = data_blob_const(p, 8);
113                 }
114         }
115
116         n->readbraw_supported = smb1cli_conn_server_readbraw(c);
117         n->readbraw_supported = smb1cli_conn_server_writebraw(c);
118         n->lockread_supported = smb1cli_conn_server_lockread(c);
119
120         tevent_req_done(req);
121 }
122
123 /*
124  Send a negprot command.
125 */
126 NTSTATUS smb_raw_negotiate_recv(struct tevent_req *req)
127 {
128         return tevent_req_simple_recv_ntstatus(req);
129 }
130
131
132 /*
133  Send a negprot command (sync interface)
134 */
135 NTSTATUS smb_raw_negotiate(struct smbcli_transport *transport, bool unicode,
136                            int minprotocol, int maxprotocol)
137 {
138         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
139         struct tevent_req *subreq = NULL;
140         bool ok;
141
142         subreq = smb_raw_negotiate_send(transport,
143                                         transport->ev,
144                                         transport,
145                                         minprotocol,
146                                         maxprotocol);
147         if (subreq == NULL) {
148                 return NT_STATUS_NO_MEMORY;
149         }
150
151         ok = tevent_req_poll(subreq, transport->ev);
152         if (!ok) {
153                 status = map_nt_error_from_unix_common(errno);
154                 goto failed;
155         }
156
157         status = smb_raw_negotiate_recv(subreq);
158
159 failed:
160         TALLOC_FREE(subreq);
161         return status;
162 }