ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / smb_server / smb / sesssetup.c
blob69cbdca388cf18e6009ac00f889f8497638cda54
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
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.
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.
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/>.
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"
36 struct sesssetup_context {
37 struct auth4_context *auth_context;
38 struct smbsrv_request *req;
42 * Log the SMB authentication, as by not calling GENSEC we won't log
43 * it during the gensec_session_info().
45 void smbsrv_not_spengo_sesssetup_authz_log(struct smbsrv_request *req,
46 struct auth_session_info *session_info)
48 struct tsocket_address *local_address;
49 struct tsocket_address *remote_address;
50 TALLOC_CTX *frame = talloc_stackframe();
52 remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
53 frame);
54 local_address = socket_get_local_addr(req->smb_conn->connection->socket,
55 frame);
57 log_successful_authz_event(req->smb_conn->connection->msg_ctx,
58 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 */);
68 talloc_free(frame);
69 return;
74 setup the OS, Lanman and domain portions of a session setup reply
76 static void sesssetup_common_strings(struct smbsrv_request *req,
77 char **os, char **lanman, char **domain)
79 (*os) = talloc_asprintf(req, "Unix");
80 (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
81 (*domain) = talloc_asprintf(req, "%s",
82 lpcfg_workgroup(req->smb_conn->lp_ctx));
85 static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req,
86 union smb_sesssetup *sess,
87 NTSTATUS status)
89 if (NT_STATUS_IS_OK(status)) {
90 req->smb_conn->negotiate.done_sesssetup = true;
91 /* we need to keep the session long term */
92 req->session = talloc_steal(req->smb_conn, req->session);
94 smbsrv_reply_sesssetup_send(req, sess, status);
97 static void sesssetup_old_send(struct tevent_req *subreq)
99 struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
100 struct smbsrv_request *req = state->req;
102 union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
103 struct auth_user_info_dc *user_info_dc = NULL;
104 struct auth_session_info *session_info;
105 struct smbsrv_session *smb_sess;
106 NTSTATUS status;
107 uint8_t authoritative = 1;
108 uint32_t flags;
110 status = auth_check_password_recv(subreq, req, &user_info_dc,
111 &authoritative);
112 TALLOC_FREE(subreq);
113 if (!NT_STATUS_IS_OK(status)) goto failed;
115 flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
116 if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
117 flags |= AUTH_SESSION_INFO_AUTHENTICATED;
119 /* This references user_info_dc into session_info */
120 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 if (!NT_STATUS_IS_OK(status)) goto failed;
126 /* allocate a new session */
127 smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
128 if (!smb_sess) {
129 status = NT_STATUS_INSUFFICIENT_RESOURCES;
130 goto failed;
133 smbsrv_not_spengo_sesssetup_authz_log(req, session_info);
135 /* Ensure this is marked as a 'real' vuid, not one
136 * simply valid for the session setup leg */
137 status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
138 if (!NT_STATUS_IS_OK(status)) goto failed;
140 /* To correctly process any AndX packet (like a tree connect)
141 * we need to fill in the session on the request here */
142 req->session = smb_sess;
143 sess->old.out.vuid = smb_sess->vuid;
145 failed:
146 status = nt_status_squash(status);
147 smbsrv_sesssetup_backend_send(req, sess, status);
151 handler for old style session setup
153 static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
155 struct auth_usersupplied_info *user_info = NULL;
156 struct tsocket_address *remote_address, *local_address;
157 const char *remote_machine = NULL;
158 struct tevent_req *subreq;
159 struct sesssetup_context *state;
161 sess->old.out.vuid = 0;
162 sess->old.out.action = 0;
164 sesssetup_common_strings(req,
165 &sess->old.out.os,
166 &sess->old.out.lanman,
167 &sess->old.out.domain);
169 if (!req->smb_conn->negotiate.done_sesssetup) {
170 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
173 if (req->smb_conn->negotiate.calling_name) {
174 remote_machine = req->smb_conn->negotiate.calling_name->name;
177 remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
178 if (!remote_address) goto nomem;
180 if (!remote_machine) {
181 remote_machine = tsocket_address_inet_addr_string(remote_address, req);
182 if (!remote_machine) goto nomem;
185 local_address = socket_get_local_addr(req->smb_conn->connection->socket, req);
186 if (!local_address) goto nomem;
188 user_info = talloc_zero(req, struct auth_usersupplied_info);
189 if (!user_info) goto nomem;
191 user_info->service_description = "SMB";
193 user_info->logon_parameters = 0;
194 user_info->flags = 0;
195 user_info->client.account_name = sess->old.in.user;
196 user_info->client.domain_name = sess->old.in.domain;
197 user_info->workstation_name = remote_machine;
199 user_info->remote_host = talloc_steal(user_info, remote_address);
200 user_info->local_host = talloc_steal(user_info, local_address);
202 user_info->password_state = AUTH_PASSWORD_RESPONSE;
203 user_info->password.response.lanman = sess->old.in.password;
204 user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
205 user_info->password.response.nt = data_blob(NULL, 0);
207 state = talloc(req, struct sesssetup_context);
208 if (!state) goto nomem;
210 if (req->smb_conn->negotiate.auth_context) {
211 state->auth_context = req->smb_conn->negotiate.auth_context;
212 } else {
213 /* TODO: should we use just "anonymous" here? */
214 NTSTATUS status = auth_context_create(state,
215 req->smb_conn->connection->event.ctx,
216 req->smb_conn->connection->msg_ctx,
217 req->smb_conn->lp_ctx,
218 &state->auth_context);
219 if (!NT_STATUS_IS_OK(status)) {
220 smbsrv_sesssetup_backend_send(req, sess, status);
221 return;
225 state->req = req;
227 subreq = auth_check_password_send(state,
228 req->smb_conn->connection->event.ctx,
229 req->smb_conn->negotiate.auth_context,
230 user_info);
231 if (!subreq) goto nomem;
232 tevent_req_set_callback(subreq, sesssetup_old_send, state);
233 return;
235 nomem:
236 smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
239 static void sesssetup_nt1_send(struct tevent_req *subreq)
241 struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
242 struct smbsrv_request *req = state->req;
243 union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
244 struct auth_user_info_dc *user_info_dc = NULL;
245 struct auth_session_info *session_info;
246 struct smbsrv_session *smb_sess;
247 uint8_t authoritative = 1;
248 uint32_t flags;
249 NTSTATUS status;
251 status = auth_check_password_recv(subreq, req, &user_info_dc,
252 &authoritative);
253 TALLOC_FREE(subreq);
254 if (!NT_STATUS_IS_OK(status)) goto failed;
256 flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
257 if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
258 flags |= AUTH_SESSION_INFO_AUTHENTICATED;
260 /* This references user_info_dc into session_info */
261 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 if (!NT_STATUS_IS_OK(status)) goto failed;
269 /* allocate a new session */
270 smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
271 if (!smb_sess) {
272 status = NT_STATUS_INSUFFICIENT_RESOURCES;
273 goto failed;
276 smbsrv_not_spengo_sesssetup_authz_log(req, session_info);
278 /* Ensure this is marked as a 'real' vuid, not one
279 * simply valid for the session setup leg */
280 status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
281 if (!NT_STATUS_IS_OK(status)) goto failed;
283 /* To correctly process any AndX packet (like a tree connect)
284 * we need to fill in the session on the request here */
285 req->session = smb_sess;
286 sess->nt1.out.vuid = smb_sess->vuid;
288 if (!smbsrv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
289 /* Already signing, or disabled */
290 goto done;
293 done:
294 status = NT_STATUS_OK;
295 failed:
296 status = nt_status_squash(status);
297 smbsrv_sesssetup_backend_send(req, sess, status);
301 handler for NT1 style session setup
303 static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
305 NTSTATUS status;
306 struct auth_usersupplied_info *user_info = NULL;
307 struct tsocket_address *remote_address, *local_address;
308 const char *remote_machine = NULL;
309 struct tevent_req *subreq;
310 struct sesssetup_context *state;
311 bool allow_raw = lpcfg_raw_ntlmv2_auth(req->smb_conn->lp_ctx);
313 sess->nt1.out.vuid = 0;
314 sess->nt1.out.action = 0;
316 sesssetup_common_strings(req,
317 &sess->nt1.out.os,
318 &sess->nt1.out.lanman,
319 &sess->nt1.out.domain);
321 if (!req->smb_conn->negotiate.done_sesssetup) {
322 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
323 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
326 state = talloc(req, struct sesssetup_context);
327 if (!state) goto nomem;
329 state->req = req;
331 if (req->smb_conn->negotiate.oid) {
332 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 status = NT_STATUS_LOGON_FAILURE;
336 goto failed;
339 /* TODO: should we use just "anonymous" here? */
340 status = auth_context_create(state,
341 req->smb_conn->connection->event.ctx,
342 req->smb_conn->connection->msg_ctx,
343 req->smb_conn->lp_ctx,
344 &state->auth_context);
345 if (!NT_STATUS_IS_OK(status)) goto failed;
346 } else if (req->smb_conn->negotiate.auth_context) {
347 state->auth_context = req->smb_conn->negotiate.auth_context;
348 } else {
349 /* TODO: should we use just "anonymous" here? */
350 status = auth_context_create(state,
351 req->smb_conn->connection->event.ctx,
352 req->smb_conn->connection->msg_ctx,
353 req->smb_conn->lp_ctx,
354 &state->auth_context);
355 if (!NT_STATUS_IS_OK(status)) goto failed;
358 if (req->smb_conn->negotiate.calling_name) {
359 remote_machine = req->smb_conn->negotiate.calling_name->name;
362 remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
363 if (!remote_address) goto nomem;
365 if (!remote_machine) {
366 remote_machine = tsocket_address_inet_addr_string(remote_address, req);
367 if (!remote_machine) goto nomem;
370 local_address = socket_get_local_addr(req->smb_conn->connection->socket, req);
371 if (!local_address) goto nomem;
373 user_info = talloc_zero(req, struct auth_usersupplied_info);
374 if (!user_info) goto nomem;
376 user_info->service_description = "SMB";
377 user_info->auth_description = "bare-NTLM";
379 user_info->logon_parameters = 0;
380 user_info->flags = 0;
381 user_info->client.account_name = sess->nt1.in.user;
382 user_info->client.domain_name = sess->nt1.in.domain;
383 user_info->workstation_name = remote_machine;
384 user_info->remote_host = talloc_steal(user_info, remote_address);
385 user_info->local_host = talloc_steal(user_info, local_address);
387 user_info->password_state = AUTH_PASSWORD_RESPONSE;
388 user_info->password.response.lanman = sess->nt1.in.password1;
389 user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data);
390 user_info->password.response.nt = sess->nt1.in.password2;
391 user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data);
393 if (!allow_raw && user_info->password.response.nt.length >= 48) {
395 * NTLMv2_RESPONSE has at least 48 bytes
396 * and should only be supported via NTLMSSP.
398 status = NT_STATUS_INVALID_PARAMETER;
399 goto failed;
402 subreq = auth_check_password_send(state,
403 req->smb_conn->connection->event.ctx,
404 state->auth_context,
405 user_info);
406 if (!subreq) goto nomem;
407 tevent_req_set_callback(subreq, sesssetup_nt1_send, state);
409 return;
411 nomem:
412 status = NT_STATUS_NO_MEMORY;
413 failed:
414 status = nt_status_squash(status);
415 smbsrv_sesssetup_backend_send(req, sess, status);
418 struct sesssetup_spnego_state {
419 struct smbsrv_request *req;
420 union smb_sesssetup *sess;
421 struct smbsrv_session *smb_sess;
424 static void sesssetup_spnego_send(struct tevent_req *subreq)
426 struct sesssetup_spnego_state *s = tevent_req_callback_data(subreq,
427 struct sesssetup_spnego_state);
428 struct smbsrv_request *req = s->req;
429 union smb_sesssetup *sess = s->sess;
430 struct smbsrv_session *smb_sess = s->smb_sess;
431 struct auth_session_info *session_info = NULL;
432 NTSTATUS status;
433 NTSTATUS skey_status;
434 DATA_BLOB session_key;
436 status = gensec_update_recv(subreq, req, &sess->spnego.out.secblob);
437 packet_recv_enable(req->smb_conn->packet);
438 TALLOC_FREE(subreq);
439 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
440 goto done;
441 } else if (!NT_STATUS_IS_OK(status)) {
442 goto failed;
445 status = gensec_session_info(smb_sess->gensec_ctx, smb_sess, &session_info);
446 if (!NT_STATUS_IS_OK(status)) goto failed;
448 /* The session_key is only needed until the end of the smbsrv_setup_signing() call */
449 skey_status = gensec_session_key(smb_sess->gensec_ctx, req, &session_key);
450 if (NT_STATUS_IS_OK(skey_status)) {
451 smbsrv_setup_signing(req->smb_conn, &session_key, NULL);
454 /* Ensure this is marked as a 'real' vuid, not one
455 * simply valid for the session setup leg */
456 status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
457 if (!NT_STATUS_IS_OK(status)) goto failed;
459 req->session = smb_sess;
461 done:
462 sess->spnego.out.vuid = smb_sess->vuid;
463 failed:
464 status = nt_status_squash(status);
465 smbsrv_sesssetup_backend_send(req, sess, status);
466 if (!NT_STATUS_IS_OK(status) &&
467 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
468 talloc_free(smb_sess);
473 handler for SPNEGO style session setup
475 static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
477 NTSTATUS status;
478 struct smbsrv_session *smb_sess = NULL;
479 bool is_smb_sess_new = false;
480 struct sesssetup_spnego_state *s = NULL;
481 uint16_t vuid;
482 struct tevent_req *subreq;
484 sess->spnego.out.vuid = 0;
485 sess->spnego.out.action = 0;
487 sesssetup_common_strings(req,
488 &sess->spnego.out.os,
489 &sess->spnego.out.lanman,
490 &sess->spnego.out.workgroup);
492 if (!req->smb_conn->negotiate.done_sesssetup) {
493 req->smb_conn->negotiate.max_send = sess->spnego.in.bufsize;
494 req->smb_conn->negotiate.client_caps = sess->spnego.in.capabilities;
497 vuid = SVAL(req->in.hdr,HDR_UID);
499 /* lookup an existing session */
500 if (vuid == 0) {
501 struct gensec_security *gensec_ctx;
502 struct tsocket_address *remote_address, *local_address;
503 status = samba_server_gensec_start(req,
504 req->smb_conn->connection->event.ctx,
505 req->smb_conn->connection->msg_ctx,
506 req->smb_conn->lp_ctx,
507 req->smb_conn->negotiate.server_credentials,
508 "cifs",
509 &gensec_ctx);
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
512 goto failed;
515 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
516 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SMB_TRANSPORT);
518 remote_address = socket_get_remote_addr(req->smb_conn->connection->socket,
519 req);
520 if (!remote_address) {
521 status = NT_STATUS_INTERNAL_ERROR;
522 DBG_ERR("Failed to obtain remote address\n");
523 goto failed;
526 status = gensec_set_remote_address(gensec_ctx,
527 remote_address);
528 if (!NT_STATUS_IS_OK(status)) {
529 DBG_ERR("Failed to set remote address\n");
530 goto failed;
533 local_address = socket_get_local_addr(req->smb_conn->connection->socket,
534 req);
535 if (!local_address) {
536 status = NT_STATUS_INTERNAL_ERROR;
537 DBG_ERR("Failed to obtain local address\n");
538 goto failed;
541 status = gensec_set_local_address(gensec_ctx,
542 local_address);
543 if (!NT_STATUS_IS_OK(status)) {
544 DBG_ERR("Failed to set local address\n");
545 goto failed;
548 status = gensec_set_target_service_description(gensec_ctx,
549 "SMB");
551 if (!NT_STATUS_IS_OK(status)) {
552 DBG_ERR("Failed to set service description\n");
553 goto failed;
556 status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid);
557 if (!NT_STATUS_IS_OK(status)) {
558 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 goto failed;
563 /* allocate a new session */
564 smb_sess = smbsrv_session_new(req->smb_conn, req->smb_conn, gensec_ctx);
565 if (!smb_sess) {
566 status = NT_STATUS_INSUFFICIENT_RESOURCES;
567 goto failed;
569 is_smb_sess_new = true;
570 } else {
571 smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
574 if (!smb_sess) {
575 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
576 goto failed;
579 if (smb_sess->session_info) {
580 status = NT_STATUS_INVALID_PARAMETER;
581 goto failed;
584 if (!smb_sess->gensec_ctx) {
585 status = NT_STATUS_INTERNAL_ERROR;
586 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
587 goto failed;
590 s = talloc(req, struct sesssetup_spnego_state);
591 if (!s) goto nomem;
592 s->req = req;
593 s->sess = sess;
594 s->smb_sess = smb_sess;
596 subreq = gensec_update_send(s,
597 req->smb_conn->connection->event.ctx,
598 smb_sess->gensec_ctx,
599 sess->spnego.in.secblob);
600 if (!subreq) {
601 goto nomem;
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 packet_recv_disable(req->smb_conn->packet);
608 tevent_req_set_callback(subreq, sesssetup_spnego_send, s);
610 return;
612 nomem:
613 status = NT_STATUS_NO_MEMORY;
614 failed:
615 if (is_smb_sess_new) {
616 talloc_free(smb_sess);
618 status = nt_status_squash(status);
619 smbsrv_sesssetup_backend_send(req, sess, status);
623 backend for sessionsetup call - this takes all 3 variants of the call
625 void smbsrv_sesssetup_backend(struct smbsrv_request *req,
626 union smb_sesssetup *sess)
628 switch (sess->old.level) {
629 case RAW_SESSSETUP_OLD:
630 sesssetup_old(req, sess);
631 return;
633 case RAW_SESSSETUP_NT1:
634 sesssetup_nt1(req, sess);
635 return;
637 case RAW_SESSSETUP_SPNEGO:
638 sesssetup_spnego(req, sess);
639 return;
641 case RAW_SESSSETUP_SMB2:
642 break;
645 smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_INVALID_LEVEL);