s4:libcli/smb2: remove unused smb2_session->pid
[kai/samba.git] / source4 / libcli / smb2 / session.c
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 #include "../source3/libsmb/smb2cli.h"
33
34 /**
35   initialise a smb2_session structure
36  */
37 struct smb2_session *smb2_session_init(struct smb2_transport *transport,
38                                        struct gensec_settings *settings,
39                                        TALLOC_CTX *parent_ctx, bool primary)
40 {
41         struct smb2_session *session;
42         NTSTATUS status;
43
44         session = talloc_zero(parent_ctx, struct smb2_session);
45         if (!session) {
46                 return NULL;
47         }
48         if (primary) {
49                 session->transport = talloc_steal(session, transport);
50         } else {
51                 session->transport = talloc_reference(session, transport);
52         }
53
54         session->smbXcli = smbXcli_session_create(session, transport->conn);
55         if (session->smbXcli == NULL) {
56                 talloc_free(session);
57                 return NULL;
58         }
59
60         /* prepare a gensec context for later use */
61         status = gensec_client_start(session, &session->gensec,
62                                      settings);
63         if (!NT_STATUS_IS_OK(status)) {
64                 talloc_free(session);
65                 return NULL;
66         }
67
68         gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
69
70         return session;
71 }
72
73 struct smb2_session_setup_spnego_state {
74         struct tevent_context *ev;
75         struct smb2_session *session;
76         struct cli_credentials *credentials;
77         uint64_t previous_session_id;
78         bool reauth;
79         NTSTATUS gensec_status;
80         DATA_BLOB in_secblob;
81         DATA_BLOB out_secblob;
82 };
83
84 static void smb2_session_setup_spnego_done(struct tevent_req *subreq);
85
86 /*
87   a composite function that does a full SPNEGO session setup
88  */
89 struct tevent_req *smb2_session_setup_spnego_send(
90                                 TALLOC_CTX *mem_ctx,
91                                 struct tevent_context *ev,
92                                 struct smb2_session *session,
93                                 struct cli_credentials *credentials,
94                                 uint64_t previous_session_id)
95 {
96         struct tevent_req *req;
97         struct smb2_session_setup_spnego_state *state;
98         uint64_t current_session_id;
99         const char *chosen_oid;
100         struct tevent_req *subreq;
101         NTSTATUS status;
102         const DATA_BLOB *server_gss_blob;
103         DATA_BLOB negprot_secblob = data_blob_null;
104         uint32_t timeout_msec;
105
106         timeout_msec = session->transport->options.request_timeout * 1000;
107
108         req = tevent_req_create(mem_ctx, &state,
109                                 struct smb2_session_setup_spnego_state);
110         if (req == NULL) {
111                 return NULL;
112         }
113         state->ev = ev;
114         state->session = session;
115         state->credentials = credentials;
116         state->previous_session_id = previous_session_id;
117
118         current_session_id = smb2cli_session_current_id(state->session->smbXcli);
119         if (current_session_id != 0) {
120                 state->reauth = true;
121         }
122
123         server_gss_blob = smbXcli_conn_server_gss_blob(session->transport->conn);
124         if (server_gss_blob) {
125                 negprot_secblob = *server_gss_blob;
126         }
127
128         status = gensec_set_credentials(session->gensec, credentials);
129         if (tevent_req_nterror(req, status)) {
130                 return tevent_req_post(req, ev);
131         }
132
133         status = gensec_set_target_hostname(session->gensec,
134                                             smbXcli_conn_remote_name(session->transport->conn));
135         if (tevent_req_nterror(req, status)) {
136                 return tevent_req_post(req, ev);
137         }
138
139         status = gensec_set_target_service(session->gensec, "cifs");
140         if (tevent_req_nterror(req, status)) {
141                 return tevent_req_post(req, ev);
142         }
143
144         if (negprot_secblob.length > 0) {
145                 chosen_oid = GENSEC_OID_SPNEGO;
146         } else {
147                 chosen_oid = GENSEC_OID_NTLMSSP;
148         }
149
150         status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
151         if (tevent_req_nterror(req, status)) {
152                 return tevent_req_post(req, ev);
153         }
154
155         status = gensec_update(session->gensec, state,
156                                state->ev,
157                                negprot_secblob,
158                                &state->in_secblob);
159         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
160                 tevent_req_nterror(req, status);
161                 return tevent_req_post(req, ev);
162         }
163         state->gensec_status = status;
164
165         subreq = smb2cli_session_setup_send(state, state->ev,
166                                             session->transport->conn,
167                                             timeout_msec,
168                                             session->smbXcli,
169                                             0, /* in_flags */
170                                             0, /* in_capabilities */
171                                             0, /* in_channel */
172                                             state->previous_session_id,
173                                             &state->in_secblob);
174         if (tevent_req_nomem(subreq, req)) {
175                 return tevent_req_post(req, ev);
176         }
177         tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
178
179         return req;
180 }
181
182 /*
183   handle continuations of the spnego session setup
184 */
185 static void smb2_session_setup_spnego_done(struct tevent_req *subreq)
186 {
187         struct tevent_req *req =
188                 tevent_req_callback_data(subreq,
189                 struct tevent_req);
190         struct smb2_session_setup_spnego_state *state =
191                 tevent_req_data(req,
192                 struct smb2_session_setup_spnego_state);
193         struct smb2_session *session = state->session;
194         NTSTATUS peer_status;
195         NTSTATUS status;
196         struct iovec *recv_iov;
197         uint32_t timeout_msec;
198
199         timeout_msec = session->transport->options.request_timeout * 1000;
200
201         status = smb2cli_session_setup_recv(subreq, state,
202                                             &recv_iov,
203                                             &state->out_secblob);
204         if (!NT_STATUS_IS_OK(status) &&
205             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
206                 tevent_req_nterror(req, status);
207                 return;
208         }
209         peer_status = status;
210
211         if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
212                 status = gensec_update(session->gensec, state,
213                                        state->ev,
214                                        state->out_secblob,
215                                        &state->in_secblob);
216                 state->gensec_status = status;
217         }
218
219         if (!NT_STATUS_IS_OK(status) &&
220             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
221                 tevent_req_nterror(req, status);
222                 return;
223         }
224
225         if (NT_STATUS_IS_OK(peer_status) && NT_STATUS_IS_OK(state->gensec_status)) {
226                 DATA_BLOB session_key;
227
228                 if (state->reauth) {
229                         tevent_req_done(req);
230                         return;
231                 }
232
233                 if (cli_credentials_is_anonymous(state->credentials)) {
234                         /*
235                          * Windows server does not set the
236                          * SMB2_SESSION_FLAG_IS_GUEST nor
237                          * SMB2_SESSION_FLAG_IS_NULL flag.
238                          *
239                          * This fix makes sure we do not try
240                          * to verify a signature on the final
241                          * session setup response.
242                          */
243                         tevent_req_done(req);
244                         return;
245                 }
246
247                 status = gensec_session_key(session->gensec, state,
248                                             &session_key);
249                 if (tevent_req_nterror(req, status)) {
250                         return;
251                 }
252
253                 status = smb2cli_session_set_session_key(session->smbXcli,
254                                                          session_key,
255                                                          recv_iov);
256                 if (tevent_req_nterror(req, status)) {
257                         return;
258                 }
259
260                 tevent_req_done(req);
261                 return;
262         }
263
264         subreq = smb2cli_session_setup_send(state, state->ev,
265                                             session->transport->conn,
266                                             timeout_msec,
267                                             session->smbXcli,
268                                             0, /* in_flags */
269                                             0, /* in_capabilities */
270                                             0, /* in_channel */
271                                             state->previous_session_id,
272                                             &state->in_secblob);
273         if (tevent_req_nomem(subreq, req)) {
274                 return;
275         }
276         tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
277 }
278
279 /*
280   receive a composite session setup reply
281 */
282 NTSTATUS smb2_session_setup_spnego_recv(struct tevent_req *req)
283 {
284         return tevent_req_simple_recv_ntstatus(req);
285 }
286
287 /*
288   sync version of smb2_session_setup_spnego
289 */
290 NTSTATUS smb2_session_setup_spnego(struct smb2_session *session, 
291                                    struct cli_credentials *credentials,
292                                    uint64_t previous_session_id)
293 {
294         struct tevent_req *subreq;
295         NTSTATUS status;
296         bool ok;
297         TALLOC_CTX *frame = talloc_stackframe();
298         struct tevent_context *ev = session->transport->ev;
299
300         if (frame == NULL) {
301                 return NT_STATUS_NO_MEMORY;
302         }
303
304         subreq = smb2_session_setup_spnego_send(frame, ev,
305                                                 session, credentials,
306                                                 previous_session_id);
307         if (subreq == NULL) {
308                 TALLOC_FREE(frame);
309                 return NT_STATUS_NO_MEMORY;
310         }
311
312         ok = tevent_req_poll(subreq, ev);
313         if (!ok) {
314                 status = map_nt_error_from_unix_common(errno);
315                 TALLOC_FREE(frame);
316                 return status;
317         }
318
319         status = smb2_session_setup_spnego_recv(subreq);
320         TALLOC_FREE(subreq);
321         if (!NT_STATUS_IS_OK(status)) {
322                 TALLOC_FREE(frame);
323                 return status;
324         }
325
326         TALLOC_FREE(frame);
327         return NT_STATUS_OK;
328 }