s3-selftest: Remove some unnecessary comma
[Samba/gebeck_regimport.git] / source4 / libcli / smb2 / session.c
blob2657266401bbac9be177a4e7e022e6610c891c6a
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 client session handling
6 Copyright (C) Andrew Tridgell 2005
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.
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.
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/>.
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 "../libcli/smb/smbXcli_base.h"
31 #include "../source3/libsmb/smb2cli.h"
33 /**
34 initialise a smb2_session structure
36 struct smb2_session *smb2_session_init(struct smb2_transport *transport,
37 struct gensec_settings *settings,
38 TALLOC_CTX *parent_ctx, bool primary)
40 struct smb2_session *session;
41 NTSTATUS status;
43 session = talloc_zero(parent_ctx, struct smb2_session);
44 if (!session) {
45 return NULL;
47 if (primary) {
48 session->transport = talloc_steal(session, transport);
49 } else {
50 session->transport = talloc_reference(session, transport);
53 session->pid = getpid();
55 session->smbXcli = smbXcli_session_create(session, transport->conn);
56 if (session->smbXcli == NULL) {
57 talloc_free(session);
58 return NULL;
61 /* prepare a gensec context for later use */
62 status = gensec_client_start(session, &session->gensec,
63 settings);
64 if (!NT_STATUS_IS_OK(status)) {
65 talloc_free(session);
66 return NULL;
69 gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
71 return session;
74 struct smb2_session_setup_spnego_state {
75 struct tevent_context *ev;
76 struct smb2_session *session;
77 struct cli_credentials *credentials;
78 uint64_t previous_session_id;
79 bool reauth;
80 NTSTATUS gensec_status;
81 DATA_BLOB in_secblob;
82 DATA_BLOB out_secblob;
85 static void smb2_session_setup_spnego_done(struct tevent_req *subreq);
88 a composite function that does a full SPNEGO session setup
90 struct tevent_req *smb2_session_setup_spnego_send(
91 TALLOC_CTX *mem_ctx,
92 struct tevent_context *ev,
93 struct smb2_session *session,
94 struct cli_credentials *credentials,
95 uint64_t previous_session_id)
97 struct tevent_req *req;
98 struct smb2_session_setup_spnego_state *state;
99 uint64_t current_session_id;
100 const char *chosen_oid;
101 struct tevent_req *subreq;
102 NTSTATUS status;
103 const DATA_BLOB *server_gss_blob;
104 DATA_BLOB negprot_secblob = data_blob_null;
105 uint32_t timeout_msec;
107 timeout_msec = session->transport->options.request_timeout * 1000;
109 req = tevent_req_create(mem_ctx, &state,
110 struct smb2_session_setup_spnego_state);
111 if (req == NULL) {
112 return NULL;
114 state->ev = ev;
115 state->session = session;
116 state->credentials = credentials;
117 state->previous_session_id = previous_session_id;
119 current_session_id = smb2cli_session_current_id(state->session->smbXcli);
120 if (current_session_id != 0) {
121 state->reauth = true;
124 server_gss_blob = smbXcli_conn_server_gss_blob(session->transport->conn);
125 if (server_gss_blob) {
126 negprot_secblob = *server_gss_blob;
129 status = gensec_set_credentials(session->gensec, credentials);
130 if (tevent_req_nterror(req, status)) {
131 return tevent_req_post(req, ev);
134 status = gensec_set_target_hostname(session->gensec,
135 smbXcli_conn_remote_name(session->transport->conn));
136 if (tevent_req_nterror(req, status)) {
137 return tevent_req_post(req, ev);
140 status = gensec_set_target_service(session->gensec, "cifs");
141 if (tevent_req_nterror(req, status)) {
142 return tevent_req_post(req, ev);
145 if (negprot_secblob.length > 0) {
146 chosen_oid = GENSEC_OID_SPNEGO;
147 } else {
148 chosen_oid = GENSEC_OID_NTLMSSP;
151 status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
152 if (tevent_req_nterror(req, status)) {
153 return tevent_req_post(req, ev);
156 status = gensec_update(session->gensec, state,
157 state->ev,
158 negprot_secblob,
159 &state->in_secblob);
160 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
161 tevent_req_nterror(req, status);
162 return tevent_req_post(req, ev);
164 state->gensec_status = status;
166 subreq = smb2cli_session_setup_send(state, state->ev,
167 session->transport->conn,
168 timeout_msec,
169 session->smbXcli,
170 0, /* in_flags */
171 0, /* in_capabilities */
172 0, /* in_channel */
173 state->previous_session_id,
174 &state->in_secblob);
175 if (tevent_req_nomem(subreq, req)) {
176 return tevent_req_post(req, ev);
178 tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
180 return req;
184 handle continuations of the spnego session setup
186 static void smb2_session_setup_spnego_done(struct tevent_req *subreq)
188 struct tevent_req *req =
189 tevent_req_callback_data(subreq,
190 struct tevent_req);
191 struct smb2_session_setup_spnego_state *state =
192 tevent_req_data(req,
193 struct smb2_session_setup_spnego_state);
194 struct smb2_session *session = state->session;
195 NTSTATUS peer_status;
196 NTSTATUS status;
197 struct iovec *recv_iov;
198 uint32_t timeout_msec;
200 timeout_msec = session->transport->options.request_timeout * 1000;
202 status = smb2cli_session_setup_recv(subreq, state,
203 &recv_iov,
204 &state->out_secblob);
205 if (!NT_STATUS_IS_OK(status) &&
206 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
207 tevent_req_nterror(req, status);
208 return;
210 peer_status = status;
212 if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
213 status = gensec_update(session->gensec, state,
214 state->ev,
215 state->out_secblob,
216 &state->in_secblob);
217 state->gensec_status = status;
220 if (!NT_STATUS_IS_OK(status) &&
221 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
222 tevent_req_nterror(req, status);
223 return;
226 if (NT_STATUS_IS_OK(peer_status) && NT_STATUS_IS_OK(state->gensec_status)) {
227 DATA_BLOB session_key;
229 if (state->reauth) {
230 tevent_req_done(req);
231 return;
234 status = gensec_session_key(session->gensec, state,
235 &session_key);
236 if (tevent_req_nterror(req, status)) {
237 return;
240 status = smb2cli_session_set_session_key(session->smbXcli,
241 session_key,
242 recv_iov);
243 if (tevent_req_nterror(req, status)) {
244 return;
247 tevent_req_done(req);
248 return;
251 subreq = smb2cli_session_setup_send(state, state->ev,
252 session->transport->conn,
253 timeout_msec,
254 session->smbXcli,
255 0, /* in_flags */
256 0, /* in_capabilities */
257 0, /* in_channel */
258 state->previous_session_id,
259 &state->in_secblob);
260 if (tevent_req_nomem(subreq, req)) {
261 return;
263 tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
267 receive a composite session setup reply
269 NTSTATUS smb2_session_setup_spnego_recv(struct tevent_req *req)
271 return tevent_req_simple_recv_ntstatus(req);
275 sync version of smb2_session_setup_spnego
277 NTSTATUS smb2_session_setup_spnego(struct smb2_session *session,
278 struct cli_credentials *credentials,
279 uint64_t previous_session_id)
281 struct tevent_req *subreq;
282 NTSTATUS status;
283 bool ok;
284 TALLOC_CTX *frame = talloc_stackframe();
285 struct tevent_context *ev = session->transport->ev;
287 if (frame == NULL) {
288 return NT_STATUS_NO_MEMORY;
291 subreq = smb2_session_setup_spnego_send(frame, ev,
292 session, credentials,
293 previous_session_id);
294 if (subreq == NULL) {
295 TALLOC_FREE(frame);
296 return NT_STATUS_NO_MEMORY;
299 ok = tevent_req_poll(subreq, ev);
300 if (!ok) {
301 status = map_nt_error_from_unix_common(errno);
302 TALLOC_FREE(frame);
303 return status;
306 status = smb2_session_setup_spnego_recv(subreq);
307 TALLOC_FREE(subreq);
308 if (!NT_STATUS_IS_OK(status)) {
309 TALLOC_FREE(frame);
310 return status;
313 TALLOC_FREE(frame);
314 return NT_STATUS_OK;