s3: smbd: Now we've proved dst_dirfsp parameter is always NULL, remove the parameter...
[Samba.git] / source3 / smbd / smbXsrv_session.c
blob2c0e3996695762643e9826c095d4bd5edd9d0c5e
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2011-2012
5 Copyright (C) Michael Adam 2012
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include <tevent.h>
24 #include "lib/util/server_id.h"
25 #include "smbd/smbd.h"
26 #include "smbd/globals.h"
27 #include "dbwrap/dbwrap.h"
28 #include "dbwrap/dbwrap_rbt.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "dbwrap/dbwrap_watch.h"
31 #include "session.h"
32 #include "auth.h"
33 #include "auth/gensec/gensec.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/security/security.h"
36 #include "messages.h"
37 #include "lib/util/util_tdb.h"
38 #include "librpc/gen_ndr/ndr_smbXsrv.h"
39 #include "serverid.h"
40 #include "lib/util/tevent_ntstatus.h"
41 #include "lib/global_contexts.h"
42 #include "source3/include/util_tdb.h"
44 struct smbXsrv_session_table {
45 struct {
46 struct db_context *db_ctx;
47 uint32_t lowest_id;
48 uint32_t highest_id;
49 uint32_t max_sessions;
50 uint32_t num_sessions;
51 } local;
52 struct {
53 struct db_context *db_ctx;
54 } global;
57 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
59 NTSTATUS smbXsrv_session_global_init(struct messaging_context *msg_ctx)
61 char *global_path = NULL;
62 struct db_context *backend = NULL;
63 struct db_context *db_ctx = NULL;
65 if (smbXsrv_session_global_db_ctx != NULL) {
66 return NT_STATUS_OK;
70 * This contains secret information like session keys!
72 global_path = lock_path(talloc_tos(), "smbXsrv_session_global.tdb");
73 if (global_path == NULL) {
74 return NT_STATUS_NO_MEMORY;
77 backend = db_open(NULL, global_path,
78 SMBD_VOLATILE_TDB_HASH_SIZE,
79 SMBD_VOLATILE_TDB_FLAGS,
80 O_RDWR | O_CREAT, 0600,
81 DBWRAP_LOCK_ORDER_1,
82 DBWRAP_FLAG_NONE);
83 TALLOC_FREE(global_path);
84 if (backend == NULL) {
85 NTSTATUS status;
87 status = map_nt_error_from_unix_common(errno);
89 return status;
92 db_ctx = db_open_watched(NULL, &backend, global_messaging_context());
93 if (db_ctx == NULL) {
94 TALLOC_FREE(backend);
95 return NT_STATUS_NO_MEMORY;
98 smbXsrv_session_global_db_ctx = db_ctx;
100 return NT_STATUS_OK;
104 * NOTE:
105 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
106 * has the same result as integer comparison between the uint32_t
107 * values.
109 * TODO: implement string based key
112 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
114 static TDB_DATA smbXsrv_session_global_id_to_key(uint32_t id,
115 uint8_t *key_buf)
117 TDB_DATA key;
119 RSIVAL(key_buf, 0, id);
121 key = make_tdb_data(key_buf, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE);
123 return key;
126 #if 0
127 static NTSTATUS smbXsrv_session_global_key_to_id(TDB_DATA key, uint32_t *id)
129 if (id == NULL) {
130 return NT_STATUS_INVALID_PARAMETER;
133 if (key.dsize != SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE) {
134 return NT_STATUS_INTERNAL_DB_CORRUPTION;
137 *id = RIVAL(key.dptr, 0);
139 return NT_STATUS_OK;
141 #endif
143 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
145 static TDB_DATA smbXsrv_session_local_id_to_key(uint32_t id,
146 uint8_t *key_buf)
148 TDB_DATA key;
150 RSIVAL(key_buf, 0, id);
152 key = make_tdb_data(key_buf, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE);
154 return key;
157 static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
159 if (id == NULL) {
160 return NT_STATUS_INVALID_PARAMETER;
163 if (key.dsize != SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE) {
164 return NT_STATUS_INTERNAL_DB_CORRUPTION;
167 *id = RIVAL(key.dptr, 0);
169 return NT_STATUS_OK;
172 static struct db_record *smbXsrv_session_global_fetch_locked(
173 struct db_context *db,
174 uint32_t id,
175 TALLOC_CTX *mem_ctx)
177 TDB_DATA key;
178 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
179 struct db_record *rec = NULL;
181 key = smbXsrv_session_global_id_to_key(id, key_buf);
183 rec = dbwrap_fetch_locked(db, mem_ctx, key);
185 if (rec == NULL) {
186 DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
187 tdb_data_dbg(key));
190 return rec;
193 static struct db_record *smbXsrv_session_local_fetch_locked(
194 struct db_context *db,
195 uint32_t id,
196 TALLOC_CTX *mem_ctx)
198 TDB_DATA key;
199 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
200 struct db_record *rec = NULL;
202 key = smbXsrv_session_local_id_to_key(id, key_buf);
204 rec = dbwrap_fetch_locked(db, mem_ctx, key);
206 if (rec == NULL) {
207 DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
208 tdb_data_dbg(key));
211 return rec;
214 static void smbXsrv_session_close_loop(struct tevent_req *subreq);
216 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
217 uint32_t lowest_id,
218 uint32_t highest_id,
219 uint32_t max_sessions)
221 struct smbXsrv_client *client = conn->client;
222 struct smbXsrv_session_table *table;
223 NTSTATUS status;
224 struct tevent_req *subreq;
225 uint64_t max_range;
227 if (lowest_id > highest_id) {
228 return NT_STATUS_INTERNAL_ERROR;
231 max_range = highest_id;
232 max_range -= lowest_id;
233 max_range += 1;
235 if (max_sessions > max_range) {
236 return NT_STATUS_INTERNAL_ERROR;
239 table = talloc_zero(client, struct smbXsrv_session_table);
240 if (table == NULL) {
241 return NT_STATUS_NO_MEMORY;
244 table->local.db_ctx = db_open_rbt(table);
245 if (table->local.db_ctx == NULL) {
246 TALLOC_FREE(table);
247 return NT_STATUS_NO_MEMORY;
249 table->local.lowest_id = lowest_id;
250 table->local.highest_id = highest_id;
251 table->local.max_sessions = max_sessions;
253 status = smbXsrv_session_global_init(client->msg_ctx);
254 if (!NT_STATUS_IS_OK(status)) {
255 TALLOC_FREE(table);
256 return status;
259 table->global.db_ctx = smbXsrv_session_global_db_ctx;
261 subreq = messaging_read_send(table,
262 client->raw_ev_ctx,
263 client->msg_ctx,
264 MSG_SMBXSRV_SESSION_CLOSE);
265 if (subreq == NULL) {
266 TALLOC_FREE(table);
267 return NT_STATUS_NO_MEMORY;
269 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, client);
271 client->session_table = table;
272 return NT_STATUS_OK;
275 static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq);
277 static void smbXsrv_session_close_loop(struct tevent_req *subreq)
279 struct smbXsrv_client *client =
280 tevent_req_callback_data(subreq,
281 struct smbXsrv_client);
282 struct smbXsrv_session_table *table = client->session_table;
283 int ret;
284 struct messaging_rec *rec = NULL;
285 struct smbXsrv_session_closeB close_blob;
286 enum ndr_err_code ndr_err;
287 struct smbXsrv_session_close0 *close_info0 = NULL;
288 struct smbXsrv_session *session = NULL;
289 NTSTATUS status;
290 struct timeval tv = timeval_current();
291 NTTIME now = timeval_to_nttime(&tv);
293 ret = messaging_read_recv(subreq, talloc_tos(), &rec);
294 TALLOC_FREE(subreq);
295 if (ret != 0) {
296 goto next;
299 ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &close_blob,
300 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_closeB);
301 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
302 status = ndr_map_error2ntstatus(ndr_err);
303 DBG_WARNING("smbXsrv_session_close_loop: "
304 "ndr_pull_struct_blob - %s\n",
305 nt_errstr(status));
306 goto next;
309 DBG_DEBUG("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n");
310 if (DEBUGLVL(DBGLVL_DEBUG)) {
311 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
314 if (close_blob.version != SMBXSRV_VERSION_0) {
315 DBG_ERR("smbXsrv_session_close_loop: "
316 "ignore invalid version %u\n", close_blob.version);
317 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
318 goto next;
321 close_info0 = close_blob.info.info0;
322 if (close_info0 == NULL) {
323 DBG_ERR("smbXsrv_session_close_loop: "
324 "ignore NULL info %u\n", close_blob.version);
325 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
326 goto next;
329 status = smb2srv_session_lookup_client(client,
330 close_info0->old_session_wire_id,
331 now, &session);
332 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
333 DBG_INFO("smbXsrv_session_close_loop: "
334 "old_session_wire_id %llu not found\n",
335 (unsigned long long)close_info0->old_session_wire_id);
336 if (DEBUGLVL(DBGLVL_INFO)) {
337 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
339 goto next;
341 if (!NT_STATUS_IS_OK(status) &&
342 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
343 !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
344 DBG_WARNING("smbXsrv_session_close_loop: "
345 "old_session_wire_id %llu - %s\n",
346 (unsigned long long)close_info0->old_session_wire_id,
347 nt_errstr(status));
348 if (DEBUGLVL(DBGLVL_WARNING)) {
349 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
351 goto next;
354 if (session->global->session_global_id != close_info0->old_session_global_id) {
355 DBG_WARNING("smbXsrv_session_close_loop: "
356 "old_session_wire_id %llu - global %u != %u\n",
357 (unsigned long long)close_info0->old_session_wire_id,
358 session->global->session_global_id,
359 close_info0->old_session_global_id);
360 if (DEBUGLVL(DBGLVL_WARNING)) {
361 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
363 goto next;
366 if (session->global->creation_time != close_info0->old_creation_time) {
367 DBG_WARNING("smbXsrv_session_close_loop: "
368 "old_session_wire_id %llu - "
369 "creation %s (%llu) != %s (%llu)\n",
370 (unsigned long long)close_info0->old_session_wire_id,
371 nt_time_string(rec, session->global->creation_time),
372 (unsigned long long)session->global->creation_time,
373 nt_time_string(rec, close_info0->old_creation_time),
374 (unsigned long long)close_info0->old_creation_time);
375 if (DEBUGLVL(DBGLVL_WARNING)) {
376 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
378 goto next;
381 subreq = smb2srv_session_shutdown_send(session, client->raw_ev_ctx,
382 session, NULL);
383 if (subreq == NULL) {
384 status = NT_STATUS_NO_MEMORY;
385 DBG_ERR("smbXsrv_session_close_loop: "
386 "smb2srv_session_shutdown_send(%llu) failed: %s\n",
387 (unsigned long long)session->global->session_wire_id,
388 nt_errstr(status));
389 if (DEBUGLVL(DBGLVL_WARNING)) {
390 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
392 goto next;
394 tevent_req_set_callback(subreq,
395 smbXsrv_session_close_shutdown_done,
396 session);
398 next:
399 TALLOC_FREE(rec);
401 subreq = messaging_read_send(table,
402 client->raw_ev_ctx,
403 client->msg_ctx,
404 MSG_SMBXSRV_SESSION_CLOSE);
405 if (subreq == NULL) {
406 const char *r;
407 r = "messaging_read_send(MSG_SMBXSRV_SESSION_CLOSE) failed";
408 exit_server_cleanly(r);
409 return;
411 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, client);
414 static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq)
416 struct smbXsrv_session *session =
417 tevent_req_callback_data(subreq,
418 struct smbXsrv_session);
419 NTSTATUS status;
421 status = smb2srv_session_shutdown_recv(subreq);
422 TALLOC_FREE(subreq);
423 if (!NT_STATUS_IS_OK(status)) {
424 DBG_ERR("smbXsrv_session_close_loop: "
425 "smb2srv_session_shutdown_recv(%llu) failed: %s\n",
426 (unsigned long long)session->global->session_wire_id,
427 nt_errstr(status));
430 status = smbXsrv_session_logoff(session);
431 if (!NT_STATUS_IS_OK(status)) {
432 DBG_ERR("smbXsrv_session_close_loop: "
433 "smbXsrv_session_logoff(%llu) failed: %s\n",
434 (unsigned long long)session->global->session_wire_id,
435 nt_errstr(status));
438 TALLOC_FREE(session);
441 struct smb1srv_session_local_allocate_state {
442 const uint32_t lowest_id;
443 const uint32_t highest_id;
444 uint32_t last_id;
445 uint32_t useable_id;
446 NTSTATUS status;
449 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
450 void *private_data)
452 struct smb1srv_session_local_allocate_state *state =
453 (struct smb1srv_session_local_allocate_state *)private_data;
454 TDB_DATA key = dbwrap_record_get_key(rec);
455 uint32_t id = 0;
456 NTSTATUS status;
458 status = smbXsrv_session_local_key_to_id(key, &id);
459 if (!NT_STATUS_IS_OK(status)) {
460 state->status = status;
461 return -1;
464 if (id <= state->last_id) {
465 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
466 return -1;
468 state->last_id = id;
470 if (id > state->useable_id) {
471 state->status = NT_STATUS_OK;
472 return -1;
475 if (state->useable_id == state->highest_id) {
476 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
477 return -1;
480 state->useable_id +=1;
481 return 0;
484 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
485 uint32_t lowest_id,
486 uint32_t highest_id,
487 TALLOC_CTX *mem_ctx,
488 struct db_record **_rec,
489 uint32_t *_id)
491 struct smb1srv_session_local_allocate_state state = {
492 .lowest_id = lowest_id,
493 .highest_id = highest_id,
494 .last_id = 0,
495 .useable_id = lowest_id,
496 .status = NT_STATUS_INTERNAL_ERROR,
498 uint32_t i;
499 uint32_t range;
500 NTSTATUS status;
501 int count = 0;
503 *_rec = NULL;
504 *_id = 0;
506 if (lowest_id > highest_id) {
507 return NT_STATUS_INSUFFICIENT_RESOURCES;
511 * first we try randomly
513 range = (highest_id - lowest_id) + 1;
515 for (i = 0; i < (range / 2); i++) {
516 uint32_t id;
517 TDB_DATA val;
518 struct db_record *rec = NULL;
520 id = generate_random() % range;
521 id += lowest_id;
523 if (id < lowest_id) {
524 id = lowest_id;
526 if (id > highest_id) {
527 id = highest_id;
530 rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
531 if (rec == NULL) {
532 return NT_STATUS_INSUFFICIENT_RESOURCES;
535 val = dbwrap_record_get_value(rec);
536 if (val.dsize != 0) {
537 TALLOC_FREE(rec);
538 continue;
541 *_rec = rec;
542 *_id = id;
543 return NT_STATUS_OK;
547 * if the range is almost full,
548 * we traverse the whole table
549 * (this relies on sorted behavior of dbwrap_rbt)
551 status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
552 &state, &count);
553 if (NT_STATUS_IS_OK(status)) {
554 if (NT_STATUS_IS_OK(state.status)) {
555 return NT_STATUS_INTERNAL_ERROR;
558 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
559 return state.status;
562 if (state.useable_id <= state.highest_id) {
563 state.status = NT_STATUS_OK;
564 } else {
565 return NT_STATUS_INSUFFICIENT_RESOURCES;
567 } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
569 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
571 * If we get anything else it is an error, because it
572 * means we did not manage to find a free slot in
573 * the db.
575 return NT_STATUS_INSUFFICIENT_RESOURCES;
578 if (NT_STATUS_IS_OK(state.status)) {
579 uint32_t id;
580 TDB_DATA val;
581 struct db_record *rec = NULL;
583 id = state.useable_id;
585 rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
586 if (rec == NULL) {
587 return NT_STATUS_INSUFFICIENT_RESOURCES;
590 val = dbwrap_record_get_value(rec);
591 if (val.dsize != 0) {
592 TALLOC_FREE(rec);
593 return NT_STATUS_INTERNAL_DB_CORRUPTION;
596 *_rec = rec;
597 *_id = id;
598 return NT_STATUS_OK;
601 return state.status;
604 struct smbXsrv_session_local_fetch_state {
605 struct smbXsrv_session *session;
606 NTSTATUS status;
609 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
610 void *private_data)
612 struct smbXsrv_session_local_fetch_state *state =
613 (struct smbXsrv_session_local_fetch_state *)private_data;
614 void *ptr;
616 if (data.dsize != sizeof(ptr)) {
617 state->status = NT_STATUS_INTERNAL_DB_ERROR;
618 return;
621 memcpy(&ptr, data.dptr, data.dsize);
622 state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
623 state->status = NT_STATUS_OK;
626 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
627 /* conn: optional */
628 struct smbXsrv_connection *conn,
629 uint32_t session_local_id,
630 NTTIME now,
631 struct smbXsrv_session **_session)
633 struct smbXsrv_session_local_fetch_state state = {
634 .session = NULL,
635 .status = NT_STATUS_INTERNAL_ERROR,
637 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
638 TDB_DATA key;
639 NTSTATUS status;
641 *_session = NULL;
643 if (session_local_id == 0) {
644 return NT_STATUS_USER_SESSION_DELETED;
647 if (table == NULL) {
648 /* this might happen before the end of negprot */
649 return NT_STATUS_USER_SESSION_DELETED;
652 if (table->local.db_ctx == NULL) {
653 return NT_STATUS_INTERNAL_ERROR;
656 key = smbXsrv_session_local_id_to_key(session_local_id, key_buf);
658 status = dbwrap_parse_record(table->local.db_ctx, key,
659 smbXsrv_session_local_fetch_parser,
660 &state);
661 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
662 return NT_STATUS_USER_SESSION_DELETED;
663 } else if (!NT_STATUS_IS_OK(status)) {
664 return status;
666 if (!NT_STATUS_IS_OK(state.status)) {
667 return state.status;
670 if (NT_STATUS_EQUAL(state.session->status, NT_STATUS_USER_SESSION_DELETED)) {
671 return NT_STATUS_USER_SESSION_DELETED;
675 * If a connection is specified check if the session is
676 * valid on the channel.
678 if (conn != NULL) {
679 struct smbXsrv_channel_global0 *c = NULL;
681 status = smbXsrv_session_find_channel(state.session, conn, &c);
682 if (!NT_STATUS_IS_OK(status)) {
683 return status;
687 state.session->idle_time = now;
689 if (!NT_STATUS_IS_OK(state.session->status)) {
690 *_session = state.session;
691 return state.session->status;
694 if (now > state.session->global->expiration_time) {
695 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
698 *_session = state.session;
699 return state.session->status;
702 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
704 return 0;
707 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
708 bool *is_free,
709 bool *was_free,
710 TALLOC_CTX *mem_ctx,
711 struct smbXsrv_session_global0 **_g,
712 uint32_t *pseqnum);
714 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
715 TALLOC_CTX *mem_ctx,
716 struct smbXsrv_session_global0 **_global)
718 uint32_t i;
719 struct smbXsrv_session_global0 *global = NULL;
720 uint32_t last_free = 0;
721 const uint32_t min_tries = 3;
723 *_global = NULL;
725 global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
726 if (global == NULL) {
727 return NT_STATUS_NO_MEMORY;
729 talloc_set_destructor(global, smbXsrv_session_global_destructor);
732 * Here we just randomly try the whole 32-bit space
734 * We use just 32-bit, because we want to reuse the
735 * ID for SRVSVC.
737 for (i = 0; i < UINT32_MAX; i++) {
738 bool is_free = false;
739 bool was_free = false;
740 uint32_t id;
742 if (i >= min_tries && last_free != 0) {
743 id = last_free;
744 } else {
745 id = generate_random();
747 if (id == 0) {
748 id++;
750 if (id == UINT32_MAX) {
751 id--;
754 global->db_rec = smbXsrv_session_global_fetch_locked(db, id,
755 mem_ctx);
756 if (global->db_rec == NULL) {
757 talloc_free(global);
758 return NT_STATUS_INSUFFICIENT_RESOURCES;
761 smbXsrv_session_global_verify_record(global->db_rec,
762 &is_free,
763 &was_free,
764 NULL, NULL, NULL);
766 if (!is_free) {
767 TALLOC_FREE(global->db_rec);
768 continue;
771 if (!was_free && i < min_tries) {
773 * The session_id is free now,
774 * but was not free before.
776 * This happens if a smbd crashed
777 * and did not cleanup the record.
779 * If this is one of our first tries,
780 * then we try to find a real free one.
782 if (last_free == 0) {
783 last_free = id;
785 TALLOC_FREE(global->db_rec);
786 continue;
789 global->session_global_id = id;
791 *_global = global;
792 return NT_STATUS_OK;
795 /* should not be reached */
796 talloc_free(global);
797 return NT_STATUS_INTERNAL_ERROR;
800 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
801 bool *is_free,
802 bool *was_free,
803 TALLOC_CTX *mem_ctx,
804 struct smbXsrv_session_global0 **_g,
805 uint32_t *pseqnum)
807 TDB_DATA key;
808 TDB_DATA val;
809 DATA_BLOB blob;
810 struct smbXsrv_session_globalB global_blob;
811 enum ndr_err_code ndr_err;
812 struct smbXsrv_session_global0 *global = NULL;
813 bool exists;
814 TALLOC_CTX *frame = talloc_stackframe();
816 *is_free = false;
818 if (was_free) {
819 *was_free = false;
821 if (_g) {
822 *_g = NULL;
824 if (pseqnum) {
825 *pseqnum = 0;
828 key = dbwrap_record_get_key(db_rec);
830 val = dbwrap_record_get_value(db_rec);
831 if (val.dsize == 0) {
832 TALLOC_FREE(frame);
833 *is_free = true;
834 if (was_free) {
835 *was_free = true;
837 return;
840 blob = data_blob_const(val.dptr, val.dsize);
842 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
843 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
844 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
845 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
846 DBG_WARNING("smbXsrv_session_global_verify_record: "
847 "key '%s' ndr_pull_struct_blob - %s\n",
848 tdb_data_dbg(key),
849 nt_errstr(status));
850 TALLOC_FREE(frame);
851 *is_free = true;
852 if (was_free) {
853 *was_free = true;
855 return;
858 DBG_DEBUG("smbXsrv_session_global_verify_record\n");
859 if (DEBUGLVL(DBGLVL_DEBUG)) {
860 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
863 if (global_blob.version != SMBXSRV_VERSION_0) {
864 DBG_ERR("smbXsrv_session_global_verify_record: "
865 "key '%s' use unsupported version %u\n",
866 tdb_data_dbg(key),
867 global_blob.version);
868 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
869 TALLOC_FREE(frame);
870 *is_free = true;
871 if (was_free) {
872 *was_free = true;
874 return;
877 global = global_blob.info.info0;
879 #define __BLOB_KEEP_SECRET(__blob) do { \
880 if ((__blob).length != 0) { \
881 talloc_keep_secret((__blob).data); \
883 } while(0)
885 uint32_t i;
886 __BLOB_KEEP_SECRET(global->application_key_blob);
887 __BLOB_KEEP_SECRET(global->signing_key_blob);
888 __BLOB_KEEP_SECRET(global->encryption_key_blob);
889 __BLOB_KEEP_SECRET(global->decryption_key_blob);
890 for (i = 0; i < global->num_channels; i++) {
891 __BLOB_KEEP_SECRET(global->channels[i].signing_key_blob);
894 #undef __BLOB_KEEP_SECRET
896 exists = serverid_exists(&global->channels[0].server_id);
897 if (!exists) {
898 struct server_id_buf idbuf;
899 DBG_NOTICE("smbXsrv_session_global_verify_record: "
900 "key '%s' server_id %s does not exist.\n",
901 tdb_data_dbg(key),
902 server_id_str_buf(global->channels[0].server_id,
903 &idbuf));
904 if (DEBUGLVL(DBGLVL_NOTICE)) {
905 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
907 TALLOC_FREE(frame);
908 dbwrap_record_delete(db_rec);
909 *is_free = true;
910 return;
913 if (_g) {
914 *_g = talloc_move(mem_ctx, &global);
916 if (pseqnum) {
917 *pseqnum = global_blob.seqnum;
919 TALLOC_FREE(frame);
922 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_session_global0 *global)
924 struct smbXsrv_session_globalB global_blob;
925 DATA_BLOB blob = data_blob_null;
926 TDB_DATA key;
927 TDB_DATA val;
928 NTSTATUS status;
929 enum ndr_err_code ndr_err;
932 * TODO: if we use other versions than '0'
933 * we would add glue code here, that would be able to
934 * store the information in the old format.
937 if (global->db_rec == NULL) {
938 return NT_STATUS_INTERNAL_ERROR;
941 key = dbwrap_record_get_key(global->db_rec);
942 val = dbwrap_record_get_value(global->db_rec);
944 ZERO_STRUCT(global_blob);
945 global_blob.version = smbXsrv_version_global_current();
946 if (val.dsize >= 8) {
947 global_blob.seqnum = IVAL(val.dptr, 4);
949 global_blob.seqnum += 1;
950 global_blob.info.info0 = global;
952 ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
953 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
955 status = ndr_map_error2ntstatus(ndr_err);
956 DBG_WARNING("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
957 tdb_data_dbg(key),
958 nt_errstr(status));
959 TALLOC_FREE(global->db_rec);
960 return status;
963 val = make_tdb_data(blob.data, blob.length);
964 status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
965 if (!NT_STATUS_IS_OK(status)) {
966 DBG_WARNING("smbXsrv_session_global_store: key '%s' store - %s\n",
967 tdb_data_dbg(key),
968 nt_errstr(status));
969 TALLOC_FREE(global->db_rec);
970 return status;
973 if (DEBUGLVL(DBGLVL_DEBUG)) {
974 DBG_DEBUG("smbXsrv_session_global_store: key '%s' stored\n",
975 tdb_data_dbg(key));
976 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
979 TALLOC_FREE(global->db_rec);
981 return NT_STATUS_OK;
984 struct smb2srv_session_close_previous_state {
985 struct tevent_context *ev;
986 struct smbXsrv_connection *connection;
987 struct dom_sid *current_sid;
988 uint64_t previous_session_id;
989 uint64_t current_session_id;
990 struct db_record *db_rec;
991 uint64_t watch_instance;
992 uint32_t last_seqnum;
995 static void smb2srv_session_close_previous_cleanup(struct tevent_req *req,
996 enum tevent_req_state req_state)
998 struct smb2srv_session_close_previous_state *state =
999 tevent_req_data(req,
1000 struct smb2srv_session_close_previous_state);
1002 if (state->db_rec != NULL) {
1003 dbwrap_watched_watch_remove_instance(state->db_rec,
1004 state->watch_instance);
1005 state->watch_instance = 0;
1006 TALLOC_FREE(state->db_rec);
1010 static void smb2srv_session_close_previous_check(struct tevent_req *req);
1011 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq);
1013 struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
1014 struct tevent_context *ev,
1015 struct smbXsrv_connection *conn,
1016 struct auth_session_info *session_info,
1017 uint64_t previous_session_id,
1018 uint64_t current_session_id)
1020 struct tevent_req *req;
1021 struct smb2srv_session_close_previous_state *state;
1022 uint32_t global_id = previous_session_id & UINT32_MAX;
1023 uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU;
1024 struct smbXsrv_session_table *table = conn->client->session_table;
1025 struct security_token *current_token = NULL;
1027 req = tevent_req_create(mem_ctx, &state,
1028 struct smb2srv_session_close_previous_state);
1029 if (req == NULL) {
1030 return NULL;
1032 state->ev = ev;
1033 state->connection = conn;
1034 state->previous_session_id = previous_session_id;
1035 state->current_session_id = current_session_id;
1037 tevent_req_set_cleanup_fn(req, smb2srv_session_close_previous_cleanup);
1039 if (global_zeros != 0) {
1040 tevent_req_done(req);
1041 return tevent_req_post(req, ev);
1044 if (session_info == NULL) {
1045 tevent_req_done(req);
1046 return tevent_req_post(req, ev);
1048 current_token = session_info->security_token;
1050 if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
1051 state->current_sid = &current_token->sids[PRIMARY_USER_SID_INDEX];
1054 if (state->current_sid == NULL) {
1055 tevent_req_done(req);
1056 return tevent_req_post(req, ev);
1059 if (!security_token_has_nt_authenticated_users(current_token)) {
1060 /* TODO */
1061 tevent_req_done(req);
1062 return tevent_req_post(req, ev);
1065 state->db_rec = smbXsrv_session_global_fetch_locked(
1066 table->global.db_ctx,
1067 global_id,
1068 state /* TALLOC_CTX */);
1069 if (state->db_rec == NULL) {
1070 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1071 return tevent_req_post(req, ev);
1074 smb2srv_session_close_previous_check(req);
1075 if (!tevent_req_is_in_progress(req)) {
1076 return tevent_req_post(req, ev);
1079 return req;
1082 static void smb2srv_session_close_previous_check(struct tevent_req *req)
1084 struct smb2srv_session_close_previous_state *state =
1085 tevent_req_data(req,
1086 struct smb2srv_session_close_previous_state);
1087 struct smbXsrv_connection *conn = state->connection;
1088 DATA_BLOB blob;
1089 struct security_token *previous_token = NULL;
1090 struct smbXsrv_session_global0 *global = NULL;
1091 enum ndr_err_code ndr_err;
1092 struct smbXsrv_session_close0 close_info0;
1093 struct smbXsrv_session_closeB close_blob;
1094 struct tevent_req *subreq = NULL;
1095 NTSTATUS status;
1096 bool is_free = false;
1097 uint32_t seqnum = 0;
1099 smbXsrv_session_global_verify_record(state->db_rec,
1100 &is_free,
1101 NULL,
1102 state,
1103 &global,
1104 &seqnum);
1106 if (is_free) {
1107 tevent_req_done(req);
1108 return;
1111 if (global->auth_session_info == NULL) {
1112 tevent_req_done(req);
1113 return;
1116 previous_token = global->auth_session_info->security_token;
1118 if (!security_token_is_sid(previous_token, state->current_sid)) {
1119 tevent_req_done(req);
1120 return;
1124 * If the record changed, but we are not happy with the change yet,
1125 * we better remove ourself from the waiter list
1126 * (most likely the first position)
1127 * and re-add us at the end of the list.
1129 * This gives other waiters a change
1130 * to make progress.
1132 * Otherwise we'll keep our waiter instance alive,
1133 * keep waiting (most likely at first position).
1134 * It means the order of watchers stays fair.
1136 if (state->last_seqnum != seqnum) {
1137 state->last_seqnum = seqnum;
1138 dbwrap_watched_watch_remove_instance(state->db_rec,
1139 state->watch_instance);
1140 state->watch_instance =
1141 dbwrap_watched_watch_add_instance(state->db_rec);
1144 subreq = dbwrap_watched_watch_send(state, state->ev, state->db_rec,
1145 state->watch_instance,
1146 (struct server_id){0});
1147 if (tevent_req_nomem(subreq, req)) {
1148 return;
1150 tevent_req_set_callback(subreq,
1151 smb2srv_session_close_previous_modified,
1152 req);
1154 close_info0.old_session_global_id = global->session_global_id;
1155 close_info0.old_session_wire_id = global->session_wire_id;
1156 close_info0.old_creation_time = global->creation_time;
1157 close_info0.new_session_wire_id = state->current_session_id;
1159 ZERO_STRUCT(close_blob);
1160 close_blob.version = smbXsrv_version_global_current();
1161 close_blob.info.info0 = &close_info0;
1163 ndr_err = ndr_push_struct_blob(&blob, state, &close_blob,
1164 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_closeB);
1165 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1166 status = ndr_map_error2ntstatus(ndr_err);
1167 DBG_WARNING("smb2srv_session_close_previous_check: "
1168 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1169 (unsigned long long)close_info0.old_session_wire_id,
1170 (unsigned long long)close_info0.new_session_wire_id,
1171 nt_errstr(status));
1172 tevent_req_nterror(req, status);
1173 return;
1176 status = messaging_send(conn->client->msg_ctx,
1177 global->channels[0].server_id,
1178 MSG_SMBXSRV_SESSION_CLOSE, &blob);
1179 TALLOC_FREE(global);
1180 if (tevent_req_nterror(req, status)) {
1181 return;
1184 TALLOC_FREE(state->db_rec);
1185 return;
1188 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
1190 struct tevent_req *req =
1191 tevent_req_callback_data(subreq,
1192 struct tevent_req);
1193 struct smb2srv_session_close_previous_state *state =
1194 tevent_req_data(req,
1195 struct smb2srv_session_close_previous_state);
1196 uint32_t global_id;
1197 NTSTATUS status;
1198 uint64_t instance = 0;
1200 status = dbwrap_watched_watch_recv(subreq, &instance, NULL, NULL);
1201 TALLOC_FREE(subreq);
1202 if (tevent_req_nterror(req, status)) {
1203 return;
1206 state->watch_instance = instance;
1208 global_id = state->previous_session_id & UINT32_MAX;
1210 state->db_rec = smbXsrv_session_global_fetch_locked(
1211 state->connection->client->session_table->global.db_ctx,
1212 global_id, state /* TALLOC_CTX */);
1213 if (state->db_rec == NULL) {
1214 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1215 return;
1218 smb2srv_session_close_previous_check(req);
1221 NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req)
1223 NTSTATUS status;
1225 if (tevent_req_is_nterror(req, &status)) {
1226 tevent_req_received(req);
1227 return status;
1230 tevent_req_received(req);
1231 return NT_STATUS_OK;
1234 static NTSTATUS smbXsrv_session_clear_and_logoff(struct smbXsrv_session *session)
1236 NTSTATUS status;
1237 struct smbXsrv_connection *xconn = NULL;
1239 if (session->client != NULL) {
1240 xconn = session->client->connections;
1243 for (; xconn != NULL; xconn = xconn->next) {
1244 struct smbd_smb2_request *preq;
1246 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
1247 if (preq->session != session) {
1248 continue;
1251 preq->session = NULL;
1253 * If we no longer have a session we can't
1254 * sign or encrypt replies.
1256 preq->do_signing = false;
1257 preq->do_encryption = false;
1258 preq->preauth = NULL;
1262 status = smbXsrv_session_logoff(session);
1263 return status;
1266 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
1268 NTSTATUS status;
1270 DBG_DEBUG("destructing session(%llu)\n",
1271 (unsigned long long)session->global->session_wire_id);
1273 status = smbXsrv_session_clear_and_logoff(session);
1274 if (!NT_STATUS_IS_OK(status)) {
1275 DBG_ERR("smbXsrv_session_destructor: "
1276 "smbXsrv_session_logoff() failed: %s\n",
1277 nt_errstr(status));
1280 TALLOC_FREE(session->global);
1282 return 0;
1285 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
1286 NTTIME now,
1287 struct smbXsrv_session **_session)
1289 struct smbXsrv_session_table *table = conn->client->session_table;
1290 struct db_record *local_rec = NULL;
1291 struct smbXsrv_session *session = NULL;
1292 void *ptr = NULL;
1293 TDB_DATA val;
1294 struct smbXsrv_session_global0 *global = NULL;
1295 struct smbXsrv_channel_global0 *channel = NULL;
1296 NTSTATUS status;
1298 if (table->local.num_sessions >= table->local.max_sessions) {
1299 return NT_STATUS_INSUFFICIENT_RESOURCES;
1302 session = talloc_zero(table, struct smbXsrv_session);
1303 if (session == NULL) {
1304 return NT_STATUS_NO_MEMORY;
1306 session->table = table;
1307 session->idle_time = now;
1308 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1309 session->client = conn->client;
1310 session->homes_snum = -1;
1312 status = smbXsrv_session_global_allocate(table->global.db_ctx,
1313 session,
1314 &global);
1315 if (!NT_STATUS_IS_OK(status)) {
1316 TALLOC_FREE(session);
1317 return status;
1319 session->global = global;
1321 if (conn->protocol >= PROTOCOL_SMB2_02) {
1322 uint64_t id = global->session_global_id;
1324 global->connection_dialect = conn->smb2.server.dialect;
1326 global->session_wire_id = id;
1328 status = smb2srv_tcon_table_init(session);
1329 if (!NT_STATUS_IS_OK(status)) {
1330 TALLOC_FREE(session);
1331 return status;
1334 session->local_id = global->session_global_id;
1336 local_rec = smbXsrv_session_local_fetch_locked(
1337 table->local.db_ctx,
1338 session->local_id,
1339 session /* TALLOC_CTX */);
1340 if (local_rec == NULL) {
1341 TALLOC_FREE(session);
1342 return NT_STATUS_NO_MEMORY;
1345 val = dbwrap_record_get_value(local_rec);
1346 if (val.dsize != 0) {
1347 TALLOC_FREE(session);
1348 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1350 } else {
1352 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
1353 table->local.lowest_id,
1354 table->local.highest_id,
1355 session,
1356 &local_rec,
1357 &session->local_id);
1358 if (!NT_STATUS_IS_OK(status)) {
1359 TALLOC_FREE(session);
1360 return status;
1363 global->session_wire_id = session->local_id;
1366 global->creation_time = now;
1367 global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
1369 status = smbXsrv_session_add_channel(session, conn, now, &channel);
1370 if (!NT_STATUS_IS_OK(status)) {
1371 TALLOC_FREE(session);
1372 return status;
1375 ptr = session;
1376 val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1377 status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1378 TALLOC_FREE(local_rec);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 TALLOC_FREE(session);
1381 return status;
1383 table->local.num_sessions += 1;
1385 talloc_set_destructor(session, smbXsrv_session_destructor);
1387 status = smbXsrv_session_global_store(global);
1388 if (!NT_STATUS_IS_OK(status)) {
1389 DBG_ERR("smbXsrv_session_create: "
1390 "global_id (0x%08x) store failed - %s\n",
1391 session->global->session_global_id,
1392 nt_errstr(status));
1393 TALLOC_FREE(session);
1394 return status;
1397 if (DEBUGLVL(DBGLVL_DEBUG)) {
1398 struct smbXsrv_sessionB session_blob = {
1399 .version = SMBXSRV_VERSION_0,
1400 .info.info0 = session,
1403 DBG_DEBUG("smbXsrv_session_create: global_id (0x%08x) stored\n",
1404 session->global->session_global_id);
1405 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1408 *_session = session;
1409 return NT_STATUS_OK;
1412 NTSTATUS smbXsrv_session_add_channel(struct smbXsrv_session *session,
1413 struct smbXsrv_connection *conn,
1414 NTTIME now,
1415 struct smbXsrv_channel_global0 **_c)
1417 struct smbXsrv_session_global0 *global = session->global;
1418 struct smbXsrv_channel_global0 *c = NULL;
1420 if (global->num_channels > 31) {
1422 * Windows allow up to 32 channels
1424 return NT_STATUS_INSUFFICIENT_RESOURCES;
1427 c = talloc_realloc(global,
1428 global->channels,
1429 struct smbXsrv_channel_global0,
1430 global->num_channels + 1);
1431 if (c == NULL) {
1432 return NT_STATUS_NO_MEMORY;
1434 global->channels = c;
1436 c = &global->channels[global->num_channels];
1437 ZERO_STRUCTP(c);
1439 c->server_id = messaging_server_id(conn->client->msg_ctx);
1440 c->channel_id = conn->channel_id;
1441 c->creation_time = now;
1442 c->local_address = tsocket_address_string(conn->local_address,
1443 global->channels);
1444 if (c->local_address == NULL) {
1445 return NT_STATUS_NO_MEMORY;
1447 c->remote_address = tsocket_address_string(conn->remote_address,
1448 global->channels);
1449 if (c->remote_address == NULL) {
1450 return NT_STATUS_NO_MEMORY;
1452 c->remote_name = talloc_strdup(global->channels,
1453 conn->remote_hostname);
1454 if (c->remote_name == NULL) {
1455 return NT_STATUS_NO_MEMORY;
1457 c->connection = conn;
1459 global->num_channels += 1;
1461 *_c = c;
1462 return NT_STATUS_OK;
1465 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
1467 struct smbXsrv_session_table *table = session->table;
1468 NTSTATUS status;
1470 if (session->global->db_rec != NULL) {
1471 DBG_ERR("smbXsrv_session_update(0x%08x): "
1472 "Called with db_rec != NULL'\n",
1473 session->global->session_global_id);
1474 return NT_STATUS_INTERNAL_ERROR;
1477 if (table == NULL) {
1478 DBG_ERR("smbXsrv_session_update(0x%08x): "
1479 "Called with table == NULL'\n",
1480 session->global->session_global_id);
1481 return NT_STATUS_INTERNAL_ERROR;
1484 session->global->db_rec = smbXsrv_session_global_fetch_locked(
1485 table->global.db_ctx,
1486 session->global->session_global_id,
1487 session->global /* TALLOC_CTX */);
1488 if (session->global->db_rec == NULL) {
1489 return NT_STATUS_INTERNAL_DB_ERROR;
1492 status = smbXsrv_session_global_store(session->global);
1493 if (!NT_STATUS_IS_OK(status)) {
1494 DBG_ERR("smbXsrv_session_update: "
1495 "global_id (0x%08x) store failed - %s\n",
1496 session->global->session_global_id,
1497 nt_errstr(status));
1498 return status;
1501 if (DEBUGLVL(DBGLVL_DEBUG)) {
1502 struct smbXsrv_sessionB session_blob = {
1503 .version = SMBXSRV_VERSION_0,
1504 .info.info0 = session,
1507 DBG_DEBUG("smbXsrv_session_update: global_id (0x%08x) stored\n",
1508 session->global->session_global_id);
1509 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1512 return NT_STATUS_OK;
1515 NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
1516 const struct smbXsrv_connection *conn,
1517 struct smbXsrv_channel_global0 **_c)
1519 uint32_t i;
1521 for (i=0; i < session->global->num_channels; i++) {
1522 struct smbXsrv_channel_global0 *c = &session->global->channels[i];
1524 if (c->channel_id != conn->channel_id) {
1525 continue;
1528 if (c->connection != conn) {
1529 continue;
1532 *_c = c;
1533 return NT_STATUS_OK;
1536 return NT_STATUS_USER_SESSION_DELETED;
1539 NTSTATUS smbXsrv_session_find_auth(const struct smbXsrv_session *session,
1540 const struct smbXsrv_connection *conn,
1541 NTTIME now,
1542 struct smbXsrv_session_auth0 **_a)
1544 struct smbXsrv_session_auth0 *a;
1546 for (a = session->pending_auth; a != NULL; a = a->next) {
1547 if (a->channel_id != conn->channel_id) {
1548 continue;
1551 if (a->connection == conn) {
1552 if (now != 0) {
1553 a->idle_time = now;
1555 *_a = a;
1556 return NT_STATUS_OK;
1560 return NT_STATUS_USER_SESSION_DELETED;
1563 static int smbXsrv_session_auth0_destructor(struct smbXsrv_session_auth0 *a)
1565 if (a->session == NULL) {
1566 return 0;
1569 DLIST_REMOVE(a->session->pending_auth, a);
1570 a->session = NULL;
1571 return 0;
1574 NTSTATUS smbXsrv_session_create_auth(struct smbXsrv_session *session,
1575 struct smbXsrv_connection *conn,
1576 NTTIME now,
1577 uint8_t in_flags,
1578 uint8_t in_security_mode,
1579 struct smbXsrv_session_auth0 **_a)
1581 struct smbXsrv_session_auth0 *a;
1582 NTSTATUS status;
1584 status = smbXsrv_session_find_auth(session, conn, 0, &a);
1585 if (NT_STATUS_IS_OK(status)) {
1586 return NT_STATUS_INTERNAL_ERROR;
1589 a = talloc_zero(session, struct smbXsrv_session_auth0);
1590 if (a == NULL) {
1591 return NT_STATUS_NO_MEMORY;
1593 a->session = session;
1594 a->connection = conn;
1595 a->in_flags = in_flags;
1596 a->in_security_mode = in_security_mode;
1597 a->creation_time = now;
1598 a->idle_time = now;
1599 a->channel_id = conn->channel_id;
1601 if (conn->protocol >= PROTOCOL_SMB3_11) {
1602 a->preauth = talloc(a, struct smbXsrv_preauth);
1603 if (a->preauth == NULL) {
1604 TALLOC_FREE(session);
1605 return NT_STATUS_NO_MEMORY;
1607 *a->preauth = conn->smb2.preauth;
1610 talloc_set_destructor(a, smbXsrv_session_auth0_destructor);
1611 DLIST_ADD_END(session->pending_auth, a);
1613 *_a = a;
1614 return NT_STATUS_OK;
1617 static void smbXsrv_session_remove_channel_done(struct tevent_req *subreq);
1619 NTSTATUS smbXsrv_session_remove_channel(struct smbXsrv_session *session,
1620 struct smbXsrv_connection *xconn)
1622 struct smbXsrv_session_auth0 *a = NULL;
1623 struct smbXsrv_channel_global0 *c = NULL;
1624 NTSTATUS status;
1625 bool need_update = false;
1627 status = smbXsrv_session_find_auth(session, xconn, 0, &a);
1628 if (!NT_STATUS_IS_OK(status)) {
1629 a = NULL;
1631 status = smbXsrv_session_find_channel(session, xconn, &c);
1632 if (!NT_STATUS_IS_OK(status)) {
1633 c = NULL;
1636 if (a != NULL) {
1637 smbXsrv_session_auth0_destructor(a);
1638 a->connection = NULL;
1639 need_update = true;
1642 if (c != NULL) {
1643 struct smbXsrv_session_global0 *global = session->global;
1644 ptrdiff_t n;
1646 n = (c - global->channels);
1647 if (n >= global->num_channels || n < 0) {
1648 return NT_STATUS_INTERNAL_ERROR;
1650 ARRAY_DEL_ELEMENT(global->channels, n, global->num_channels);
1651 global->num_channels--;
1652 if (global->num_channels == 0) {
1653 struct smbXsrv_client *client = session->client;
1654 struct tevent_queue *xconn_wait_queue =
1655 xconn->transport.shutdown_wait_queue;
1656 struct tevent_req *subreq = NULL;
1659 * Let the connection wait until the session is
1660 * destroyed.
1662 * We don't set a callback, as we just want to block the
1663 * wait queue and the talloc_free() of the session will
1664 * remove the item from the wait queue in order
1665 * to remove allow the connection to disappear.
1667 if (xconn_wait_queue != NULL) {
1668 subreq = tevent_queue_wait_send(session,
1669 client->raw_ev_ctx,
1670 xconn_wait_queue);
1671 if (subreq == NULL) {
1672 status = NT_STATUS_NO_MEMORY;
1673 DBG_ERR("tevent_queue_wait_send() session(%llu) failed: %s\n",
1674 (unsigned long long)session->global->session_wire_id,
1675 nt_errstr(status));
1676 return status;
1681 * This is guaranteed to set
1682 * session->status = NT_STATUS_USER_SESSION_DELETED
1683 * even if NULL is returned.
1685 subreq = smb2srv_session_shutdown_send(session,
1686 client->raw_ev_ctx,
1687 session,
1688 NULL);
1689 if (subreq == NULL) {
1690 status = NT_STATUS_NO_MEMORY;
1691 DBG_ERR("smb2srv_session_shutdown_send(%llu) failed: %s\n",
1692 (unsigned long long)session->global->session_wire_id,
1693 nt_errstr(status));
1694 return status;
1696 tevent_req_set_callback(subreq,
1697 smbXsrv_session_remove_channel_done,
1698 session);
1700 need_update = true;
1703 if (!need_update) {
1704 return NT_STATUS_OK;
1707 return smbXsrv_session_update(session);
1710 static void smbXsrv_session_remove_channel_done(struct tevent_req *subreq)
1712 struct smbXsrv_session *session =
1713 tevent_req_callback_data(subreq,
1714 struct smbXsrv_session);
1715 NTSTATUS status;
1717 status = smb2srv_session_shutdown_recv(subreq);
1718 TALLOC_FREE(subreq);
1719 if (!NT_STATUS_IS_OK(status)) {
1720 DBG_ERR("smb2srv_session_shutdown_recv(%llu) failed: %s\n",
1721 (unsigned long long)session->global->session_wire_id,
1722 nt_errstr(status));
1725 status = smbXsrv_session_logoff(session);
1726 if (!NT_STATUS_IS_OK(status)) {
1727 DBG_ERR("smbXsrv_session_logoff(%llu) failed: %s\n",
1728 (unsigned long long)session->global->session_wire_id,
1729 nt_errstr(status));
1732 TALLOC_FREE(session);
1735 struct smb2srv_session_shutdown_state {
1736 struct tevent_queue *wait_queue;
1739 static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq);
1741 struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
1742 struct tevent_context *ev,
1743 struct smbXsrv_session *session,
1744 struct smbd_smb2_request *current_req)
1746 struct tevent_req *req;
1747 struct smb2srv_session_shutdown_state *state;
1748 struct tevent_req *subreq;
1749 struct smbXsrv_connection *xconn = NULL;
1750 size_t len = 0;
1753 * Make sure that no new request will be able to use this session.
1755 session->status = NT_STATUS_USER_SESSION_DELETED;
1757 req = tevent_req_create(mem_ctx, &state,
1758 struct smb2srv_session_shutdown_state);
1759 if (req == NULL) {
1760 return NULL;
1763 state->wait_queue = tevent_queue_create(state, "smb2srv_session_shutdown_queue");
1764 if (tevent_req_nomem(state->wait_queue, req)) {
1765 return tevent_req_post(req, ev);
1768 for (xconn = session->client->connections; xconn != NULL; xconn = xconn->next) {
1769 struct smbd_smb2_request *preq;
1771 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
1772 if (preq == current_req) {
1773 /* Can't cancel current request. */
1774 continue;
1776 if (preq->session != session) {
1777 /* Request on different session. */
1778 continue;
1781 if (preq->subreq != NULL) {
1782 tevent_req_cancel(preq->subreq);
1786 * Now wait until the request is finished.
1788 * We don't set a callback, as we just want to block the
1789 * wait queue and the talloc_free() of the request will
1790 * remove the item from the wait queue.
1792 subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
1793 if (tevent_req_nomem(subreq, req)) {
1794 return tevent_req_post(req, ev);
1799 len = tevent_queue_length(state->wait_queue);
1800 if (len == 0) {
1801 tevent_req_done(req);
1802 return tevent_req_post(req, ev);
1806 * Now we add our own waiter to the end of the queue,
1807 * this way we get notified when all pending requests are finished
1808 * and send to the socket.
1810 subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
1811 if (tevent_req_nomem(subreq, req)) {
1812 return tevent_req_post(req, ev);
1814 tevent_req_set_callback(subreq, smb2srv_session_shutdown_wait_done, req);
1816 return req;
1819 static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq)
1821 struct tevent_req *req =
1822 tevent_req_callback_data(subreq,
1823 struct tevent_req);
1825 tevent_queue_wait_recv(subreq);
1826 TALLOC_FREE(subreq);
1828 tevent_req_done(req);
1831 NTSTATUS smb2srv_session_shutdown_recv(struct tevent_req *req)
1833 return tevent_req_simple_recv_ntstatus(req);
1836 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
1838 struct smbXsrv_session_table *table;
1839 struct db_record *local_rec = NULL;
1840 struct db_record *global_rec = NULL;
1841 struct smbd_server_connection *sconn = NULL;
1842 NTSTATUS status;
1843 NTSTATUS error = NT_STATUS_OK;
1845 if (session->table == NULL) {
1846 return NT_STATUS_OK;
1849 table = session->table;
1850 session->table = NULL;
1852 sconn = session->client->sconn;
1853 session->client = NULL;
1854 session->status = NT_STATUS_USER_SESSION_DELETED;
1857 * For SMB2 this is a bit redundant as files are also close
1858 * below via smb2srv_tcon_disconnect_all() -> ... ->
1859 * smbXsrv_tcon_disconnect() -> close_cnum() ->
1860 * file_close_conn().
1862 file_close_user(sconn, session->global->session_wire_id);
1864 if (session->tcon_table != NULL) {
1866 * Note: We only have a tcon_table for SMB2.
1868 status = smb2srv_tcon_disconnect_all(session);
1869 if (!NT_STATUS_IS_OK(status)) {
1870 DBG_ERR("smbXsrv_session_logoff(0x%08x): "
1871 "smb2srv_tcon_disconnect_all() failed: %s\n",
1872 session->global->session_global_id,
1873 nt_errstr(status));
1874 error = status;
1878 invalidate_vuid(sconn, session->global->session_wire_id);
1880 global_rec = session->global->db_rec;
1881 session->global->db_rec = NULL;
1882 if (global_rec == NULL) {
1883 global_rec = smbXsrv_session_global_fetch_locked(
1884 table->global.db_ctx,
1885 session->global->session_global_id,
1886 session->global /* TALLOC_CTX */);
1887 if (global_rec == NULL) {
1888 error = NT_STATUS_INTERNAL_ERROR;
1892 if (global_rec != NULL) {
1893 status = dbwrap_record_delete(global_rec);
1894 if (!NT_STATUS_IS_OK(status)) {
1895 TDB_DATA key = dbwrap_record_get_key(global_rec);
1897 DBG_ERR("smbXsrv_session_logoff(0x%08x): "
1898 "failed to delete global key '%s': %s\n",
1899 session->global->session_global_id,
1900 tdb_data_dbg(key),
1901 nt_errstr(status));
1902 error = status;
1905 TALLOC_FREE(global_rec);
1907 local_rec = session->db_rec;
1908 if (local_rec == NULL) {
1909 local_rec = smbXsrv_session_local_fetch_locked(
1910 table->local.db_ctx,
1911 session->local_id,
1912 session /* TALLOC_CTX */);
1913 if (local_rec == NULL) {
1914 error = NT_STATUS_INTERNAL_ERROR;
1918 if (local_rec != NULL) {
1919 status = dbwrap_record_delete(local_rec);
1920 if (!NT_STATUS_IS_OK(status)) {
1921 TDB_DATA key = dbwrap_record_get_key(local_rec);
1923 DBG_ERR("smbXsrv_session_logoff(0x%08x): "
1924 "failed to delete local key '%s': %s\n",
1925 session->global->session_global_id,
1926 tdb_data_dbg(key),
1927 nt_errstr(status));
1928 error = status;
1930 table->local.num_sessions -= 1;
1932 if (session->db_rec == NULL) {
1933 TALLOC_FREE(local_rec);
1935 session->db_rec = NULL;
1937 return error;
1940 struct smbXsrv_session_logoff_all_state {
1941 NTSTATUS first_status;
1942 int errors;
1945 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1946 void *private_data);
1948 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_client *client)
1950 struct smbXsrv_session_table *table = client->session_table;
1951 struct smbXsrv_session_logoff_all_state state;
1952 NTSTATUS status;
1953 int count = 0;
1955 if (table == NULL) {
1956 DBG_DEBUG("smbXsrv_session_logoff_all: "
1957 "empty session_table, nothing to do.\n");
1958 return NT_STATUS_OK;
1961 ZERO_STRUCT(state);
1963 status = dbwrap_traverse(table->local.db_ctx,
1964 smbXsrv_session_logoff_all_callback,
1965 &state, &count);
1966 if (!NT_STATUS_IS_OK(status)) {
1967 DBG_ERR("smbXsrv_session_logoff_all: "
1968 "dbwrap_traverse() failed: %s\n",
1969 nt_errstr(status));
1970 return status;
1973 if (!NT_STATUS_IS_OK(state.first_status)) {
1974 DBG_ERR("smbXsrv_session_logoff_all: "
1975 "count[%d] errors[%d] first[%s]\n",
1976 count, state.errors,
1977 nt_errstr(state.first_status));
1978 return state.first_status;
1981 return NT_STATUS_OK;
1984 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1985 void *private_data)
1987 struct smbXsrv_session_logoff_all_state *state =
1988 (struct smbXsrv_session_logoff_all_state *)private_data;
1989 TDB_DATA val;
1990 void *ptr = NULL;
1991 struct smbXsrv_session *session = NULL;
1992 NTSTATUS status;
1994 val = dbwrap_record_get_value(local_rec);
1995 if (val.dsize != sizeof(ptr)) {
1996 status = NT_STATUS_INTERNAL_ERROR;
1997 if (NT_STATUS_IS_OK(state->first_status)) {
1998 state->first_status = status;
2000 state->errors++;
2001 return 0;
2004 memcpy(&ptr, val.dptr, val.dsize);
2005 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
2007 session->db_rec = local_rec;
2008 status = smbXsrv_session_clear_and_logoff(session);
2009 session->db_rec = NULL;
2010 if (!NT_STATUS_IS_OK(status)) {
2011 if (NT_STATUS_IS_OK(state->first_status)) {
2012 state->first_status = status;
2014 state->errors++;
2015 return 0;
2018 return 0;
2021 struct smbXsrv_session_local_trav_state {
2022 NTSTATUS status;
2023 int (*caller_cb)(struct smbXsrv_session *session,
2024 void *caller_data);
2025 void *caller_data;
2028 static int smbXsrv_session_local_traverse_cb(struct db_record *local_rec,
2029 void *private_data);
2031 NTSTATUS smbXsrv_session_local_traverse(
2032 struct smbXsrv_client *client,
2033 int (*caller_cb)(struct smbXsrv_session *session,
2034 void *caller_data),
2035 void *caller_data)
2037 struct smbXsrv_session_table *table = client->session_table;
2038 struct smbXsrv_session_local_trav_state state;
2039 NTSTATUS status;
2040 int count = 0;
2042 state = (struct smbXsrv_session_local_trav_state) {
2043 .status = NT_STATUS_OK,
2044 .caller_cb = caller_cb,
2045 .caller_data = caller_data,
2048 if (table == NULL) {
2049 DBG_DEBUG("empty session_table, nothing to do.\n");
2050 return NT_STATUS_OK;
2053 status = dbwrap_traverse(table->local.db_ctx,
2054 smbXsrv_session_local_traverse_cb,
2055 &state,
2056 &count);
2057 if (!NT_STATUS_IS_OK(status)) {
2058 DBG_ERR("dbwrap_traverse() failed: %s\n", nt_errstr(status));
2059 return status;
2061 if (!NT_STATUS_IS_OK(state.status)) {
2062 DBG_ERR("count[%d] status[%s]\n",
2063 count, nt_errstr(state.status));
2064 return state.status;
2067 return NT_STATUS_OK;
2070 static int smbXsrv_session_local_traverse_cb(struct db_record *local_rec,
2071 void *private_data)
2073 struct smbXsrv_session_local_trav_state *state =
2074 (struct smbXsrv_session_local_trav_state *)private_data;
2075 TDB_DATA val;
2076 void *ptr = NULL;
2077 struct smbXsrv_session *session = NULL;
2078 int ret;
2080 val = dbwrap_record_get_value(local_rec);
2081 if (val.dsize != sizeof(ptr)) {
2082 state->status = NT_STATUS_INTERNAL_ERROR;
2083 return -1;
2086 memcpy(&ptr, val.dptr, val.dsize);
2087 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
2089 session->db_rec = local_rec;
2090 ret = state->caller_cb(session, state->caller_data);
2091 session->db_rec = NULL;
2093 return ret;
2096 struct smbXsrv_session_disconnect_xconn_state {
2097 struct smbXsrv_connection *xconn;
2098 NTSTATUS first_status;
2099 int errors;
2102 static int smbXsrv_session_disconnect_xconn_callback(struct db_record *local_rec,
2103 void *private_data);
2105 NTSTATUS smbXsrv_session_disconnect_xconn(struct smbXsrv_connection *xconn)
2107 struct smbXsrv_client *client = xconn->client;
2108 struct smbXsrv_session_table *table = client->session_table;
2109 struct smbXsrv_session_disconnect_xconn_state state;
2110 NTSTATUS status;
2111 int count = 0;
2113 if (table == NULL) {
2114 DBG_ERR("empty session_table, nothing to do.\n");
2115 return NT_STATUS_OK;
2118 ZERO_STRUCT(state);
2119 state.xconn = xconn;
2121 status = dbwrap_traverse(table->local.db_ctx,
2122 smbXsrv_session_disconnect_xconn_callback,
2123 &state, &count);
2124 if (!NT_STATUS_IS_OK(status)) {
2125 DBG_ERR("dbwrap_traverse() failed: %s\n",
2126 nt_errstr(status));
2127 return status;
2130 if (!NT_STATUS_IS_OK(state.first_status)) {
2131 DBG_ERR("count[%d] errors[%d] first[%s]\n",
2132 count, state.errors,
2133 nt_errstr(state.first_status));
2134 return state.first_status;
2137 return NT_STATUS_OK;
2140 static int smbXsrv_session_disconnect_xconn_callback(struct db_record *local_rec,
2141 void *private_data)
2143 struct smbXsrv_session_disconnect_xconn_state *state =
2144 (struct smbXsrv_session_disconnect_xconn_state *)private_data;
2145 TDB_DATA val;
2146 void *ptr = NULL;
2147 struct smbXsrv_session *session = NULL;
2148 NTSTATUS status;
2150 val = dbwrap_record_get_value(local_rec);
2151 if (val.dsize != sizeof(ptr)) {
2152 status = NT_STATUS_INTERNAL_ERROR;
2153 if (NT_STATUS_IS_OK(state->first_status)) {
2154 state->first_status = status;
2156 state->errors++;
2157 return 0;
2160 memcpy(&ptr, val.dptr, val.dsize);
2161 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
2163 session->db_rec = local_rec;
2164 status = smbXsrv_session_remove_channel(session, state->xconn);
2165 session->db_rec = NULL;
2166 if (!NT_STATUS_IS_OK(status)) {
2167 if (NT_STATUS_IS_OK(state->first_status)) {
2168 state->first_status = status;
2170 state->errors++;
2173 return 0;
2176 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
2179 * Allow a range from 1..65534 with 65534 values.
2181 return smbXsrv_session_table_init(conn, 1, UINT16_MAX - 1,
2182 UINT16_MAX - 1);
2185 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
2186 uint16_t vuid, NTTIME now,
2187 struct smbXsrv_session **session)
2189 struct smbXsrv_session_table *table = conn->client->session_table;
2190 uint32_t local_id = vuid;
2192 return smbXsrv_session_local_lookup(table, conn, local_id, now,
2193 session);
2196 NTSTATUS smbXsrv_session_info_lookup(struct smbXsrv_client *client,
2197 uint64_t session_wire_id,
2198 struct auth_session_info **si)
2200 struct smbXsrv_session_table *table = client->session_table;
2201 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
2202 struct smbXsrv_session_local_fetch_state state = {
2203 .session = NULL,
2204 .status = NT_STATUS_INTERNAL_ERROR,
2206 TDB_DATA key;
2207 NTSTATUS status;
2209 if (session_wire_id == 0) {
2210 return NT_STATUS_USER_SESSION_DELETED;
2213 if (table == NULL) {
2214 /* this might happen before the end of negprot */
2215 return NT_STATUS_USER_SESSION_DELETED;
2218 if (table->local.db_ctx == NULL) {
2219 return NT_STATUS_INTERNAL_ERROR;
2222 key = smbXsrv_session_local_id_to_key(session_wire_id, key_buf);
2224 status = dbwrap_parse_record(table->local.db_ctx, key,
2225 smbXsrv_session_local_fetch_parser,
2226 &state);
2227 if (!NT_STATUS_IS_OK(status)) {
2228 return status;
2230 if (!NT_STATUS_IS_OK(state.status)) {
2231 return state.status;
2233 if (state.session->global->auth_session_info == NULL) {
2234 return NT_STATUS_USER_SESSION_DELETED;
2237 *si = state.session->global->auth_session_info;
2238 return NT_STATUS_OK;
2242 * In memory of get_valid_user_struct()
2244 * This function is similar to smbXsrv_session_local_lookup() and it's wrappers,
2245 * but it doesn't implement the state checks of
2246 * those. get_valid_smbXsrv_session() is NOT meant to be called to validate the
2247 * session wire-id of incoming SMB requests, it MUST only be used in later
2248 * internal processing where the session wire-id has already been validated.
2250 NTSTATUS get_valid_smbXsrv_session(struct smbXsrv_client *client,
2251 uint64_t session_wire_id,
2252 struct smbXsrv_session **session)
2254 struct smbXsrv_session_table *table = client->session_table;
2255 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
2256 struct smbXsrv_session_local_fetch_state state = {
2257 .session = NULL,
2258 .status = NT_STATUS_INTERNAL_ERROR,
2260 TDB_DATA key;
2261 NTSTATUS status;
2263 if (session_wire_id == 0) {
2264 return NT_STATUS_USER_SESSION_DELETED;
2267 if (table == NULL) {
2268 /* this might happen before the end of negprot */
2269 return NT_STATUS_USER_SESSION_DELETED;
2272 if (table->local.db_ctx == NULL) {
2273 return NT_STATUS_INTERNAL_ERROR;
2276 key = smbXsrv_session_local_id_to_key(session_wire_id, key_buf);
2278 status = dbwrap_parse_record(table->local.db_ctx, key,
2279 smbXsrv_session_local_fetch_parser,
2280 &state);
2281 if (!NT_STATUS_IS_OK(status)) {
2282 return status;
2284 if (!NT_STATUS_IS_OK(state.status)) {
2285 return state.status;
2287 if (state.session->global->auth_session_info == NULL) {
2288 return NT_STATUS_USER_SESSION_DELETED;
2291 *session = state.session;
2292 return NT_STATUS_OK;
2295 NTSTATUS smb2srv_session_lookup_global(struct smbXsrv_client *client,
2296 uint64_t session_wire_id,
2297 TALLOC_CTX *mem_ctx,
2298 struct smbXsrv_session **_session)
2300 TALLOC_CTX *frame = talloc_stackframe();
2301 struct smbXsrv_session_table *table = client->session_table;
2302 uint32_t global_id = session_wire_id & UINT32_MAX;
2303 uint64_t global_zeros = session_wire_id & 0xFFFFFFFF00000000LLU;
2304 struct smbXsrv_session *session = NULL;
2305 struct db_record *global_rec = NULL;
2306 bool is_free = false;
2307 NTSTATUS status;
2309 if (global_id == 0) {
2310 TALLOC_FREE(frame);
2311 return NT_STATUS_USER_SESSION_DELETED;
2313 if (global_zeros != 0) {
2314 TALLOC_FREE(frame);
2315 return NT_STATUS_USER_SESSION_DELETED;
2318 if (table == NULL) {
2319 /* this might happen before the end of negprot */
2320 TALLOC_FREE(frame);
2321 return NT_STATUS_USER_SESSION_DELETED;
2324 if (table->global.db_ctx == NULL) {
2325 TALLOC_FREE(frame);
2326 return NT_STATUS_INTERNAL_ERROR;
2329 session = talloc_zero(mem_ctx, struct smbXsrv_session);
2330 if (session == NULL) {
2331 TALLOC_FREE(frame);
2332 return NT_STATUS_NO_MEMORY;
2334 talloc_steal(frame, session);
2336 session->client = client;
2337 session->status = NT_STATUS_BAD_LOGON_SESSION_STATE;
2338 session->local_id = global_id;
2341 * This means smb2_get_new_nonce() will return
2342 * NT_STATUS_ENCRYPTION_FAILED.
2344 * But we initialize some random parts just in case...
2346 session->nonce_high_max = session->nonce_high = 0;
2347 generate_nonce_buffer((uint8_t *)&session->nonce_high_random,
2348 sizeof(session->nonce_high_random));
2349 generate_nonce_buffer((uint8_t *)&session->nonce_low,
2350 sizeof(session->nonce_low));
2352 global_rec = smbXsrv_session_global_fetch_locked(table->global.db_ctx,
2353 global_id,
2354 frame);
2355 if (global_rec == NULL) {
2356 TALLOC_FREE(frame);
2357 return NT_STATUS_INTERNAL_DB_ERROR;
2360 smbXsrv_session_global_verify_record(global_rec,
2361 &is_free,
2362 NULL,
2363 session,
2364 &session->global,
2365 NULL);
2366 if (is_free) {
2367 TALLOC_FREE(frame);
2368 return NT_STATUS_USER_SESSION_DELETED;
2372 * We don't have channels on this session
2373 * and only the main signing key
2375 session->global->num_channels = 0;
2376 status = smb2_signing_key_sign_create(session->global,
2377 session->global->signing_algo,
2378 NULL, /* no master key */
2379 NULL, /* derivations */
2380 &session->global->signing_key);
2381 if (!NT_STATUS_IS_OK(status)) {
2382 TALLOC_FREE(frame);
2383 return NT_STATUS_NO_MEMORY;
2385 session->global->signing_key->blob = session->global->signing_key_blob;
2386 session->global->signing_flags = 0;
2388 status = smb2_signing_key_cipher_create(session->global,
2389 session->global->encryption_cipher,
2390 NULL, /* no master key */
2391 NULL, /* derivations */
2392 &session->global->decryption_key);
2393 if (!NT_STATUS_IS_OK(status)) {
2394 TALLOC_FREE(frame);
2395 return NT_STATUS_NO_MEMORY;
2397 session->global->decryption_key->blob = session->global->decryption_key_blob;
2398 session->global->encryption_flags = 0;
2400 *_session = talloc_move(mem_ctx, &session);
2401 TALLOC_FREE(frame);
2402 return NT_STATUS_OK;
2405 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
2408 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
2410 return smbXsrv_session_table_init(conn, 1, UINT32_MAX - 1,
2411 UINT16_MAX - 1);
2414 static NTSTATUS smb2srv_session_lookup_raw(struct smbXsrv_session_table *table,
2415 /* conn: optional */
2416 struct smbXsrv_connection *conn,
2417 uint64_t session_id, NTTIME now,
2418 struct smbXsrv_session **session)
2420 uint32_t local_id = session_id & UINT32_MAX;
2421 uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
2423 if (local_zeros != 0) {
2424 return NT_STATUS_USER_SESSION_DELETED;
2427 return smbXsrv_session_local_lookup(table, conn, local_id, now,
2428 session);
2431 NTSTATUS smb2srv_session_lookup_conn(struct smbXsrv_connection *conn,
2432 uint64_t session_id, NTTIME now,
2433 struct smbXsrv_session **session)
2435 struct smbXsrv_session_table *table = conn->client->session_table;
2436 return smb2srv_session_lookup_raw(table, conn, session_id, now,
2437 session);
2440 NTSTATUS smb2srv_session_lookup_client(struct smbXsrv_client *client,
2441 uint64_t session_id, NTTIME now,
2442 struct smbXsrv_session **session)
2444 struct smbXsrv_session_table *table = client->session_table;
2445 return smb2srv_session_lookup_raw(table, NULL, session_id, now,
2446 session);
2449 struct smbXsrv_session_global_traverse_state {
2450 int (*fn)(struct smbXsrv_session_global0 *, void *);
2451 void *private_data;
2454 static int smbXsrv_session_global_traverse_fn(struct db_record *rec, void *data)
2456 int ret = -1;
2457 struct smbXsrv_session_global_traverse_state *state =
2458 (struct smbXsrv_session_global_traverse_state*)data;
2459 TDB_DATA key = dbwrap_record_get_key(rec);
2460 TDB_DATA val = dbwrap_record_get_value(rec);
2461 DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
2462 struct smbXsrv_session_globalB global_blob;
2463 enum ndr_err_code ndr_err;
2464 TALLOC_CTX *frame = talloc_stackframe();
2466 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
2467 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
2468 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2469 DBG_WARNING("Invalid record in smbXsrv_session_global.tdb:"
2470 "key '%s' ndr_pull_struct_blob - %s\n",
2471 tdb_data_dbg(key),
2472 ndr_errstr(ndr_err));
2473 goto done;
2476 if (global_blob.version != SMBXSRV_VERSION_0) {
2477 DBG_WARNING("Invalid record in smbXsrv_session_global.tdb:"
2478 "key '%s' unsupported version - %d\n",
2479 tdb_data_dbg(key),
2480 (int)global_blob.version);
2481 goto done;
2484 if (global_blob.info.info0 == NULL) {
2485 DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
2486 "key '%s' info0 NULL pointer\n",
2487 tdb_data_dbg(key));
2488 goto done;
2491 global_blob.info.info0->db_rec = rec;
2492 ret = state->fn(global_blob.info.info0, state->private_data);
2493 done:
2494 TALLOC_FREE(frame);
2495 return ret;
2498 NTSTATUS smbXsrv_session_global_traverse(
2499 int (*fn)(struct smbXsrv_session_global0 *, void *),
2500 void *private_data)
2503 NTSTATUS status;
2504 int count = 0;
2505 struct smbXsrv_session_global_traverse_state state = {
2506 .fn = fn,
2507 .private_data = private_data,
2510 become_root();
2511 status = smbXsrv_session_global_init(NULL);
2512 if (!NT_STATUS_IS_OK(status)) {
2513 unbecome_root();
2514 DBG_ERR("Failed to initialize session_global: %s\n",
2515 nt_errstr(status));
2516 return status;
2519 status = dbwrap_traverse_read(smbXsrv_session_global_db_ctx,
2520 smbXsrv_session_global_traverse_fn,
2521 &state,
2522 &count);
2523 unbecome_root();
2525 return status;