Line data Source code
1 :
2 : /*
3 : Unix SMB/CIFS implementation.
4 : handle SMBsessionsetup
5 : Copyright (C) Andrew Tridgell 1998-2001
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
7 : Copyright (C) Jim McDonough 2002
8 : Copyright (C) Luke Howard 2003
9 : Copyright (C) Stefan Metzmacher 2005
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "includes.h"
26 : #include <tevent.h>
27 : #include "version.h"
28 : #include "auth/gensec/gensec.h"
29 : #include "auth/auth.h"
30 : #include "smb_server/smb_server.h"
31 : #include "samba/service_stream.h"
32 : #include "param/param.h"
33 : #include "../lib/tsocket/tsocket.h"
34 : #include "lib/stream/packet.h"
35 :
36 : struct sesssetup_context {
37 : struct auth4_context *auth_context;
38 : struct smbsrv_request *req;
39 : };
40 :
41 : /*
42 : * Log the SMB authentication, as by not calling GENSEC we won't log
43 : * it during the gensec_session_info().
44 : */
45 11 : void smbsrv_not_spengo_sesssetup_authz_log(struct smbsrv_request *req,
46 : struct auth_session_info *session_info)
47 : {
48 0 : struct tsocket_address *local_address;
49 0 : struct tsocket_address *remote_address;
50 11 : TALLOC_CTX *frame = talloc_stackframe();
51 :
52 11 : remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
53 : frame);
54 11 : local_address = socket_get_local_addr(req->smb_conn->connection->socket,
55 : frame);
56 :
57 11 : log_successful_authz_event(req->smb_conn->connection->msg_ctx,
58 11 : req->smb_conn->lp_ctx,
59 : remote_address,
60 : local_address,
61 : "SMB",
62 : "bare-NTLM",
63 : AUTHZ_TRANSPORT_PROTECTION_SMB,
64 : session_info,
65 : NULL /* client_audit_info */,
66 : NULL /* server_audit_info */);
67 :
68 11 : talloc_free(frame);
69 11 : return;
70 : }
71 :
72 :
73 : /*
74 : setup the OS, Lanman and domain portions of a session setup reply
75 : */
76 1150 : static void sesssetup_common_strings(struct smbsrv_request *req,
77 : char **os, char **lanman, char **domain)
78 : {
79 1150 : (*os) = talloc_asprintf(req, "Unix");
80 1150 : (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
81 1150 : (*domain) = talloc_asprintf(req, "%s",
82 1150 : lpcfg_workgroup(req->smb_conn->lp_ctx));
83 1150 : }
84 :
85 1150 : static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req,
86 : union smb_sesssetup *sess,
87 : NTSTATUS status)
88 : {
89 1150 : if (NT_STATUS_IS_OK(status)) {
90 962 : req->smb_conn->negotiate.done_sesssetup = true;
91 : /* we need to keep the session long term */
92 962 : req->session = talloc_steal(req->smb_conn, req->session);
93 : }
94 1150 : smbsrv_reply_sesssetup_send(req, sess, status);
95 1150 : }
96 :
97 4 : static void sesssetup_old_send(struct tevent_req *subreq)
98 : {
99 4 : struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
100 4 : struct smbsrv_request *req = state->req;
101 :
102 4 : union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
103 4 : struct auth_user_info_dc *user_info_dc = NULL;
104 0 : struct auth_session_info *session_info;
105 0 : struct smbsrv_session *smb_sess;
106 0 : NTSTATUS status;
107 4 : uint8_t authoritative = 1;
108 0 : uint32_t flags;
109 :
110 4 : status = auth_check_password_recv(subreq, req, &user_info_dc,
111 : &authoritative);
112 4 : TALLOC_FREE(subreq);
113 4 : if (!NT_STATUS_IS_OK(status)) goto failed;
114 :
115 0 : flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
116 0 : if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
117 0 : flags |= AUTH_SESSION_INFO_AUTHENTICATED;
118 : }
119 : /* This references user_info_dc into session_info */
120 0 : status = req->smb_conn->negotiate.auth_context->generate_session_info(req->smb_conn->negotiate.auth_context,
121 : req,
122 : user_info_dc, sess->old.in.user,
123 : flags, &session_info);
124 0 : if (!NT_STATUS_IS_OK(status)) goto failed;
125 :
126 : /* allocate a new session */
127 0 : smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
128 0 : if (!smb_sess) {
129 0 : status = NT_STATUS_INSUFFICIENT_RESOURCES;
130 0 : goto failed;
131 : }
132 :
133 0 : smbsrv_not_spengo_sesssetup_authz_log(req, session_info);
134 :
135 : /* Ensure this is marked as a 'real' vuid, not one
136 : * simply valid for the session setup leg */
137 0 : status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
138 0 : if (!NT_STATUS_IS_OK(status)) goto failed;
139 :
140 : /* To correctly process any AndX packet (like a tree connect)
141 : * we need to fill in the session on the request here */
142 0 : req->session = smb_sess;
143 0 : sess->old.out.vuid = smb_sess->vuid;
144 :
145 4 : failed:
146 4 : status = nt_status_squash(status);
147 4 : smbsrv_sesssetup_backend_send(req, sess, status);
148 4 : }
149 :
150 : /*
151 : handler for old style session setup
152 : */
153 4 : static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
154 : {
155 4 : struct auth_usersupplied_info *user_info = NULL;
156 0 : struct tsocket_address *remote_address, *local_address;
157 4 : const char *remote_machine = NULL;
158 0 : struct tevent_req *subreq;
159 0 : struct sesssetup_context *state;
160 :
161 4 : sess->old.out.vuid = 0;
162 4 : sess->old.out.action = 0;
163 :
164 4 : sesssetup_common_strings(req,
165 : &sess->old.out.os,
166 : &sess->old.out.lanman,
167 : &sess->old.out.domain);
168 :
169 4 : if (!req->smb_conn->negotiate.done_sesssetup) {
170 4 : req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
171 : }
172 :
173 4 : if (req->smb_conn->negotiate.calling_name) {
174 0 : remote_machine = req->smb_conn->negotiate.calling_name->name;
175 : }
176 :
177 4 : remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
178 4 : if (!remote_address) goto nomem;
179 :
180 4 : if (!remote_machine) {
181 4 : remote_machine = tsocket_address_inet_addr_string(remote_address, req);
182 4 : if (!remote_machine) goto nomem;
183 : }
184 :
185 4 : local_address = socket_get_local_addr(req->smb_conn->connection->socket, req);
186 4 : if (!local_address) goto nomem;
187 :
188 4 : user_info = talloc_zero(req, struct auth_usersupplied_info);
189 4 : if (!user_info) goto nomem;
190 :
191 4 : user_info->service_description = "SMB";
192 :
193 4 : user_info->logon_parameters = 0;
194 4 : user_info->flags = 0;
195 4 : user_info->client.account_name = sess->old.in.user;
196 4 : user_info->client.domain_name = sess->old.in.domain;
197 4 : user_info->workstation_name = remote_machine;
198 :
199 4 : user_info->remote_host = talloc_steal(user_info, remote_address);
200 4 : user_info->local_host = talloc_steal(user_info, local_address);
201 :
202 4 : user_info->password_state = AUTH_PASSWORD_RESPONSE;
203 4 : user_info->password.response.lanman = sess->old.in.password;
204 4 : user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
205 4 : user_info->password.response.nt = data_blob(NULL, 0);
206 :
207 4 : state = talloc(req, struct sesssetup_context);
208 4 : if (!state) goto nomem;
209 :
210 4 : if (req->smb_conn->negotiate.auth_context) {
211 4 : state->auth_context = req->smb_conn->negotiate.auth_context;
212 : } else {
213 : /* TODO: should we use just "anonymous" here? */
214 0 : NTSTATUS status = auth_context_create(state,
215 0 : req->smb_conn->connection->event.ctx,
216 0 : req->smb_conn->connection->msg_ctx,
217 0 : req->smb_conn->lp_ctx,
218 : &state->auth_context);
219 0 : if (!NT_STATUS_IS_OK(status)) {
220 0 : smbsrv_sesssetup_backend_send(req, sess, status);
221 0 : return;
222 : }
223 : }
224 :
225 4 : state->req = req;
226 :
227 4 : subreq = auth_check_password_send(state,
228 4 : req->smb_conn->connection->event.ctx,
229 4 : req->smb_conn->negotiate.auth_context,
230 : user_info);
231 4 : if (!subreq) goto nomem;
232 4 : tevent_req_set_callback(subreq, sesssetup_old_send, state);
233 4 : return;
234 :
235 0 : nomem:
236 0 : smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
237 : }
238 :
239 13 : static void sesssetup_nt1_send(struct tevent_req *subreq)
240 : {
241 13 : struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
242 13 : struct smbsrv_request *req = state->req;
243 13 : union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
244 13 : struct auth_user_info_dc *user_info_dc = NULL;
245 0 : struct auth_session_info *session_info;
246 0 : struct smbsrv_session *smb_sess;
247 13 : uint8_t authoritative = 1;
248 0 : uint32_t flags;
249 0 : NTSTATUS status;
250 :
251 13 : status = auth_check_password_recv(subreq, req, &user_info_dc,
252 : &authoritative);
253 13 : TALLOC_FREE(subreq);
254 13 : if (!NT_STATUS_IS_OK(status)) goto failed;
255 :
256 11 : flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
257 11 : if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
258 7 : flags |= AUTH_SESSION_INFO_AUTHENTICATED;
259 : }
260 : /* This references user_info_dc into session_info */
261 11 : status = state->auth_context->generate_session_info(state->auth_context,
262 : req,
263 : user_info_dc,
264 : sess->nt1.in.user,
265 : flags,
266 : &session_info);
267 11 : if (!NT_STATUS_IS_OK(status)) goto failed;
268 :
269 : /* allocate a new session */
270 11 : smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
271 11 : if (!smb_sess) {
272 0 : status = NT_STATUS_INSUFFICIENT_RESOURCES;
273 0 : goto failed;
274 : }
275 :
276 11 : smbsrv_not_spengo_sesssetup_authz_log(req, session_info);
277 :
278 : /* Ensure this is marked as a 'real' vuid, not one
279 : * simply valid for the session setup leg */
280 11 : status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
281 11 : if (!NT_STATUS_IS_OK(status)) goto failed;
282 :
283 : /* To correctly process any AndX packet (like a tree connect)
284 : * we need to fill in the session on the request here */
285 11 : req->session = smb_sess;
286 11 : sess->nt1.out.vuid = smb_sess->vuid;
287 :
288 11 : if (!smbsrv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
289 : /* Already signing, or disabled */
290 1 : goto done;
291 : }
292 :
293 10 : done:
294 11 : status = NT_STATUS_OK;
295 13 : failed:
296 13 : status = nt_status_squash(status);
297 13 : smbsrv_sesssetup_backend_send(req, sess, status);
298 13 : }
299 :
300 : /*
301 : handler for NT1 style session setup
302 : */
303 13 : static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
304 : {
305 0 : NTSTATUS status;
306 13 : struct auth_usersupplied_info *user_info = NULL;
307 0 : struct tsocket_address *remote_address, *local_address;
308 13 : const char *remote_machine = NULL;
309 0 : struct tevent_req *subreq;
310 0 : struct sesssetup_context *state;
311 13 : bool allow_raw = lpcfg_raw_ntlmv2_auth(req->smb_conn->lp_ctx);
312 :
313 13 : sess->nt1.out.vuid = 0;
314 13 : sess->nt1.out.action = 0;
315 :
316 13 : sesssetup_common_strings(req,
317 : &sess->nt1.out.os,
318 : &sess->nt1.out.lanman,
319 : &sess->nt1.out.domain);
320 :
321 13 : if (!req->smb_conn->negotiate.done_sesssetup) {
322 12 : req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
323 12 : req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
324 : }
325 :
326 13 : state = talloc(req, struct sesssetup_context);
327 13 : if (!state) goto nomem;
328 :
329 13 : state->req = req;
330 :
331 13 : if (req->smb_conn->negotiate.oid) {
332 2 : if (sess->nt1.in.user && *sess->nt1.in.user) {
333 : /* We can't accept a normal login, because we
334 : * don't have a challenge */
335 0 : status = NT_STATUS_LOGON_FAILURE;
336 0 : goto failed;
337 : }
338 :
339 : /* TODO: should we use just "anonymous" here? */
340 2 : status = auth_context_create(state,
341 2 : req->smb_conn->connection->event.ctx,
342 2 : req->smb_conn->connection->msg_ctx,
343 2 : req->smb_conn->lp_ctx,
344 : &state->auth_context);
345 2 : if (!NT_STATUS_IS_OK(status)) goto failed;
346 11 : } else if (req->smb_conn->negotiate.auth_context) {
347 11 : state->auth_context = req->smb_conn->negotiate.auth_context;
348 : } else {
349 : /* TODO: should we use just "anonymous" here? */
350 0 : status = auth_context_create(state,
351 0 : req->smb_conn->connection->event.ctx,
352 0 : req->smb_conn->connection->msg_ctx,
353 0 : req->smb_conn->lp_ctx,
354 : &state->auth_context);
355 0 : if (!NT_STATUS_IS_OK(status)) goto failed;
356 : }
357 :
358 13 : if (req->smb_conn->negotiate.calling_name) {
359 0 : remote_machine = req->smb_conn->negotiate.calling_name->name;
360 : }
361 :
362 13 : remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
363 13 : if (!remote_address) goto nomem;
364 :
365 13 : if (!remote_machine) {
366 13 : remote_machine = tsocket_address_inet_addr_string(remote_address, req);
367 13 : if (!remote_machine) goto nomem;
368 : }
369 :
370 13 : local_address = socket_get_local_addr(req->smb_conn->connection->socket, req);
371 13 : if (!local_address) goto nomem;
372 :
373 13 : user_info = talloc_zero(req, struct auth_usersupplied_info);
374 13 : if (!user_info) goto nomem;
375 :
376 13 : user_info->service_description = "SMB";
377 13 : user_info->auth_description = "bare-NTLM";
378 :
379 13 : user_info->logon_parameters = 0;
380 13 : user_info->flags = 0;
381 13 : user_info->client.account_name = sess->nt1.in.user;
382 13 : user_info->client.domain_name = sess->nt1.in.domain;
383 13 : user_info->workstation_name = remote_machine;
384 13 : user_info->remote_host = talloc_steal(user_info, remote_address);
385 13 : user_info->local_host = talloc_steal(user_info, local_address);
386 :
387 13 : user_info->password_state = AUTH_PASSWORD_RESPONSE;
388 13 : user_info->password.response.lanman = sess->nt1.in.password1;
389 13 : user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data);
390 13 : user_info->password.response.nt = sess->nt1.in.password2;
391 13 : user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data);
392 :
393 13 : if (!allow_raw && user_info->password.response.nt.length >= 48) {
394 : /*
395 : * NTLMv2_RESPONSE has at least 48 bytes
396 : * and should only be supported via NTLMSSP.
397 : */
398 0 : status = NT_STATUS_INVALID_PARAMETER;
399 0 : goto failed;
400 : }
401 :
402 13 : subreq = auth_check_password_send(state,
403 13 : req->smb_conn->connection->event.ctx,
404 : state->auth_context,
405 : user_info);
406 13 : if (!subreq) goto nomem;
407 13 : tevent_req_set_callback(subreq, sesssetup_nt1_send, state);
408 :
409 13 : return;
410 :
411 0 : nomem:
412 0 : status = NT_STATUS_NO_MEMORY;
413 0 : failed:
414 0 : status = nt_status_squash(status);
415 0 : smbsrv_sesssetup_backend_send(req, sess, status);
416 : }
417 :
418 : struct sesssetup_spnego_state {
419 : struct smbsrv_request *req;
420 : union smb_sesssetup *sess;
421 : struct smbsrv_session *smb_sess;
422 : };
423 :
424 1130 : static void sesssetup_spnego_send(struct tevent_req *subreq)
425 : {
426 1130 : struct sesssetup_spnego_state *s = tevent_req_callback_data(subreq,
427 : struct sesssetup_spnego_state);
428 1130 : struct smbsrv_request *req = s->req;
429 1130 : union smb_sesssetup *sess = s->sess;
430 1130 : struct smbsrv_session *smb_sess = s->smb_sess;
431 1130 : struct auth_session_info *session_info = NULL;
432 0 : NTSTATUS status;
433 0 : NTSTATUS skey_status;
434 0 : DATA_BLOB session_key;
435 :
436 1130 : status = gensec_update_recv(subreq, req, &sess->spnego.out.secblob);
437 1130 : packet_recv_enable(req->smb_conn->packet);
438 1130 : TALLOC_FREE(subreq);
439 1130 : if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
440 176 : goto done;
441 954 : } else if (!NT_STATUS_IS_OK(status)) {
442 3 : goto failed;
443 : }
444 :
445 951 : status = gensec_session_info(smb_sess->gensec_ctx, smb_sess, &session_info);
446 951 : if (!NT_STATUS_IS_OK(status)) goto failed;
447 :
448 : /* The session_key is only needed until the end of the smbsrv_setup_signing() call */
449 951 : skey_status = gensec_session_key(smb_sess->gensec_ctx, req, &session_key);
450 951 : if (NT_STATUS_IS_OK(skey_status)) {
451 951 : smbsrv_setup_signing(req->smb_conn, &session_key, NULL);
452 : }
453 :
454 : /* Ensure this is marked as a 'real' vuid, not one
455 : * simply valid for the session setup leg */
456 951 : status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
457 951 : if (!NT_STATUS_IS_OK(status)) goto failed;
458 :
459 951 : req->session = smb_sess;
460 :
461 1127 : done:
462 1127 : sess->spnego.out.vuid = smb_sess->vuid;
463 1130 : failed:
464 1130 : status = nt_status_squash(status);
465 1130 : smbsrv_sesssetup_backend_send(req, sess, status);
466 1130 : if (!NT_STATUS_IS_OK(status) &&
467 179 : !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
468 3 : talloc_free(smb_sess);
469 : }
470 1130 : }
471 :
472 : /*
473 : handler for SPNEGO style session setup
474 : */
475 1133 : static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
476 : {
477 0 : NTSTATUS status;
478 1133 : struct smbsrv_session *smb_sess = NULL;
479 1133 : bool is_smb_sess_new = false;
480 1133 : struct sesssetup_spnego_state *s = NULL;
481 0 : uint16_t vuid;
482 0 : struct tevent_req *subreq;
483 :
484 1133 : sess->spnego.out.vuid = 0;
485 1133 : sess->spnego.out.action = 0;
486 :
487 1133 : sesssetup_common_strings(req,
488 : &sess->spnego.out.os,
489 : &sess->spnego.out.lanman,
490 : &sess->spnego.out.workgroup);
491 :
492 1133 : if (!req->smb_conn->negotiate.done_sesssetup) {
493 1091 : req->smb_conn->negotiate.max_send = sess->spnego.in.bufsize;
494 1091 : req->smb_conn->negotiate.client_caps = sess->spnego.in.capabilities;
495 : }
496 :
497 1133 : vuid = SVAL(req->in.hdr,HDR_UID);
498 :
499 : /* lookup an existing session */
500 1133 : if (vuid == 0) {
501 0 : struct gensec_security *gensec_ctx;
502 0 : struct tsocket_address *remote_address, *local_address;
503 954 : status = samba_server_gensec_start(req,
504 954 : req->smb_conn->connection->event.ctx,
505 954 : req->smb_conn->connection->msg_ctx,
506 954 : req->smb_conn->lp_ctx,
507 954 : req->smb_conn->negotiate.server_credentials,
508 : "cifs",
509 : &gensec_ctx);
510 954 : if (!NT_STATUS_IS_OK(status)) {
511 0 : DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
512 0 : goto failed;
513 : }
514 :
515 954 : gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
516 954 : gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SMB_TRANSPORT);
517 :
518 954 : remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
519 : req);
520 954 : if (!remote_address) {
521 0 : status = NT_STATUS_INTERNAL_ERROR;
522 0 : DBG_ERR("Failed to obtain remote address\n");
523 0 : goto failed;
524 : }
525 :
526 954 : status = gensec_set_remote_address(gensec_ctx,
527 : remote_address);
528 954 : if (!NT_STATUS_IS_OK(status)) {
529 0 : DBG_ERR("Failed to set remote address\n");
530 0 : goto failed;
531 : }
532 :
533 954 : local_address = socket_get_local_addr(req->smb_conn->connection->socket,
534 : req);
535 954 : if (!local_address) {
536 0 : status = NT_STATUS_INTERNAL_ERROR;
537 0 : DBG_ERR("Failed to obtain local address\n");
538 0 : goto failed;
539 : }
540 :
541 954 : status = gensec_set_local_address(gensec_ctx,
542 : local_address);
543 954 : if (!NT_STATUS_IS_OK(status)) {
544 0 : DBG_ERR("Failed to set local address\n");
545 0 : goto failed;
546 : }
547 :
548 954 : status = gensec_set_target_service_description(gensec_ctx,
549 : "SMB");
550 :
551 954 : if (!NT_STATUS_IS_OK(status)) {
552 0 : DBG_ERR("Failed to set service description\n");
553 0 : goto failed;
554 : }
555 :
556 954 : status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid);
557 954 : if (!NT_STATUS_IS_OK(status)) {
558 0 : DEBUG(1, ("Failed to start GENSEC %s server code: %s\n",
559 : gensec_get_name_by_oid(gensec_ctx, req->smb_conn->negotiate.oid), nt_errstr(status)));
560 0 : goto failed;
561 : }
562 :
563 : /* allocate a new session */
564 954 : smb_sess = smbsrv_session_new(req->smb_conn, req->smb_conn, gensec_ctx);
565 954 : if (!smb_sess) {
566 0 : status = NT_STATUS_INSUFFICIENT_RESOURCES;
567 0 : goto failed;
568 : }
569 954 : is_smb_sess_new = true;
570 : } else {
571 179 : smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
572 : }
573 :
574 1133 : if (!smb_sess) {
575 1 : status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
576 1 : goto failed;
577 : }
578 :
579 1132 : if (smb_sess->session_info) {
580 2 : status = NT_STATUS_INVALID_PARAMETER;
581 2 : goto failed;
582 : }
583 :
584 1130 : if (!smb_sess->gensec_ctx) {
585 0 : status = NT_STATUS_INTERNAL_ERROR;
586 0 : DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
587 0 : goto failed;
588 : }
589 :
590 1130 : s = talloc(req, struct sesssetup_spnego_state);
591 1130 : if (!s) goto nomem;
592 1130 : s->req = req;
593 1130 : s->sess = sess;
594 1130 : s->smb_sess = smb_sess;
595 :
596 1130 : subreq = gensec_update_send(s,
597 1130 : req->smb_conn->connection->event.ctx,
598 : smb_sess->gensec_ctx,
599 : sess->spnego.in.secblob);
600 1130 : if (!subreq) {
601 0 : goto nomem;
602 : }
603 : /* disable receipt of more packets on this socket until we've
604 : finished with the session setup. This avoids a problem with
605 : crashes if we get EOF on the socket while processing a session
606 : setup */
607 1130 : packet_recv_disable(req->smb_conn->packet);
608 1130 : tevent_req_set_callback(subreq, sesssetup_spnego_send, s);
609 :
610 1130 : return;
611 :
612 0 : nomem:
613 0 : status = NT_STATUS_NO_MEMORY;
614 3 : failed:
615 3 : if (is_smb_sess_new) {
616 0 : talloc_free(smb_sess);
617 : }
618 3 : status = nt_status_squash(status);
619 3 : smbsrv_sesssetup_backend_send(req, sess, status);
620 : }
621 :
622 : /*
623 : backend for sessionsetup call - this takes all 3 variants of the call
624 : */
625 1150 : void smbsrv_sesssetup_backend(struct smbsrv_request *req,
626 : union smb_sesssetup *sess)
627 : {
628 1150 : switch (sess->old.level) {
629 4 : case RAW_SESSSETUP_OLD:
630 4 : sesssetup_old(req, sess);
631 1150 : return;
632 :
633 13 : case RAW_SESSSETUP_NT1:
634 13 : sesssetup_nt1(req, sess);
635 13 : return;
636 :
637 1133 : case RAW_SESSSETUP_SPNEGO:
638 1133 : sesssetup_spnego(req, sess);
639 1133 : return;
640 :
641 0 : case RAW_SESSSETUP_SMB2:
642 0 : break;
643 : }
644 :
645 0 : smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_INVALID_LEVEL);
646 : }
|