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/>.
22 #include "system/filesys.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"
33 #include "../lib/tsocket/tsocket.h"
34 #include "../libcli/security/security.h"
36 #include "lib/util/util_tdb.h"
37 #include "librpc/gen_ndr/ndr_smbXsrv.h"
39 #include "lib/util/tevent_ntstatus.h"
40 #include "msg_channel.h"
42 struct smbXsrv_session_table {
44 struct db_context *db_ctx;
47 uint32_t num_sessions;
50 struct db_context *db_ctx;
52 struct msg_channel *close_channel;
55 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
57 NTSTATUS smbXsrv_session_global_init(void)
59 const char *global_path = NULL;
60 struct db_context *db_ctx = NULL;
62 if (smbXsrv_session_global_db_ctx != NULL) {
67 * This contains secret information like session keys!
69 global_path = lock_path("smbXsrv_session_global.tdb");
71 db_ctx = db_open(NULL, global_path,
75 TDB_INCOMPATIBLE_HASH,
76 O_RDWR | O_CREAT, 0600,
81 status = map_nt_error_from_unix_common(errno);
86 smbXsrv_session_global_db_ctx = db_ctx;
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
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,
107 RSIVAL(key_buf, 0, id);
109 key = make_tdb_data(key_buf, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE);
114 static NTSTATUS smbXsrv_session_global_key_to_id(TDB_DATA key, uint32_t *id)
117 return NT_STATUS_INVALID_PARAMETER;
120 if (key.dsize != SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE){
121 return NT_STATUS_INTERNAL_DB_CORRUPTION;
124 *id = RIVAL(key.dptr, 0);
129 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
131 static TDB_DATA smbXsrv_session_local_id_to_key(uint32_t id,
136 RSIVAL(key_buf, 0, id);
138 key = make_tdb_data(key_buf, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE);
143 static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
146 return NT_STATUS_INVALID_PARAMETER;
149 if (key.dsize != SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE){
150 return NT_STATUS_INTERNAL_DB_CORRUPTION;
153 *id = RIVAL(key.dptr, 0);
158 static void smbXsrv_session_close_loop(struct tevent_req *subreq);
160 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
164 struct smbXsrv_session_table *table;
166 struct tevent_req *subreq;
169 table = talloc_zero(conn, struct smbXsrv_session_table);
171 return NT_STATUS_NO_MEMORY;
174 table->local.db_ctx = db_open_rbt(conn);
175 if (table->local.db_ctx == NULL) {
177 return NT_STATUS_NO_MEMORY;
179 table->local.lowest_id = lowest_id;
180 table->local.highest_id = highest_id;
182 status = smbXsrv_session_global_init();
183 if (!NT_STATUS_IS_OK(status)) {
188 table->global.db_ctx = smbXsrv_session_global_db_ctx;
190 dbwrap_watch_db(table->global.db_ctx, conn->msg_ctx);
192 ret = msg_channel_init(table, conn->msg_ctx,
193 MSG_SMBXSRV_SESSION_CLOSE,
194 &table->close_channel);
196 status = map_nt_error_from_unix_common(errno);
201 subreq = msg_read_send(table, conn->ev_ctx, table->close_channel);
202 if (subreq == NULL) {
204 return NT_STATUS_NO_MEMORY;
206 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, conn);
208 conn->session_table = table;
212 static void smbXsrv_session_close_loop(struct tevent_req *subreq)
214 struct smbXsrv_connection *conn =
215 tevent_req_callback_data(subreq,
216 struct smbXsrv_connection);
217 struct smbXsrv_session_table *table = conn->session_table;
219 struct messaging_rec *rec = NULL;
220 struct smbXsrv_session_globalB global_blob;
221 enum ndr_err_code ndr_err;
222 struct smbXsrv_session_global0 *global = NULL;
223 struct smbXsrv_session *session = NULL;
225 struct timeval tv = timeval_current();
226 NTTIME now = timeval_to_nttime(&tv);
227 struct connection_struct *cur_conn, *next_conn;
229 ret = msg_read_recv(subreq, talloc_tos(), &rec);
235 ndr_err = ndr_pull_struct_blob_all(&rec->buf, rec, &global_blob,
236 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
237 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
241 DEBUG(0,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
242 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
244 if (global_blob.version != SMBXSRV_VERSION_0) {
248 global = global_blob.info.info0;
250 status = smb2srv_session_lookup(conn, global->session_wire_id,
252 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
255 if (!NT_STATUS_IS_OK(status) &&
256 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
257 !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
262 * TODO: cancel all outstanding requests on the session
264 file_close_user(conn->sconn, session->compat->vuid);
266 for (cur_conn=conn->sconn->connections; cur_conn; cur_conn=next_conn) {
267 struct smbXsrv_tcon *tcon;
269 next_conn = cur_conn->next;
270 tcon = cur_conn->tcon;
272 if (cur_conn->vuid != session->compat->vuid) {
276 set_current_service(cur_conn, 0, True);
277 close_cnum(cur_conn, cur_conn->vuid);
282 invalidate_vuid(conn->sconn, session->compat->vuid);
283 session->compat = NULL;
285 session->status = NT_STATUS_USER_SESSION_DELETED;
286 talloc_steal(rec, session);
291 subreq = msg_read_send(table, conn->ev_ctx, table->close_channel);
292 if (subreq == NULL) {
296 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, conn);
299 struct smb1srv_session_local_allocate_state {
300 const uint32_t lowest_id;
301 const uint32_t highest_id;
307 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
310 struct smb1srv_session_local_allocate_state *state =
311 (struct smb1srv_session_local_allocate_state *)private_data;
312 TDB_DATA key = dbwrap_record_get_key(rec);
316 status = smbXsrv_session_local_key_to_id(key, &id);
317 if (!NT_STATUS_IS_OK(status)) {
318 state->status = status;
322 if (id <= state->last_id) {
323 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
328 if (id > state->useable_id) {
329 state->status = NT_STATUS_OK;
333 state->useable_id +=1;
337 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
341 struct db_record **_rec,
344 struct smb1srv_session_local_allocate_state state = {
345 .lowest_id = lowest_id,
346 .highest_id = highest_id,
348 .useable_id = lowest_id,
349 .status = NT_STATUS_INTERNAL_ERROR,
359 if (lowest_id > highest_id) {
360 return NT_STATUS_INSUFFICIENT_RESOURCES;
363 range = (highest_id - lowest_id) + 1;
365 for (i = 0; i < range; i++) {
367 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
370 struct db_record *rec = NULL;
372 id = generate_random() % range;
375 if (id < lowest_id) {
378 if (id > highest_id) {
382 key = smbXsrv_session_local_id_to_key(id, key_buf);
384 rec = dbwrap_fetch_locked(db, mem_ctx, key);
386 return NT_STATUS_INSUFFICIENT_RESOURCES;
389 val = dbwrap_record_get_value(rec);
390 if (val.dsize != 0) {
400 status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
402 if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
404 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
406 * If we get anything else it is an error, because it
407 * means we did not manage to find a free slot in
410 return NT_STATUS_INSUFFICIENT_RESOURCES;
413 if (NT_STATUS_IS_OK(state.status)) {
415 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
418 struct db_record *rec = NULL;
420 id = state.useable_id;
422 key = smbXsrv_session_local_id_to_key(id, key_buf);
424 rec = dbwrap_fetch_locked(db, mem_ctx, key);
426 return NT_STATUS_INSUFFICIENT_RESOURCES;
429 val = dbwrap_record_get_value(rec);
430 if (val.dsize != 0) {
432 return NT_STATUS_INTERNAL_DB_CORRUPTION;
443 struct smbXsrv_session_local_fetch_state {
444 struct smbXsrv_session *session;
448 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
451 struct smbXsrv_session_local_fetch_state *state =
452 (struct smbXsrv_session_local_fetch_state *)private_data;
455 if (data.dsize != sizeof(ptr)) {
456 state->status = NT_STATUS_INTERNAL_DB_ERROR;
460 memcpy(&ptr, data.dptr, data.dsize);
461 state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
462 state->status = NT_STATUS_OK;
465 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
466 uint32_t session_local_id,
468 struct smbXsrv_session **_session)
470 struct smbXsrv_session_local_fetch_state state = {
472 .status = NT_STATUS_INTERNAL_ERROR,
474 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
480 if (session_local_id == 0) {
481 return NT_STATUS_USER_SESSION_DELETED;
485 /* this might happen before the end of negprot */
486 return NT_STATUS_USER_SESSION_DELETED;
489 if (table->local.db_ctx == NULL) {
490 return NT_STATUS_INTERNAL_ERROR;
493 key = smbXsrv_session_local_id_to_key(session_local_id, key_buf);
495 status = dbwrap_parse_record(table->local.db_ctx, key,
496 smbXsrv_session_local_fetch_parser,
498 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
499 return NT_STATUS_USER_SESSION_DELETED;
500 } else if (!NT_STATUS_IS_OK(status)) {
503 if (!NT_STATUS_IS_OK(state.status)) {
507 state.session->idle_time = now;
509 if (!NT_STATUS_IS_OK(state.session->status)) {
510 *_session = state.session;
511 return state.session->status;
514 if (now > state.session->global->expiration_time) {
515 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
518 *_session = state.session;
519 return state.session->status;
522 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
527 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
531 struct smbXsrv_session_global0 **_g);
533 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
535 struct smbXsrv_session_global0 **_global)
538 struct smbXsrv_session_global0 *global = NULL;
539 uint32_t last_free = 0;
540 const uint32_t min_tries = 3;
544 global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
545 if (global == NULL) {
546 return NT_STATUS_NO_MEMORY;
548 talloc_set_destructor(global, smbXsrv_session_global_destructor);
550 for (i = 0; i < UINT32_MAX; i++) {
551 bool is_free = false;
552 bool was_free = false;
554 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
557 if (i >= min_tries && last_free != 0) {
560 id = generate_random();
562 if (id >= UINT16_MAX) {
564 * For now we truncate to 16bit,
565 * as that's what all callers
566 * expect (uint16_t vuid).
568 id = id & UINT16_MAX;
573 if (id == UINT32_MAX) {
577 key = smbXsrv_session_global_id_to_key(id, key_buf);
579 global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
580 if (global->db_rec == NULL) {
582 return NT_STATUS_INSUFFICIENT_RESOURCES;
585 smbXsrv_session_global_verify_record(global->db_rec,
591 TALLOC_FREE(global->db_rec);
595 if (!was_free && i < min_tries) {
597 * The session_id is free now,
598 * but was not free before.
600 * This happens if a smbd crashed
601 * and did not cleanup the record.
603 * If this is one of our first tries,
604 * then we try to find a real free one.
606 if (last_free == 0) {
609 TALLOC_FREE(global->db_rec);
612 global->session_global_id = id;
618 /* should not be reached */
620 return NT_STATUS_INTERNAL_ERROR;
623 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
627 struct smbXsrv_session_global0 **_g)
632 struct smbXsrv_session_globalB global_blob;
633 enum ndr_err_code ndr_err;
634 struct smbXsrv_session_global0 *global = NULL;
636 TALLOC_CTX *frame = talloc_stackframe();
647 key = dbwrap_record_get_key(db_rec);
649 val = dbwrap_record_get_value(db_rec);
650 if (val.dsize == 0) {
659 blob = data_blob_const(val.dptr, val.dsize);
661 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
662 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
663 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
664 DEBUG(1,("smbXsrv_session_global_verify_record: "
665 "key '%s' use unsupported version %u\n",
666 hex_encode_talloc(frame, key.dptr, key.dsize),
667 global_blob.version));
672 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
674 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
677 if (global_blob.version != SMBXSRV_VERSION_0) {
678 DEBUG(0,("smbXsrv_session_global_verify_record: "
679 "key '%s' use unsupported version %u\n",
680 hex_encode_talloc(frame, key.dptr, key.dsize),
681 global_blob.version));
682 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
687 global = global_blob.info.info0;
689 exists = serverid_exists(&global->channels[0].server_id);
691 DEBUG(2,("smbXsrv_session_global_verify_record: "
692 "key '%s' server_id %s does not exist.\n",
693 hex_encode_talloc(frame, key.dptr, key.dsize),
694 server_id_str(frame, &global->channels[0].server_id)));
696 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
699 dbwrap_record_delete(db_rec);
705 *_g = talloc_move(mem_ctx, &global);
710 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_connection *sconn,
711 struct smbXsrv_session_global0 *global)
713 struct smbXsrv_session_globalB global_blob;
714 DATA_BLOB blob = data_blob_null;
718 enum ndr_err_code ndr_err;
721 * TODO: if we use other versions than '0'
722 * we would add glue code here, that would be able to
723 * store the information in the old format.
726 if (global->db_rec == NULL) {
727 return NT_STATUS_INTERNAL_ERROR;
730 key = dbwrap_record_get_key(global->db_rec);
731 val = dbwrap_record_get_value(global->db_rec);
733 ZERO_STRUCT(global_blob);
734 global_blob.version = smbXsrv_version_global_current();
735 if (val.dsize >= 8) {
736 global_blob.seqnum = IVAL(val.dptr, 4);
738 global_blob.seqnum += 1;
739 global_blob.info.info0 = global;
741 ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
742 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
743 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
744 status = ndr_map_error2ntstatus(ndr_err);
745 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
746 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
748 TALLOC_FREE(global->db_rec);
752 val = make_tdb_data(blob.data, blob.length);
753 status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
754 if (!NT_STATUS_IS_OK(status)) {
755 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
756 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
758 TALLOC_FREE(global->db_rec);
763 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
764 hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
765 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
768 TALLOC_FREE(global->db_rec);
773 struct smb2srv_session_close_previous_state {
774 struct tevent_context *ev;
775 struct smbXsrv_session *current_session;
776 struct dom_sid *current_sid;
777 struct db_record *db_rec;
780 static void smb2srv_session_close_previous_check(struct tevent_req *req);
781 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq);
783 struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
784 struct tevent_context *ev,
785 struct smbXsrv_session *current_session,
786 uint64_t previous_session_id)
788 struct tevent_req *req;
789 struct smb2srv_session_close_previous_state *state;
790 uint32_t global_id = previous_session_id & UINT32_MAX;
791 uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU;
792 struct smbXsrv_connection *conn = current_session->connection;
793 struct smbXsrv_session_table *table = conn->session_table;
794 struct security_token *current_token = NULL;
795 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
798 req = tevent_req_create(mem_ctx, &state,
799 struct smb2srv_session_close_previous_state);
804 state->current_session = current_session;
806 if (global_zeros != 0) {
807 tevent_req_done(req);
808 return tevent_req_post(req, ev);
811 if (current_session->global->auth_session_info == NULL) {
812 tevent_req_done(req);
813 return tevent_req_post(req, ev);
815 current_token = current_session->global->auth_session_info->security_token;
817 if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
818 state->current_sid = ¤t_token->sids[PRIMARY_USER_SID_INDEX];
821 if (state->current_sid == NULL) {
822 tevent_req_done(req);
823 return tevent_req_post(req, ev);
826 if (!security_token_has_nt_authenticated_users(current_token)) {
828 tevent_req_done(req);
829 return tevent_req_post(req, ev);
832 key = smbXsrv_session_global_id_to_key(global_id, key_buf);
834 state->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
836 if (state->db_rec == NULL) {
837 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
838 return tevent_req_post(req, ev);
841 smb2srv_session_close_previous_check(req);
842 if (!tevent_req_is_in_progress(req)) {
843 return tevent_req_post(req, ev);
849 static void smb2srv_session_close_previous_check(struct tevent_req *req)
851 struct smb2srv_session_close_previous_state *state =
853 struct smb2srv_session_close_previous_state);
854 struct smbXsrv_connection *conn = state->current_session->connection;
857 struct security_token *previous_token = NULL;
858 struct smbXsrv_session_global0 *global = NULL;
859 struct tevent_req *subreq = NULL;
861 bool is_free = false;
863 smbXsrv_session_global_verify_record(state->db_rec,
870 TALLOC_FREE(state->db_rec);
871 tevent_req_done(req);
875 if (global->auth_session_info == NULL) {
876 TALLOC_FREE(state->db_rec);
877 tevent_req_done(req);
881 previous_token = global->auth_session_info->security_token;
883 if (!security_token_is_sid(previous_token, state->current_sid)) {
884 TALLOC_FREE(state->db_rec);
885 tevent_req_done(req);
889 subreq = dbwrap_record_watch_send(state, state->ev,
890 state->db_rec, conn->msg_ctx);
891 if (tevent_req_nomem(subreq, req)) {
892 TALLOC_FREE(state->db_rec);
895 tevent_req_set_callback(subreq,
896 smb2srv_session_close_previous_modified,
899 val = dbwrap_record_get_value(state->db_rec);
900 blob = data_blob_const(val.dptr, val.dsize);
902 status = messaging_send(conn->msg_ctx,
903 global->channels[0].server_id,
904 MSG_SMBXSRV_SESSION_CLOSE, &blob);
905 TALLOC_FREE(state->db_rec);
906 if (tevent_req_nterror(req, status)) {
914 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
916 struct tevent_req *req =
917 tevent_req_callback_data(subreq,
919 struct smb2srv_session_close_previous_state *state =
921 struct smb2srv_session_close_previous_state);
924 status = dbwrap_record_watch_recv(subreq, state, &state->db_rec);
926 if (tevent_req_nterror(req, status)) {
930 smb2srv_session_close_previous_check(req);
933 NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req)
937 if (tevent_req_is_nterror(req, &status)) {
938 tevent_req_received(req);
942 tevent_req_received(req);
946 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
948 struct smbXsrv_session_table *table;
949 struct db_record *local_rec = NULL;
950 struct db_record *global_rec = NULL;
953 if (session->table == NULL) {
957 table = session->table;
958 session->table = NULL;
960 session->connection = NULL;
962 local_rec = session->db_rec;
963 session->db_rec = NULL;
964 if (local_rec == NULL) {
965 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
968 key = smbXsrv_session_local_id_to_key(session->local_id,
971 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
975 if (local_rec != NULL) {
976 status = dbwrap_record_delete(local_rec);
979 global_rec = session->global->db_rec;
980 session->global->db_rec = NULL;
981 if (global_rec == NULL) {
982 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
985 key = smbXsrv_session_global_id_to_key(
986 session->global->session_global_id,
989 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
990 session->global, key);
993 if (global_rec != NULL) {
994 status = dbwrap_record_delete(global_rec);
996 TALLOC_FREE(session->global);
1001 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
1003 struct smbXsrv_session **_session)
1005 struct smbXsrv_session_table *table = conn->session_table;
1006 uint32_t max_sessions = table->local.highest_id - table->local.lowest_id;
1007 struct db_record *local_rec = NULL;
1008 struct smbXsrv_session *session = NULL;
1011 struct smbXsrv_session_global0 *global = NULL;
1012 struct smbXsrv_channel_global0 *channels = NULL;
1015 if (table->local.num_sessions >= max_sessions) {
1016 return NT_STATUS_INSUFFICIENT_RESOURCES;
1019 session = talloc_zero(conn, struct smbXsrv_session);
1020 if (session == NULL) {
1021 return NT_STATUS_NO_MEMORY;
1023 session->table = table;
1024 session->idle_time = now;
1025 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1026 session->connection = conn;
1028 status = smbXsrv_session_global_allocate(table->global.db_ctx,
1031 if (!NT_STATUS_IS_OK(status)) {
1032 talloc_free(session);
1035 session->global = global;
1037 talloc_set_destructor(session, smbXsrv_session_destructor);
1039 if (conn->protocol >= PROTOCOL_SMB2_02) {
1040 uint16_t dialect = SMB2_DIALECT_REVISION_2FF;
1041 uint64_t id = global->session_global_id;
1042 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
1045 status = smb2srv_tcon_table_init(session);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 talloc_free(session);
1051 global->session_wire_id = id;
1053 switch (conn->protocol) {
1054 case PROTOCOL_SMB2_02:
1055 dialect = SMB2_DIALECT_REVISION_202;
1057 case PROTOCOL_SMB2_10:
1058 dialect = SMB2_DIALECT_REVISION_210;
1060 case PROTOCOL_SMB2_22:
1061 dialect = SMB2_DIALECT_REVISION_222;
1063 case PROTOCOL_SMB2_24:
1064 dialect = SMB2_DIALECT_REVISION_224;
1066 case PROTOCOL_SMB3_00:
1067 dialect = SMB3_DIALECT_REVISION_300;
1070 talloc_free(session);
1071 return NT_STATUS_INTERNAL_ERROR;
1073 global->connection_dialect = dialect;
1075 session->local_id = global->session_global_id;
1077 key = smbXsrv_session_local_id_to_key(session->local_id, key_buf);
1079 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
1081 if (local_rec == NULL) {
1082 return NT_STATUS_NO_MEMORY;
1085 val = dbwrap_record_get_value(local_rec);
1086 if (val.dsize != 0) {
1087 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1091 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
1092 table->local.lowest_id,
1093 table->local.highest_id,
1096 &session->local_id);
1097 if (!NT_STATUS_IS_OK(status)) {
1101 global->session_wire_id = session->local_id;
1105 val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1106 status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1107 TALLOC_FREE(local_rec);
1108 if (!NT_STATUS_IS_OK(status)) {
1109 talloc_free(session);
1113 global->creation_time = now;
1114 global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
1116 global->num_channels = 1;
1117 channels = talloc_zero_array(global,
1118 struct smbXsrv_channel_global0,
1119 global->num_channels);
1120 if (channels == NULL) {
1121 talloc_free(session);
1122 return NT_STATUS_NO_MEMORY;
1124 global->channels = channels;
1126 channels[0].server_id = messaging_server_id(conn->msg_ctx);
1127 channels[0].local_address = tsocket_address_string(conn->local_address,
1129 if (channels[0].local_address == NULL) {
1130 talloc_free(session);
1131 return NT_STATUS_NO_MEMORY;
1133 channels[0].remote_address = tsocket_address_string(conn->remote_address,
1135 if (channels[0].remote_address == NULL) {
1136 talloc_free(session);
1137 return NT_STATUS_NO_MEMORY;
1139 channels[0].remote_name = talloc_strdup(channels, conn->remote_hostname);
1140 if (channels[0].remote_name == NULL) {
1141 talloc_free(session);
1142 return NT_STATUS_NO_MEMORY;
1144 channels[0].signing_key = data_blob_null;
1146 status = smbXsrv_session_global_store(conn,
1148 if (!NT_STATUS_IS_OK(status)) {
1149 DEBUG(0,("smbXsrv_session_create: "
1150 "global_id 0x%08X store failed - %s\n",
1151 session->global->session_global_id,
1152 nt_errstr(status)));
1153 talloc_free(session);
1158 struct smbXsrv_sessionB session_blob;
1160 ZERO_STRUCT(session_blob);
1161 session_blob.version = SMBXSRV_VERSION_0;
1162 session_blob.info.info0 = session;
1164 DEBUG(10,("smbXsrv_session_create: global_id (0x%08X) stored\n",
1165 session->global->session_global_id));
1166 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1169 *_session = session;
1170 return NT_STATUS_OK;
1173 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
1175 struct smbXsrv_session_table *table = session->table;
1177 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
1180 if (session->global->db_rec != NULL) {
1181 return NT_STATUS_INTERNAL_ERROR;
1184 key = smbXsrv_session_global_id_to_key(
1185 session->global->session_global_id,
1188 session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
1189 session->global, key);
1190 if (session->global->db_rec == NULL) {
1191 return NT_STATUS_INTERNAL_DB_ERROR;
1194 status = smbXsrv_session_global_store(session->connection,
1196 if (!NT_STATUS_IS_OK(status)) {
1197 DEBUG(0,("smbXsrv_session_update: "
1198 "global_id 0x%08X store failed - %s\n",
1199 session->global->session_global_id,
1200 nt_errstr(status)));
1205 struct smbXsrv_sessionB session_blob;
1207 ZERO_STRUCT(session_blob);
1208 session_blob.version = SMBXSRV_VERSION_0;
1209 session_blob.info.info0 = session;
1211 DEBUG(10,("smbXsrv_session_update: global_id 0x%08X stored\n",
1212 session->global->session_global_id));
1213 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1216 return NT_STATUS_OK;
1219 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
1222 * Allow a range from 100..65534.
1224 return smbXsrv_session_table_init(conn, 100, UINT16_MAX - 1);
1227 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
1228 uint16_t vuid, NTTIME now,
1229 struct smbXsrv_session **session)
1231 struct smbXsrv_session_table *table = conn->session_table;
1232 uint32_t local_id = vuid;
1234 return smbXsrv_session_local_lookup(table, local_id, now, session);
1237 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
1240 * For now use the same range as SMB1.
1242 * Allow a range from 100..65534.
1244 return smbXsrv_session_table_init(conn, 100, UINT16_MAX - 1);
1247 NTSTATUS smb2srv_session_lookup(struct smbXsrv_connection *conn,
1248 uint64_t session_id, NTTIME now,
1249 struct smbXsrv_session **session)
1251 struct smbXsrv_session_table *table = conn->session_table;
1252 uint32_t local_id = session_id & UINT32_MAX;
1253 uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
1255 if (local_zeros != 0) {
1256 return NT_STATUS_USER_SESSION_DELETED;
1259 return smbXsrv_session_local_lookup(table, local_id, now, session);