source: vendor/current/source4/libcli/smb2/session.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 9.8 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 SMB2 client session handling
5
6 Copyright (C) Andrew Tridgell 2005
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "system/network.h"
24#include <tevent.h>
25#include "lib/util/tevent_ntstatus.h"
26#include "libcli/raw/libcliraw.h"
27#include "libcli/smb2/smb2.h"
28#include "libcli/smb2/smb2_calls.h"
29#include "auth/gensec/gensec.h"
30#include "auth/credentials/credentials.h"
31#include "../libcli/smb/smbXcli_base.h"
32
33/**
34 initialise a smb2_session structure
35 */
36struct smb2_session *smb2_session_init(struct smb2_transport *transport,
37 struct gensec_settings *settings,
38 TALLOC_CTX *parent_ctx)
39{
40 struct smb2_session *session;
41 NTSTATUS status;
42
43 session = talloc_zero(parent_ctx, struct smb2_session);
44 if (!session) {
45 return NULL;
46 }
47 session->transport = talloc_steal(session, transport);
48
49 session->smbXcli = smbXcli_session_create(session, transport->conn);
50 if (session->smbXcli == NULL) {
51 talloc_free(session);
52 return NULL;
53 }
54
55 /* prepare a gensec context for later use */
56 status = gensec_client_start(session, &session->gensec,
57 settings);
58 if (!NT_STATUS_IS_OK(status)) {
59 talloc_free(session);
60 return NULL;
61 }
62
63 gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
64
65 return session;
66}
67
68/*
69 * Note: that the caller needs to keep 'transport' around as
70 * long as the returned session is active!
71 */
72struct smb2_session *smb2_session_channel(struct smb2_transport *transport,
73 struct gensec_settings *settings,
74 TALLOC_CTX *parent_ctx,
75 struct smb2_session *base_session)
76{
77 struct smb2_session *session;
78 NTSTATUS status;
79
80 session = talloc_zero(parent_ctx, struct smb2_session);
81 if (!session) {
82 return NULL;
83 }
84 session->transport = transport;
85
86 status = smb2cli_session_create_channel(session,
87 base_session->smbXcli,
88 transport->conn,
89 &session->smbXcli);
90 if (!NT_STATUS_IS_OK(status)) {
91 talloc_free(session);
92 return NULL;
93 }
94
95 session->needs_bind = true;
96
97 /* prepare a gensec context for later use */
98 status = gensec_client_start(session, &session->gensec,
99 settings);
100 if (!NT_STATUS_IS_OK(status)) {
101 talloc_free(session);
102 return NULL;
103 }
104
105 gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
106
107 return session;
108}
109
110struct smb2_session_setup_spnego_state {
111 struct tevent_context *ev;
112 struct smb2_session *session;
113 struct cli_credentials *credentials;
114 uint64_t previous_session_id;
115 bool session_bind;
116 bool reauth;
117 NTSTATUS gensec_status;
118 DATA_BLOB in_secblob;
119 DATA_BLOB out_secblob;
120};
121
122static void smb2_session_setup_spnego_done(struct tevent_req *subreq);
123
124/*
125 a composite function that does a full SPNEGO session setup
126 */
127struct tevent_req *smb2_session_setup_spnego_send(
128 TALLOC_CTX *mem_ctx,
129 struct tevent_context *ev,
130 struct smb2_session *session,
131 struct cli_credentials *credentials,
132 uint64_t previous_session_id)
133{
134 struct tevent_req *req;
135 struct smb2_session_setup_spnego_state *state;
136 uint64_t current_session_id;
137 const char *chosen_oid;
138 struct tevent_req *subreq;
139 NTSTATUS status;
140 const DATA_BLOB *server_gss_blob;
141 DATA_BLOB negprot_secblob = data_blob_null;
142 uint32_t timeout_msec;
143 uint8_t in_flags = 0;
144
145 timeout_msec = session->transport->options.request_timeout * 1000;
146
147 req = tevent_req_create(mem_ctx, &state,
148 struct smb2_session_setup_spnego_state);
149 if (req == NULL) {
150 return NULL;
151 }
152 state->ev = ev;
153 state->session = session;
154 state->credentials = credentials;
155 state->previous_session_id = previous_session_id;
156
157 current_session_id = smb2cli_session_current_id(state->session->smbXcli);
158 if (state->session->needs_bind) {
159 state->session_bind = true;
160 } else if (current_session_id != 0) {
161 state->reauth = true;
162 }
163 server_gss_blob = smbXcli_conn_server_gss_blob(session->transport->conn);
164 if (server_gss_blob) {
165 negprot_secblob = *server_gss_blob;
166 }
167
168 status = gensec_set_credentials(session->gensec, credentials);
169 if (tevent_req_nterror(req, status)) {
170 return tevent_req_post(req, ev);
171 }
172
173 status = gensec_set_target_hostname(session->gensec,
174 smbXcli_conn_remote_name(session->transport->conn));
175 if (tevent_req_nterror(req, status)) {
176 return tevent_req_post(req, ev);
177 }
178
179 status = gensec_set_target_service(session->gensec, "cifs");
180 if (tevent_req_nterror(req, status)) {
181 return tevent_req_post(req, ev);
182 }
183
184 if (negprot_secblob.length > 0) {
185 chosen_oid = GENSEC_OID_SPNEGO;
186 } else {
187 chosen_oid = GENSEC_OID_NTLMSSP;
188 }
189
190 status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
191 if (tevent_req_nterror(req, status)) {
192 return tevent_req_post(req, ev);
193 }
194
195 status = gensec_update_ev(session->gensec, state,
196 state->ev,
197 negprot_secblob,
198 &state->in_secblob);
199 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
200 tevent_req_nterror(req, status);
201 return tevent_req_post(req, ev);
202 }
203 state->gensec_status = status;
204
205 if (state->session_bind) {
206 in_flags |= SMB2_SESSION_FLAG_BINDING;
207 }
208
209 subreq = smb2cli_session_setup_send(state, state->ev,
210 session->transport->conn,
211 timeout_msec,
212 session->smbXcli,
213 in_flags,
214 0, /* in_capabilities */
215 0, /* in_channel */
216 state->previous_session_id,
217 &state->in_secblob);
218 if (tevent_req_nomem(subreq, req)) {
219 return tevent_req_post(req, ev);
220 }
221 tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
222
223 return req;
224}
225
226/*
227 handle continuations of the spnego session setup
228*/
229static void smb2_session_setup_spnego_done(struct tevent_req *subreq)
230{
231 struct tevent_req *req =
232 tevent_req_callback_data(subreq,
233 struct tevent_req);
234 struct smb2_session_setup_spnego_state *state =
235 tevent_req_data(req,
236 struct smb2_session_setup_spnego_state);
237 struct smb2_session *session = state->session;
238 NTSTATUS peer_status;
239 NTSTATUS status;
240 struct iovec *recv_iov;
241 uint32_t timeout_msec;
242 uint8_t in_flags = 0;
243
244 timeout_msec = session->transport->options.request_timeout * 1000;
245
246 status = smb2cli_session_setup_recv(subreq, state,
247 &recv_iov,
248 &state->out_secblob);
249 if (!NT_STATUS_IS_OK(status) &&
250 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
251 tevent_req_nterror(req, status);
252 return;
253 }
254 peer_status = status;
255
256 if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
257 status = gensec_update_ev(session->gensec, state,
258 state->ev,
259 state->out_secblob,
260 &state->in_secblob);
261 state->gensec_status = status;
262 }
263
264 if (!NT_STATUS_IS_OK(status) &&
265 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
266 tevent_req_nterror(req, status);
267 return;
268 }
269
270 if (NT_STATUS_IS_OK(peer_status) && NT_STATUS_IS_OK(state->gensec_status)) {
271 DATA_BLOB session_key;
272
273 if (state->reauth) {
274 tevent_req_done(req);
275 return;
276 }
277
278 if (cli_credentials_is_anonymous(state->credentials)) {
279 /*
280 * Windows server does not set the
281 * SMB2_SESSION_FLAG_IS_GUEST nor
282 * SMB2_SESSION_FLAG_IS_NULL flag.
283 *
284 * This fix makes sure we do not try
285 * to verify a signature on the final
286 * session setup response.
287 */
288 tevent_req_done(req);
289 return;
290 }
291
292 status = gensec_session_key(session->gensec, state,
293 &session_key);
294 if (tevent_req_nterror(req, status)) {
295 return;
296 }
297
298 if (state->session_bind) {
299 status = smb2cli_session_set_channel_key(session->smbXcli,
300 session_key,
301 recv_iov);
302 if (tevent_req_nterror(req, status)) {
303 return;
304 }
305 session->needs_bind = false;
306 } else {
307 status = smb2cli_session_set_session_key(session->smbXcli,
308 session_key,
309 recv_iov);
310 if (tevent_req_nterror(req, status)) {
311 return;
312 }
313 }
314 tevent_req_done(req);
315 return;
316 }
317
318 if (state->session_bind) {
319 in_flags |= SMB2_SESSION_FLAG_BINDING;
320 }
321
322 subreq = smb2cli_session_setup_send(state, state->ev,
323 session->transport->conn,
324 timeout_msec,
325 session->smbXcli,
326 in_flags,
327 0, /* in_capabilities */
328 0, /* in_channel */
329 state->previous_session_id,
330 &state->in_secblob);
331 if (tevent_req_nomem(subreq, req)) {
332 return;
333 }
334 tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
335}
336
337/*
338 receive a composite session setup reply
339*/
340NTSTATUS smb2_session_setup_spnego_recv(struct tevent_req *req)
341{
342 return tevent_req_simple_recv_ntstatus(req);
343}
344
345/*
346 sync version of smb2_session_setup_spnego
347*/
348NTSTATUS smb2_session_setup_spnego(struct smb2_session *session,
349 struct cli_credentials *credentials,
350 uint64_t previous_session_id)
351{
352 struct tevent_req *subreq;
353 NTSTATUS status;
354 bool ok;
355 TALLOC_CTX *frame = talloc_stackframe();
356 struct tevent_context *ev = session->transport->ev;
357
358 if (frame == NULL) {
359 return NT_STATUS_NO_MEMORY;
360 }
361
362 subreq = smb2_session_setup_spnego_send(frame, ev,
363 session, credentials,
364 previous_session_id);
365 if (subreq == NULL) {
366 TALLOC_FREE(frame);
367 return NT_STATUS_NO_MEMORY;
368 }
369
370 ok = tevent_req_poll(subreq, ev);
371 if (!ok) {
372 status = map_nt_error_from_unix_common(errno);
373 TALLOC_FREE(frame);
374 return status;
375 }
376
377 status = smb2_session_setup_spnego_recv(subreq);
378 TALLOC_FREE(subreq);
379 if (!NT_STATUS_IS_OK(status)) {
380 TALLOC_FREE(frame);
381 return status;
382 }
383
384 TALLOC_FREE(frame);
385 return NT_STATUS_OK;
386}
Note: See TracBrowser for help on using the repository browser.