replace: Add nss_wrapper_enabled().
[Samba.git] / source3 / smbd / smbXsrv_session.c
blob560fa3c2b4d5da110edea8b42f073c094192e690
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 "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_rbt.h"
28 #include "dbwrap/dbwrap_open.h"
29 #include "dbwrap/dbwrap_watch.h"
30 #include "session.h"
31 #include "auth.h"
32 #include "auth/gensec/gensec.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "../libcli/security/security.h"
35 #include "messages.h"
36 #include "lib/util/util_tdb.h"
37 #include "librpc/gen_ndr/ndr_smbXsrv.h"
38 #include "serverid.h"
39 #include "lib/util/tevent_ntstatus.h"
41 struct smbXsrv_session_table {
42 struct {
43 struct db_context *db_ctx;
44 uint32_t lowest_id;
45 uint32_t highest_id;
46 uint32_t max_sessions;
47 uint32_t num_sessions;
48 } local;
49 struct {
50 struct db_context *db_ctx;
51 } global;
54 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
56 NTSTATUS smbXsrv_session_global_init(void)
58 const char *global_path = NULL;
59 struct db_context *db_ctx = NULL;
61 if (smbXsrv_session_global_db_ctx != NULL) {
62 return NT_STATUS_OK;
66 * This contains secret information like session keys!
68 global_path = lock_path("smbXsrv_session_global.tdb");
70 db_ctx = db_open(NULL, global_path,
71 0, /* hash_size */
72 TDB_DEFAULT |
73 TDB_CLEAR_IF_FIRST |
74 TDB_INCOMPATIBLE_HASH,
75 O_RDWR | O_CREAT, 0600,
76 DBWRAP_LOCK_ORDER_1,
77 DBWRAP_FLAG_NONE);
78 if (db_ctx == NULL) {
79 NTSTATUS status;
81 status = map_nt_error_from_unix_common(errno);
83 return status;
86 smbXsrv_session_global_db_ctx = db_ctx;
88 return NT_STATUS_OK;
92 * NOTE:
93 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
94 * has the same result as integer comparison between the uint32_t
95 * values.
97 * TODO: implement string based key
100 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
102 static TDB_DATA smbXsrv_session_global_id_to_key(uint32_t id,
103 uint8_t *key_buf)
105 TDB_DATA key;
107 RSIVAL(key_buf, 0, id);
109 key = make_tdb_data(key_buf, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE);
111 return key;
114 #if 0
115 static NTSTATUS smbXsrv_session_global_key_to_id(TDB_DATA key, uint32_t *id)
117 if (id == NULL) {
118 return NT_STATUS_INVALID_PARAMETER;
121 if (key.dsize != SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE) {
122 return NT_STATUS_INTERNAL_DB_CORRUPTION;
125 *id = RIVAL(key.dptr, 0);
127 return NT_STATUS_OK;
129 #endif
131 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
133 static TDB_DATA smbXsrv_session_local_id_to_key(uint32_t id,
134 uint8_t *key_buf)
136 TDB_DATA key;
138 RSIVAL(key_buf, 0, id);
140 key = make_tdb_data(key_buf, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE);
142 return key;
145 static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
147 if (id == NULL) {
148 return NT_STATUS_INVALID_PARAMETER;
151 if (key.dsize != SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE) {
152 return NT_STATUS_INTERNAL_DB_CORRUPTION;
155 *id = RIVAL(key.dptr, 0);
157 return NT_STATUS_OK;
160 static void smbXsrv_session_close_loop(struct tevent_req *subreq);
162 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
163 uint32_t lowest_id,
164 uint32_t highest_id,
165 uint32_t max_sessions)
167 struct smbXsrv_session_table *table;
168 NTSTATUS status;
169 struct tevent_req *subreq;
170 uint64_t max_range;
172 if (lowest_id > highest_id) {
173 return NT_STATUS_INTERNAL_ERROR;
176 max_range = highest_id;
177 max_range -= lowest_id;
178 max_range += 1;
180 if (max_sessions > max_range) {
181 return NT_STATUS_INTERNAL_ERROR;
184 table = talloc_zero(conn, struct smbXsrv_session_table);
185 if (table == NULL) {
186 return NT_STATUS_NO_MEMORY;
189 table->local.db_ctx = db_open_rbt(table);
190 if (table->local.db_ctx == NULL) {
191 TALLOC_FREE(table);
192 return NT_STATUS_NO_MEMORY;
194 table->local.lowest_id = lowest_id;
195 table->local.highest_id = highest_id;
196 table->local.max_sessions = max_sessions;
198 status = smbXsrv_session_global_init();
199 if (!NT_STATUS_IS_OK(status)) {
200 TALLOC_FREE(table);
201 return status;
204 table->global.db_ctx = smbXsrv_session_global_db_ctx;
206 dbwrap_watch_db(table->global.db_ctx, conn->msg_ctx);
208 subreq = messaging_read_send(table, conn->ev_ctx, conn->msg_ctx,
209 MSG_SMBXSRV_SESSION_CLOSE);
210 if (subreq == NULL) {
211 TALLOC_FREE(table);
212 return NT_STATUS_NO_MEMORY;
214 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, conn);
216 conn->session_table = table;
217 return NT_STATUS_OK;
220 static void smbXsrv_session_close_loop(struct tevent_req *subreq)
222 struct smbXsrv_connection *conn =
223 tevent_req_callback_data(subreq,
224 struct smbXsrv_connection);
225 struct smbXsrv_session_table *table = conn->session_table;
226 int ret;
227 struct messaging_rec *rec = NULL;
228 struct smbXsrv_session_closeB close_blob;
229 enum ndr_err_code ndr_err;
230 struct smbXsrv_session_close0 *close_info0 = NULL;
231 struct smbXsrv_session *session = NULL;
232 NTSTATUS status;
233 struct timeval tv = timeval_current();
234 NTTIME now = timeval_to_nttime(&tv);
236 ret = messaging_read_recv(subreq, talloc_tos(), &rec);
237 TALLOC_FREE(subreq);
238 if (ret != 0) {
239 goto next;
242 ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &close_blob,
243 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_closeB);
244 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
245 status = ndr_map_error2ntstatus(ndr_err);
246 DEBUG(1,("smbXsrv_session_close_loop: "
247 "ndr_pull_struct_blob - %s\n",
248 nt_errstr(status)));
249 goto next;
252 DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
253 if (DEBUGLVL(10)) {
254 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
257 if (close_blob.version != SMBXSRV_VERSION_0) {
258 DEBUG(0,("smbXsrv_session_close_loop: "
259 "ignore invalid version %u\n", close_blob.version));
260 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
261 goto next;
264 close_info0 = close_blob.info.info0;
265 if (close_info0 == NULL) {
266 DEBUG(0,("smbXsrv_session_close_loop: "
267 "ignore NULL info %u\n", close_blob.version));
268 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
269 goto next;
272 status = smb2srv_session_lookup(conn, close_info0->old_session_wire_id,
273 now, &session);
274 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
275 DEBUG(4,("smbXsrv_session_close_loop: "
276 "old_session_wire_id %llu not found\n",
277 (unsigned long long)close_info0->old_session_wire_id));
278 if (DEBUGLVL(4)) {
279 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
281 goto next;
283 if (!NT_STATUS_IS_OK(status) &&
284 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
285 !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
286 DEBUG(1,("smbXsrv_session_close_loop: "
287 "old_session_wire_id %llu - %s\n",
288 (unsigned long long)close_info0->old_session_wire_id,
289 nt_errstr(status)));
290 if (DEBUGLVL(1)) {
291 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
293 goto next;
296 if (session->global->session_global_id != close_info0->old_session_global_id) {
297 DEBUG(1,("smbXsrv_session_close_loop: "
298 "old_session_wire_id %llu - global %u != %u\n",
299 (unsigned long long)close_info0->old_session_wire_id,
300 session->global->session_global_id,
301 close_info0->old_session_global_id));
302 if (DEBUGLVL(1)) {
303 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
305 goto next;
308 if (session->global->creation_time != close_info0->old_creation_time) {
309 DEBUG(1,("smbXsrv_session_close_loop: "
310 "old_session_wire_id %llu - "
311 "creation %s (%llu) != %s (%llu)\n",
312 (unsigned long long)close_info0->old_session_wire_id,
313 nt_time_string(rec, session->global->creation_time),
314 (unsigned long long)session->global->creation_time,
315 nt_time_string(rec, close_info0->old_creation_time),
316 (unsigned long long)close_info0->old_creation_time));
317 if (DEBUGLVL(1)) {
318 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
320 goto next;
324 * TODO: cancel all outstanding requests on the session
326 status = smbXsrv_session_logoff(session);
327 if (!NT_STATUS_IS_OK(status)) {
328 DEBUG(0, ("smbXsrv_session_close_loop: "
329 "smbXsrv_session_logoff(%llu) failed: %s\n",
330 (unsigned long long)session->global->session_wire_id,
331 nt_errstr(status)));
332 if (DEBUGLVL(1)) {
333 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
336 TALLOC_FREE(session);
338 next:
339 TALLOC_FREE(rec);
341 subreq = messaging_read_send(table, conn->ev_ctx, conn->msg_ctx,
342 MSG_SMBXSRV_SESSION_CLOSE);
343 if (subreq == NULL) {
344 smbd_server_connection_terminate(conn->sconn,
345 "msg_read_send() failed");
346 return;
348 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, conn);
351 struct smb1srv_session_local_allocate_state {
352 const uint32_t lowest_id;
353 const uint32_t highest_id;
354 uint32_t last_id;
355 uint32_t useable_id;
356 NTSTATUS status;
359 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
360 void *private_data)
362 struct smb1srv_session_local_allocate_state *state =
363 (struct smb1srv_session_local_allocate_state *)private_data;
364 TDB_DATA key = dbwrap_record_get_key(rec);
365 uint32_t id = 0;
366 NTSTATUS status;
368 status = smbXsrv_session_local_key_to_id(key, &id);
369 if (!NT_STATUS_IS_OK(status)) {
370 state->status = status;
371 return -1;
374 if (id <= state->last_id) {
375 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
376 return -1;
378 state->last_id = id;
380 if (id > state->useable_id) {
381 state->status = NT_STATUS_OK;
382 return -1;
385 if (state->useable_id == state->highest_id) {
386 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
387 return -1;
390 state->useable_id +=1;
391 return 0;
394 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
395 uint32_t lowest_id,
396 uint32_t highest_id,
397 TALLOC_CTX *mem_ctx,
398 struct db_record **_rec,
399 uint32_t *_id)
401 struct smb1srv_session_local_allocate_state state = {
402 .lowest_id = lowest_id,
403 .highest_id = highest_id,
404 .last_id = 0,
405 .useable_id = lowest_id,
406 .status = NT_STATUS_INTERNAL_ERROR,
408 uint32_t i;
409 uint32_t range;
410 NTSTATUS status;
411 int count = 0;
413 *_rec = NULL;
414 *_id = 0;
416 if (lowest_id > highest_id) {
417 return NT_STATUS_INSUFFICIENT_RESOURCES;
421 * first we try randomly
423 range = (highest_id - lowest_id) + 1;
425 for (i = 0; i < (range / 2); i++) {
426 uint32_t id;
427 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
428 TDB_DATA key;
429 TDB_DATA val;
430 struct db_record *rec = NULL;
432 id = generate_random() % range;
433 id += lowest_id;
435 if (id < lowest_id) {
436 id = lowest_id;
438 if (id > highest_id) {
439 id = highest_id;
442 key = smbXsrv_session_local_id_to_key(id, key_buf);
444 rec = dbwrap_fetch_locked(db, mem_ctx, key);
445 if (rec == NULL) {
446 return NT_STATUS_INSUFFICIENT_RESOURCES;
449 val = dbwrap_record_get_value(rec);
450 if (val.dsize != 0) {
451 TALLOC_FREE(rec);
452 continue;
455 *_rec = rec;
456 *_id = id;
457 return NT_STATUS_OK;
461 * if the range is almost full,
462 * we traverse the whole table
463 * (this relies on sorted behavior of dbwrap_rbt)
465 status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
466 &state, &count);
467 if (NT_STATUS_IS_OK(status)) {
468 if (NT_STATUS_IS_OK(state.status)) {
469 return NT_STATUS_INTERNAL_ERROR;
472 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
473 return state.status;
476 if (state.useable_id <= state.highest_id) {
477 state.status = NT_STATUS_OK;
478 } else {
479 return NT_STATUS_INSUFFICIENT_RESOURCES;
481 } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
483 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
485 * If we get anything else it is an error, because it
486 * means we did not manage to find a free slot in
487 * the db.
489 return NT_STATUS_INSUFFICIENT_RESOURCES;
492 if (NT_STATUS_IS_OK(state.status)) {
493 uint32_t id;
494 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
495 TDB_DATA key;
496 TDB_DATA val;
497 struct db_record *rec = NULL;
499 id = state.useable_id;
501 key = smbXsrv_session_local_id_to_key(id, key_buf);
503 rec = dbwrap_fetch_locked(db, mem_ctx, key);
504 if (rec == NULL) {
505 return NT_STATUS_INSUFFICIENT_RESOURCES;
508 val = dbwrap_record_get_value(rec);
509 if (val.dsize != 0) {
510 TALLOC_FREE(rec);
511 return NT_STATUS_INTERNAL_DB_CORRUPTION;
514 *_rec = rec;
515 *_id = id;
516 return NT_STATUS_OK;
519 return state.status;
522 struct smbXsrv_session_local_fetch_state {
523 struct smbXsrv_session *session;
524 NTSTATUS status;
527 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
528 void *private_data)
530 struct smbXsrv_session_local_fetch_state *state =
531 (struct smbXsrv_session_local_fetch_state *)private_data;
532 void *ptr;
534 if (data.dsize != sizeof(ptr)) {
535 state->status = NT_STATUS_INTERNAL_DB_ERROR;
536 return;
539 memcpy(&ptr, data.dptr, data.dsize);
540 state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
541 state->status = NT_STATUS_OK;
544 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
545 uint32_t session_local_id,
546 NTTIME now,
547 struct smbXsrv_session **_session)
549 struct smbXsrv_session_local_fetch_state state = {
550 .session = NULL,
551 .status = NT_STATUS_INTERNAL_ERROR,
553 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
554 TDB_DATA key;
555 NTSTATUS status;
557 *_session = NULL;
559 if (session_local_id == 0) {
560 return NT_STATUS_USER_SESSION_DELETED;
563 if (table == NULL) {
564 /* this might happen before the end of negprot */
565 return NT_STATUS_USER_SESSION_DELETED;
568 if (table->local.db_ctx == NULL) {
569 return NT_STATUS_INTERNAL_ERROR;
572 key = smbXsrv_session_local_id_to_key(session_local_id, key_buf);
574 status = dbwrap_parse_record(table->local.db_ctx, key,
575 smbXsrv_session_local_fetch_parser,
576 &state);
577 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
578 return NT_STATUS_USER_SESSION_DELETED;
579 } else if (!NT_STATUS_IS_OK(status)) {
580 return status;
582 if (!NT_STATUS_IS_OK(state.status)) {
583 return state.status;
586 if (NT_STATUS_EQUAL(state.session->status, NT_STATUS_USER_SESSION_DELETED)) {
587 return NT_STATUS_USER_SESSION_DELETED;
590 state.session->idle_time = now;
592 if (!NT_STATUS_IS_OK(state.session->status)) {
593 *_session = state.session;
594 return state.session->status;
597 if (now > state.session->global->expiration_time) {
598 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
601 *_session = state.session;
602 return state.session->status;
605 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
607 return 0;
610 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
611 bool *is_free,
612 bool *was_free,
613 TALLOC_CTX *mem_ctx,
614 struct smbXsrv_session_global0 **_g);
616 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
617 TALLOC_CTX *mem_ctx,
618 struct smbXsrv_session_global0 **_global)
620 uint32_t i;
621 struct smbXsrv_session_global0 *global = NULL;
622 uint32_t last_free = 0;
623 const uint32_t min_tries = 3;
625 *_global = NULL;
627 global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
628 if (global == NULL) {
629 return NT_STATUS_NO_MEMORY;
631 talloc_set_destructor(global, smbXsrv_session_global_destructor);
634 * Here we just randomly try the whole 32-bit space
636 * We use just 32-bit, because we want to reuse the
637 * ID for SRVSVC.
639 for (i = 0; i < UINT32_MAX; i++) {
640 bool is_free = false;
641 bool was_free = false;
642 uint32_t id;
643 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
644 TDB_DATA key;
646 if (i >= min_tries && last_free != 0) {
647 id = last_free;
648 } else {
649 id = generate_random();
651 if (id == 0) {
652 id++;
654 if (id == UINT32_MAX) {
655 id--;
658 key = smbXsrv_session_global_id_to_key(id, key_buf);
660 global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
661 if (global->db_rec == NULL) {
662 talloc_free(global);
663 return NT_STATUS_INSUFFICIENT_RESOURCES;
666 smbXsrv_session_global_verify_record(global->db_rec,
667 &is_free,
668 &was_free,
669 NULL, NULL);
671 if (!is_free) {
672 TALLOC_FREE(global->db_rec);
673 continue;
676 if (!was_free && i < min_tries) {
678 * The session_id is free now,
679 * but was not free before.
681 * This happens if a smbd crashed
682 * and did not cleanup the record.
684 * If this is one of our first tries,
685 * then we try to find a real free one.
687 if (last_free == 0) {
688 last_free = id;
690 TALLOC_FREE(global->db_rec);
691 continue;
694 global->session_global_id = id;
696 *_global = global;
697 return NT_STATUS_OK;
700 /* should not be reached */
701 talloc_free(global);
702 return NT_STATUS_INTERNAL_ERROR;
705 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
706 bool *is_free,
707 bool *was_free,
708 TALLOC_CTX *mem_ctx,
709 struct smbXsrv_session_global0 **_g)
711 TDB_DATA key;
712 TDB_DATA val;
713 DATA_BLOB blob;
714 struct smbXsrv_session_globalB global_blob;
715 enum ndr_err_code ndr_err;
716 struct smbXsrv_session_global0 *global = NULL;
717 bool exists;
718 TALLOC_CTX *frame = talloc_stackframe();
720 *is_free = false;
722 if (was_free) {
723 *was_free = false;
725 if (_g) {
726 *_g = NULL;
729 key = dbwrap_record_get_key(db_rec);
731 val = dbwrap_record_get_value(db_rec);
732 if (val.dsize == 0) {
733 TALLOC_FREE(frame);
734 *is_free = true;
735 if (was_free) {
736 *was_free = true;
738 return;
741 blob = data_blob_const(val.dptr, val.dsize);
743 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
744 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
745 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
746 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
747 DEBUG(1,("smbXsrv_session_global_verify_record: "
748 "key '%s' ndr_pull_struct_blob - %s\n",
749 hex_encode_talloc(frame, key.dptr, key.dsize),
750 nt_errstr(status)));
751 TALLOC_FREE(frame);
752 return;
755 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
756 if (DEBUGLVL(10)) {
757 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
760 if (global_blob.version != SMBXSRV_VERSION_0) {
761 DEBUG(0,("smbXsrv_session_global_verify_record: "
762 "key '%s' use unsupported version %u\n",
763 hex_encode_talloc(frame, key.dptr, key.dsize),
764 global_blob.version));
765 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
766 TALLOC_FREE(frame);
767 return;
770 global = global_blob.info.info0;
772 exists = serverid_exists(&global->channels[0].server_id);
773 if (!exists) {
774 DEBUG(2,("smbXsrv_session_global_verify_record: "
775 "key '%s' server_id %s does not exist.\n",
776 hex_encode_talloc(frame, key.dptr, key.dsize),
777 server_id_str(frame, &global->channels[0].server_id)));
778 if (DEBUGLVL(2)) {
779 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
781 TALLOC_FREE(frame);
782 dbwrap_record_delete(db_rec);
783 *is_free = true;
784 return;
787 if (_g) {
788 *_g = talloc_move(mem_ctx, &global);
790 TALLOC_FREE(frame);
793 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_session_global0 *global)
795 struct smbXsrv_session_globalB global_blob;
796 DATA_BLOB blob = data_blob_null;
797 TDB_DATA key;
798 TDB_DATA val;
799 NTSTATUS status;
800 enum ndr_err_code ndr_err;
803 * TODO: if we use other versions than '0'
804 * we would add glue code here, that would be able to
805 * store the information in the old format.
808 if (global->db_rec == NULL) {
809 return NT_STATUS_INTERNAL_ERROR;
812 key = dbwrap_record_get_key(global->db_rec);
813 val = dbwrap_record_get_value(global->db_rec);
815 ZERO_STRUCT(global_blob);
816 global_blob.version = smbXsrv_version_global_current();
817 if (val.dsize >= 8) {
818 global_blob.seqnum = IVAL(val.dptr, 4);
820 global_blob.seqnum += 1;
821 global_blob.info.info0 = global;
823 ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
824 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
825 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
826 status = ndr_map_error2ntstatus(ndr_err);
827 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
828 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
829 nt_errstr(status)));
830 TALLOC_FREE(global->db_rec);
831 return status;
834 val = make_tdb_data(blob.data, blob.length);
835 status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
836 if (!NT_STATUS_IS_OK(status)) {
837 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
838 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
839 nt_errstr(status)));
840 TALLOC_FREE(global->db_rec);
841 return status;
844 if (DEBUGLVL(10)) {
845 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
846 hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
847 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
850 TALLOC_FREE(global->db_rec);
852 return NT_STATUS_OK;
855 struct smb2srv_session_close_previous_state {
856 struct tevent_context *ev;
857 struct smbXsrv_connection *connection;
858 struct dom_sid *current_sid;
859 uint64_t current_session_id;
860 struct db_record *db_rec;
863 static void smb2srv_session_close_previous_check(struct tevent_req *req);
864 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq);
866 struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
867 struct tevent_context *ev,
868 struct smbXsrv_connection *conn,
869 struct auth_session_info *session_info,
870 uint64_t previous_session_id,
871 uint64_t current_session_id)
873 struct tevent_req *req;
874 struct smb2srv_session_close_previous_state *state;
875 uint32_t global_id = previous_session_id & UINT32_MAX;
876 uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU;
877 struct smbXsrv_session_table *table = conn->session_table;
878 struct security_token *current_token = NULL;
879 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
880 TDB_DATA key;
882 req = tevent_req_create(mem_ctx, &state,
883 struct smb2srv_session_close_previous_state);
884 if (req == NULL) {
885 return NULL;
887 state->ev = ev;
888 state->connection = conn;
889 state->current_session_id = current_session_id;
891 if (global_zeros != 0) {
892 tevent_req_done(req);
893 return tevent_req_post(req, ev);
896 if (session_info == NULL) {
897 tevent_req_done(req);
898 return tevent_req_post(req, ev);
900 current_token = session_info->security_token;
902 if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
903 state->current_sid = &current_token->sids[PRIMARY_USER_SID_INDEX];
906 if (state->current_sid == NULL) {
907 tevent_req_done(req);
908 return tevent_req_post(req, ev);
911 if (!security_token_has_nt_authenticated_users(current_token)) {
912 /* TODO */
913 tevent_req_done(req);
914 return tevent_req_post(req, ev);
917 key = smbXsrv_session_global_id_to_key(global_id, key_buf);
919 state->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
920 state, key);
921 if (state->db_rec == NULL) {
922 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
923 return tevent_req_post(req, ev);
926 smb2srv_session_close_previous_check(req);
927 if (!tevent_req_is_in_progress(req)) {
928 return tevent_req_post(req, ev);
931 return req;
934 static void smb2srv_session_close_previous_check(struct tevent_req *req)
936 struct smb2srv_session_close_previous_state *state =
937 tevent_req_data(req,
938 struct smb2srv_session_close_previous_state);
939 struct smbXsrv_connection *conn = state->connection;
940 DATA_BLOB blob;
941 struct security_token *previous_token = NULL;
942 struct smbXsrv_session_global0 *global = NULL;
943 enum ndr_err_code ndr_err;
944 struct smbXsrv_session_close0 close_info0;
945 struct smbXsrv_session_closeB close_blob;
946 struct tevent_req *subreq = NULL;
947 NTSTATUS status;
948 bool is_free = false;
950 smbXsrv_session_global_verify_record(state->db_rec,
951 &is_free,
952 NULL,
953 state,
954 &global);
956 if (is_free) {
957 TALLOC_FREE(state->db_rec);
958 tevent_req_done(req);
959 return;
962 if (global->auth_session_info == NULL) {
963 TALLOC_FREE(state->db_rec);
964 tevent_req_done(req);
965 return;
968 previous_token = global->auth_session_info->security_token;
970 if (!security_token_is_sid(previous_token, state->current_sid)) {
971 TALLOC_FREE(state->db_rec);
972 tevent_req_done(req);
973 return;
976 subreq = dbwrap_record_watch_send(state, state->ev,
977 state->db_rec, conn->msg_ctx);
978 if (tevent_req_nomem(subreq, req)) {
979 TALLOC_FREE(state->db_rec);
980 return;
982 tevent_req_set_callback(subreq,
983 smb2srv_session_close_previous_modified,
984 req);
986 close_info0.old_session_global_id = global->session_global_id;
987 close_info0.old_session_wire_id = global->session_wire_id;
988 close_info0.old_creation_time = global->creation_time;
989 close_info0.new_session_wire_id = state->current_session_id;
991 ZERO_STRUCT(close_blob);
992 close_blob.version = smbXsrv_version_global_current();
993 close_blob.info.info0 = &close_info0;
995 ndr_err = ndr_push_struct_blob(&blob, state, &close_blob,
996 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_closeB);
997 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
998 TALLOC_FREE(state->db_rec);
999 status = ndr_map_error2ntstatus(ndr_err);
1000 DEBUG(1,("smb2srv_session_close_previous_check: "
1001 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1002 (unsigned long long)close_info0.old_session_wire_id,
1003 (unsigned long long)close_info0.new_session_wire_id,
1004 nt_errstr(status)));
1005 tevent_req_nterror(req, status);
1006 return;
1009 status = messaging_send(conn->msg_ctx,
1010 global->channels[0].server_id,
1011 MSG_SMBXSRV_SESSION_CLOSE, &blob);
1012 TALLOC_FREE(state->db_rec);
1013 if (tevent_req_nterror(req, status)) {
1014 return;
1017 TALLOC_FREE(global);
1018 return;
1021 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
1023 struct tevent_req *req =
1024 tevent_req_callback_data(subreq,
1025 struct tevent_req);
1026 struct smb2srv_session_close_previous_state *state =
1027 tevent_req_data(req,
1028 struct smb2srv_session_close_previous_state);
1029 NTSTATUS status;
1031 status = dbwrap_record_watch_recv(subreq, state, &state->db_rec);
1032 TALLOC_FREE(subreq);
1033 if (tevent_req_nterror(req, status)) {
1034 return;
1037 smb2srv_session_close_previous_check(req);
1040 NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req)
1042 NTSTATUS status;
1044 if (tevent_req_is_nterror(req, &status)) {
1045 tevent_req_received(req);
1046 return status;
1049 tevent_req_received(req);
1050 return NT_STATUS_OK;
1053 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
1055 NTSTATUS status;
1057 status = smbXsrv_session_logoff(session);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 DEBUG(0, ("smbXsrv_session_destructor: "
1060 "smbXsrv_session_logoff() failed: %s\n",
1061 nt_errstr(status)));
1064 TALLOC_FREE(session->global);
1066 return 0;
1069 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
1070 NTTIME now,
1071 struct smbXsrv_session **_session)
1073 struct smbXsrv_session_table *table = conn->session_table;
1074 struct db_record *local_rec = NULL;
1075 struct smbXsrv_session *session = NULL;
1076 void *ptr = NULL;
1077 TDB_DATA val;
1078 struct smbXsrv_session_global0 *global = NULL;
1079 struct smbXsrv_channel_global0 *channels = NULL;
1080 NTSTATUS status;
1082 if (table->local.num_sessions >= table->local.max_sessions) {
1083 return NT_STATUS_INSUFFICIENT_RESOURCES;
1086 session = talloc_zero(table, struct smbXsrv_session);
1087 if (session == NULL) {
1088 return NT_STATUS_NO_MEMORY;
1090 session->table = table;
1091 session->idle_time = now;
1092 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1093 session->connection = conn;
1095 status = smbXsrv_session_global_allocate(table->global.db_ctx,
1096 session,
1097 &global);
1098 if (!NT_STATUS_IS_OK(status)) {
1099 TALLOC_FREE(session);
1100 return status;
1102 session->global = global;
1104 if (conn->protocol >= PROTOCOL_SMB2_02) {
1105 uint64_t id = global->session_global_id;
1106 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
1107 TDB_DATA key;
1109 global->connection_dialect = conn->smb2.server.dialect;
1111 global->session_wire_id = id;
1113 status = smb2srv_tcon_table_init(session);
1114 if (!NT_STATUS_IS_OK(status)) {
1115 TALLOC_FREE(session);
1116 return status;
1119 session->local_id = global->session_global_id;
1121 key = smbXsrv_session_local_id_to_key(session->local_id, key_buf);
1123 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
1124 session, key);
1125 if (local_rec == NULL) {
1126 TALLOC_FREE(session);
1127 return NT_STATUS_NO_MEMORY;
1130 val = dbwrap_record_get_value(local_rec);
1131 if (val.dsize != 0) {
1132 TALLOC_FREE(session);
1133 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1135 } else {
1137 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
1138 table->local.lowest_id,
1139 table->local.highest_id,
1140 session,
1141 &local_rec,
1142 &session->local_id);
1143 if (!NT_STATUS_IS_OK(status)) {
1144 TALLOC_FREE(session);
1145 return status;
1148 global->session_wire_id = session->local_id;
1151 global->creation_time = now;
1152 global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
1154 global->num_channels = 1;
1155 channels = talloc_zero_array(global,
1156 struct smbXsrv_channel_global0,
1157 global->num_channels);
1158 if (channels == NULL) {
1159 TALLOC_FREE(session);
1160 return NT_STATUS_NO_MEMORY;
1162 global->channels = channels;
1164 channels[0].server_id = messaging_server_id(conn->msg_ctx);
1165 channels[0].local_address = tsocket_address_string(conn->local_address,
1166 channels);
1167 if (channels[0].local_address == NULL) {
1168 TALLOC_FREE(session);
1169 return NT_STATUS_NO_MEMORY;
1171 channels[0].remote_address = tsocket_address_string(conn->remote_address,
1172 channels);
1173 if (channels[0].remote_address == NULL) {
1174 TALLOC_FREE(session);
1175 return NT_STATUS_NO_MEMORY;
1177 channels[0].remote_name = talloc_strdup(channels, conn->remote_hostname);
1178 if (channels[0].remote_name == NULL) {
1179 TALLOC_FREE(session);
1180 return NT_STATUS_NO_MEMORY;
1182 channels[0].signing_key = data_blob_null;
1184 ptr = session;
1185 val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1186 status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1187 TALLOC_FREE(local_rec);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 TALLOC_FREE(session);
1190 return status;
1192 table->local.num_sessions += 1;
1194 talloc_set_destructor(session, smbXsrv_session_destructor);
1196 status = smbXsrv_session_global_store(global);
1197 if (!NT_STATUS_IS_OK(status)) {
1198 DEBUG(0,("smbXsrv_session_create: "
1199 "global_id (0x%08x) store failed - %s\n",
1200 session->global->session_global_id,
1201 nt_errstr(status)));
1202 TALLOC_FREE(session);
1203 return status;
1206 if (DEBUGLVL(10)) {
1207 struct smbXsrv_sessionB session_blob;
1209 ZERO_STRUCT(session_blob);
1210 session_blob.version = SMBXSRV_VERSION_0;
1211 session_blob.info.info0 = session;
1213 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1214 session->global->session_global_id));
1215 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1218 *_session = session;
1219 return NT_STATUS_OK;
1222 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
1224 struct smbXsrv_session_table *table = session->table;
1225 NTSTATUS status;
1226 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
1227 TDB_DATA key;
1229 if (session->global->db_rec != NULL) {
1230 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1231 "Called with db_rec != NULL'\n",
1232 session->global->session_global_id));
1233 return NT_STATUS_INTERNAL_ERROR;
1236 key = smbXsrv_session_global_id_to_key(
1237 session->global->session_global_id,
1238 key_buf);
1240 session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
1241 session->global, key);
1242 if (session->global->db_rec == NULL) {
1243 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1244 "Failed to lock global key '%s'\n",
1245 session->global->session_global_id,
1246 hex_encode_talloc(talloc_tos(), key.dptr,
1247 key.dsize)));
1248 return NT_STATUS_INTERNAL_DB_ERROR;
1251 status = smbXsrv_session_global_store(session->global);
1252 if (!NT_STATUS_IS_OK(status)) {
1253 DEBUG(0,("smbXsrv_session_update: "
1254 "global_id (0x%08x) store failed - %s\n",
1255 session->global->session_global_id,
1256 nt_errstr(status)));
1257 return status;
1260 if (DEBUGLVL(10)) {
1261 struct smbXsrv_sessionB session_blob;
1263 ZERO_STRUCT(session_blob);
1264 session_blob.version = SMBXSRV_VERSION_0;
1265 session_blob.info.info0 = session;
1267 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1268 session->global->session_global_id));
1269 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1272 return NT_STATUS_OK;
1275 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
1277 struct smbXsrv_session_table *table;
1278 struct db_record *local_rec = NULL;
1279 struct db_record *global_rec = NULL;
1280 struct smbXsrv_connection *conn;
1281 NTSTATUS status;
1282 NTSTATUS error = NT_STATUS_OK;
1284 if (session->table == NULL) {
1285 return NT_STATUS_OK;
1288 table = session->table;
1289 session->table = NULL;
1291 conn = session->connection;
1292 session->connection = NULL;
1293 session->status = NT_STATUS_USER_SESSION_DELETED;
1295 global_rec = session->global->db_rec;
1296 session->global->db_rec = NULL;
1297 if (global_rec == NULL) {
1298 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
1299 TDB_DATA key;
1301 key = smbXsrv_session_global_id_to_key(
1302 session->global->session_global_id,
1303 key_buf);
1305 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
1306 session->global, key);
1307 if (global_rec == NULL) {
1308 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1309 "Failed to lock global key '%s'\n",
1310 session->global->session_global_id,
1311 hex_encode_talloc(global_rec, key.dptr,
1312 key.dsize)));
1313 error = NT_STATUS_INTERNAL_ERROR;
1317 if (global_rec != NULL) {
1318 status = dbwrap_record_delete(global_rec);
1319 if (!NT_STATUS_IS_OK(status)) {
1320 TDB_DATA key = dbwrap_record_get_key(global_rec);
1322 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1323 "failed to delete global key '%s': %s\n",
1324 session->global->session_global_id,
1325 hex_encode_talloc(global_rec, key.dptr,
1326 key.dsize),
1327 nt_errstr(status)));
1328 error = status;
1331 TALLOC_FREE(global_rec);
1333 local_rec = session->db_rec;
1334 if (local_rec == NULL) {
1335 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
1336 TDB_DATA key;
1338 key = smbXsrv_session_local_id_to_key(session->local_id,
1339 key_buf);
1341 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
1342 session, key);
1343 if (local_rec == NULL) {
1344 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1345 "Failed to lock local key '%s'\n",
1346 session->global->session_global_id,
1347 hex_encode_talloc(local_rec, key.dptr,
1348 key.dsize)));
1349 error = NT_STATUS_INTERNAL_ERROR;
1353 if (local_rec != NULL) {
1354 status = dbwrap_record_delete(local_rec);
1355 if (!NT_STATUS_IS_OK(status)) {
1356 TDB_DATA key = dbwrap_record_get_key(local_rec);
1358 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1359 "failed to delete local key '%s': %s\n",
1360 session->global->session_global_id,
1361 hex_encode_talloc(local_rec, key.dptr,
1362 key.dsize),
1363 nt_errstr(status)));
1364 error = status;
1366 table->local.num_sessions -= 1;
1368 if (session->db_rec == NULL) {
1369 TALLOC_FREE(local_rec);
1371 session->db_rec = NULL;
1373 if (session->compat) {
1374 file_close_user(conn->sconn, session->compat->vuid);
1377 if (conn->protocol >= PROTOCOL_SMB2_02) {
1378 status = smb2srv_tcon_disconnect_all(session);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1381 "smb2srv_tcon_disconnect_all() failed: %s\n",
1382 session->global->session_global_id,
1383 nt_errstr(status)));
1384 error = status;
1388 if (session->compat) {
1389 invalidate_vuid(conn->sconn, session->compat->vuid);
1390 session->compat = NULL;
1393 return error;
1396 struct smbXsrv_session_logoff_all_state {
1397 NTSTATUS first_status;
1398 int errors;
1401 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1402 void *private_data);
1404 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_connection *conn)
1406 struct smbXsrv_session_table *table = conn->session_table;
1407 struct smbXsrv_session_logoff_all_state state;
1408 NTSTATUS status;
1409 int count = 0;
1411 if (table == NULL) {
1412 DEBUG(10, ("smbXsrv_session_logoff_all: "
1413 "empty session_table, nothing to do.\n"));
1414 return NT_STATUS_OK;
1417 ZERO_STRUCT(state);
1419 status = dbwrap_traverse(table->local.db_ctx,
1420 smbXsrv_session_logoff_all_callback,
1421 &state, &count);
1422 if (!NT_STATUS_IS_OK(status)) {
1423 DEBUG(0, ("smbXsrv_session_logoff_all: "
1424 "dbwrap_traverse() failed: %s\n",
1425 nt_errstr(status)));
1426 return status;
1429 if (!NT_STATUS_IS_OK(state.first_status)) {
1430 DEBUG(0, ("smbXsrv_session_logoff_all: "
1431 "count[%d] errors[%d] first[%s]\n",
1432 count, state.errors,
1433 nt_errstr(state.first_status)));
1434 return state.first_status;
1437 return NT_STATUS_OK;
1440 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1441 void *private_data)
1443 struct smbXsrv_session_logoff_all_state *state =
1444 (struct smbXsrv_session_logoff_all_state *)private_data;
1445 TDB_DATA val;
1446 void *ptr = NULL;
1447 struct smbXsrv_session *session = NULL;
1448 NTSTATUS status;
1450 val = dbwrap_record_get_value(local_rec);
1451 if (val.dsize != sizeof(ptr)) {
1452 status = NT_STATUS_INTERNAL_ERROR;
1453 if (NT_STATUS_IS_OK(state->first_status)) {
1454 state->first_status = status;
1456 state->errors++;
1457 return 0;
1460 memcpy(&ptr, val.dptr, val.dsize);
1461 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
1463 session->db_rec = local_rec;
1464 status = smbXsrv_session_logoff(session);
1465 if (!NT_STATUS_IS_OK(status)) {
1466 if (NT_STATUS_IS_OK(state->first_status)) {
1467 state->first_status = status;
1469 state->errors++;
1470 return 0;
1473 return 0;
1476 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
1479 * Allow a range from 1..65534 with 65534 values.
1481 return smbXsrv_session_table_init(conn, 1, UINT16_MAX - 1,
1482 UINT16_MAX - 1);
1485 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
1486 uint16_t vuid, NTTIME now,
1487 struct smbXsrv_session **session)
1489 struct smbXsrv_session_table *table = conn->session_table;
1490 uint32_t local_id = vuid;
1492 return smbXsrv_session_local_lookup(table, local_id, now, session);
1495 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
1498 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1500 return smbXsrv_session_table_init(conn, 1, UINT32_MAX - 1,
1501 UINT16_MAX - 1);
1504 NTSTATUS smb2srv_session_lookup(struct smbXsrv_connection *conn,
1505 uint64_t session_id, NTTIME now,
1506 struct smbXsrv_session **session)
1508 struct smbXsrv_session_table *table = conn->session_table;
1509 uint32_t local_id = session_id & UINT32_MAX;
1510 uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
1512 if (local_zeros != 0) {
1513 return NT_STATUS_USER_SESSION_DELETED;
1516 return smbXsrv_session_local_lookup(table, local_id, now, session);
1519 struct smbXsrv_session_global_traverse_state {
1520 int (*fn)(struct smbXsrv_session_global0 *, void *);
1521 void *private_data;
1524 static int smbXsrv_session_global_traverse_fn(struct db_record *rec, void *data)
1526 int ret = -1;
1527 struct smbXsrv_session_global_traverse_state *state =
1528 (struct smbXsrv_session_global_traverse_state*)data;
1529 TDB_DATA key = dbwrap_record_get_key(rec);
1530 TDB_DATA val = dbwrap_record_get_value(rec);
1531 DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
1532 struct smbXsrv_session_globalB global_blob;
1533 enum ndr_err_code ndr_err;
1534 TALLOC_CTX *frame = talloc_stackframe();
1536 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
1537 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
1538 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1539 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1540 "key '%s' ndr_pull_struct_blob - %s\n",
1541 hex_encode_talloc(frame, key.dptr, key.dsize),
1542 ndr_errstr(ndr_err)));
1543 goto done;
1546 if (global_blob.version != SMBXSRV_VERSION_0) {
1547 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1548 "key '%s' unsuported version - %d\n",
1549 hex_encode_talloc(frame, key.dptr, key.dsize),
1550 (int)global_blob.version));
1551 goto done;
1554 global_blob.info.info0->db_rec = rec;
1555 ret = state->fn(global_blob.info.info0, state->private_data);
1556 done:
1557 TALLOC_FREE(frame);
1558 return ret;
1561 NTSTATUS smbXsrv_session_global_traverse(
1562 int (*fn)(struct smbXsrv_session_global0 *, void *),
1563 void *private_data)
1566 NTSTATUS status;
1567 int count = 0;
1568 struct smbXsrv_session_global_traverse_state state = {
1569 .fn = fn,
1570 .private_data = private_data,
1573 become_root();
1574 status = smbXsrv_session_global_init();
1575 if (!NT_STATUS_IS_OK(status)) {
1576 unbecome_root();
1577 DEBUG(0, ("Failed to initialize session_global: %s\n",
1578 nt_errstr(status)));
1579 return status;
1582 status = dbwrap_traverse_read(smbXsrv_session_global_db_ctx,
1583 smbXsrv_session_global_traverse_fn,
1584 &state,
1585 &count);
1586 unbecome_root();
1588 return status;