39bfd5283d2376e23a7acacd8efc8bd6e8d1751c
[metze/samba/wip.git] / source3 / smbd / smbXsrv_session.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2011-2012
5    Copyright (C) Michael Adam 2012
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_rbt.h"
26 #include "dbwrap/dbwrap_open.h"
27 #include "session.h"
28 #include "auth.h"
29 #include "../lib/tsocket/tsocket.h"
30 #include "../libcli/security/security.h"
31 #include "messages.h"
32 #include "lib/util/util_tdb.h"
33 #include "librpc/gen_ndr/ndr_smbXsrv.h"
34
35 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
36
37 NTSTATUS smbXsrv_session_global_init(void)
38 {
39         const char *global_path = NULL;
40         struct db_context *db_ctx = NULL;
41
42         if (smbXsrv_session_global_db_ctx != NULL) {
43                 return NT_STATUS_OK;
44         }
45
46         /*
47          * This contains secret information like session keys!
48          */
49         global_path = lock_path("smbXsrv_session_global.tdb");
50
51         db_ctx = db_open(NULL, global_path,
52                          0, /* hash_size */
53                          TDB_DEFAULT |
54                          TDB_CLEAR_IF_FIRST |
55                          TDB_INCOMPATIBLE_HASH,
56                          O_RDWR | O_CREAT, 0600,
57                          DBWRAP_LOCK_ORDER_1);
58         if (db_ctx == NULL) {
59                 NTSTATUS status;
60
61                 status = map_nt_error_from_unix_common(errno);
62
63                 return status;
64         }
65
66         smbXsrv_session_global_db_ctx = db_ctx;
67
68         return NT_STATUS_OK;
69 }
70
71 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
72                                            uint32_t lowest_id,
73                                            uint32_t highest_id)
74 {
75         struct smbXsrv_session_table *table = &conn->session_table;
76         NTSTATUS status;
77
78         ZERO_STRUCTP(table);
79         table->local.db_ctx = db_open_rbt(conn);
80         if (table->local.db_ctx == NULL) {
81                 return NT_STATUS_NO_MEMORY;
82         }
83         table->local.lowest_id = lowest_id;
84         table->local.highest_id = highest_id;
85
86         status = smbXsrv_session_global_init();
87         if (!NT_STATUS_IS_OK(status)) {
88                 return status;
89         }
90
91         table->global.db_ctx = smbXsrv_session_global_db_ctx;
92
93         return NT_STATUS_OK;
94 }
95
96 struct smb1srv_session_local_allocate_state {
97         const uint32_t lowest_id;
98         const uint32_t highest_id;
99         uint32_t last_id;
100         uint32_t useable_id;
101         NTSTATUS status;
102 };
103
104 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
105                                                    void *private_data)
106 {
107         struct smb1srv_session_local_allocate_state *state =
108                 (struct smb1srv_session_local_allocate_state *)private_data;
109         TDB_DATA key = dbwrap_record_get_key(rec);
110         uint32_t id = 0;
111
112         if (key.dsize != sizeof(uint32_t)) {
113                 //TODO errno?
114                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
115                 return -1;
116         }
117
118         /*
119          * NOTE:
120          * We need big endian so that dbwrap_rbt's memcmp
121          * has the same result as integer comparison between the uint32_t
122          * values.
123          *
124          * TODO: implement string based key
125          */
126         id = RIVAL(key.dptr, 0);
127
128         if (id <= state->last_id) {
129                 //TODO errno?
130                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
131                 return -1;
132         }
133         state->last_id = id;
134
135         if (id > state->useable_id) {
136                 state->status = NT_STATUS_OK;
137                 return -1;
138         }
139
140         state->useable_id +=1;
141         return 0;
142 }
143
144 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
145                                                   uint32_t lowest_id,
146                                                   uint32_t highest_id,
147                                                   TALLOC_CTX *mem_ctx,
148                                                   struct db_record **_rec,
149                                                   uint32_t *_id)
150 {
151         struct smb1srv_session_local_allocate_state state = {
152                 .lowest_id = lowest_id,
153                 .highest_id = highest_id,
154                 .last_id = 0,
155                 .useable_id = lowest_id,
156                 .status = NT_STATUS_INTERNAL_ERROR,
157         };
158         uint32_t i;
159         uint32_t range;
160         NTSTATUS status;
161         int count = 0;
162
163         *_rec = NULL;
164         *_id = 0;
165
166         if (lowest_id > highest_id) {
167                 return NT_STATUS_INSUFFICIENT_RESOURCES;
168         }
169
170         range = (highest_id - lowest_id) + 1;
171
172         for (i = 0; i < range; i++) {
173                 uint32_t id;
174                 uint8_t key_buf[sizeof(uint32_t)];
175                 TDB_DATA key;
176                 TDB_DATA val;
177                 struct db_record *rec = NULL;
178
179                 id = generate_random() % range;
180                 id += lowest_id;
181
182                 if (id < lowest_id) {
183                         id = lowest_id;
184                 }
185                 if (id > highest_id) {
186                         id = highest_id;
187                 }
188
189                 RSIVAL(key_buf, 0, id);
190                 key = make_tdb_data(key_buf, sizeof(key_buf));
191
192                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
193                 if (rec == NULL) {
194                         return NT_STATUS_INSUFFICIENT_RESOURCES;
195                 }
196
197                 val = dbwrap_record_get_value(rec);
198                 if (val.dsize != 0) {
199                         TALLOC_FREE(rec);
200                         continue;
201                 }
202
203                 *_rec = rec;
204                 *_id = id;
205                 return NT_STATUS_OK;
206         }
207
208         status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
209                                       &state, &count);
210         if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
211                 /*
212                  * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
213                  *
214                  * If we get anything else it is an error, because it
215                  * means we did not manage to find a free slot in
216                  * the db.
217                  */
218                 return NT_STATUS_INSUFFICIENT_RESOURCES;
219         }
220
221         if (NT_STATUS_IS_OK(state.status)) {
222                 uint32_t id;
223                 uint8_t key_buf[sizeof(uint32_t)];
224                 TDB_DATA key;
225                 TDB_DATA val;
226                 struct db_record *rec = NULL;
227
228                 id = state.useable_id;
229
230                 RSIVAL(key_buf, 0, id);
231                 key = make_tdb_data(key_buf, sizeof(key_buf));
232
233                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
234                 if (rec == NULL) {
235                         return NT_STATUS_INSUFFICIENT_RESOURCES;
236                 }
237
238                 val = dbwrap_record_get_value(rec);
239                 if (val.dsize != 0) {
240                         TALLOC_FREE(rec);
241                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
242                 }
243
244                 *_rec = rec;
245                 *_id = id;
246                 return NT_STATUS_OK;
247         }
248
249         return state.status;
250 }
251
252 struct smbXsrv_session_local_fetch_state {
253         struct smbXsrv_session *session;
254         NTSTATUS status;
255 };
256
257 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
258                                                void *private_data)
259 {
260         struct smbXsrv_session_local_fetch_state *state =
261                 (struct smbXsrv_session_local_fetch_state *)private_data;
262         void *ptr;
263
264         if (data.dsize != sizeof(ptr)) {
265                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
266                 return;
267         }
268
269         memcpy(&ptr, data.dptr, data.dsize);
270         state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
271         state->status = NT_STATUS_OK;
272 }
273
274 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
275                                              uint32_t session_local_id,
276                                              NTTIME now,
277                                              struct smbXsrv_session **_session)
278 {
279         struct smbXsrv_session_local_fetch_state state = {
280                 .session = NULL,
281                 .status = NT_STATUS_INTERNAL_ERROR,
282         };
283         uint8_t key_buf[sizeof(uint32_t)];
284         TDB_DATA key;
285         NTSTATUS status;
286
287         *_session = NULL;
288
289         if (table->local.db_ctx == NULL) {
290                 return NT_STATUS_INTERNAL_ERROR;
291         }
292
293         RSIVAL(key_buf, 0, session_local_id);
294         key = make_tdb_data(key_buf, sizeof(key_buf));
295
296         status = dbwrap_parse_record(table->local.db_ctx, key,
297                                      smbXsrv_session_local_fetch_parser,
298                                      &state);
299         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
300                 return NT_STATUS_USER_SESSION_DELETED;
301         } else if (!NT_STATUS_IS_OK(status)) {
302                 return status;
303         }
304         if (!NT_STATUS_IS_OK(state.status)) {
305                 return state.status;
306         }
307
308         if (!NT_STATUS_IS_OK(state.session->status)) {
309                 *_session = state.session;
310                 return state.session->status;
311         }
312
313         if (now > state.session->global->expiration_time) {
314                 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
315         }
316
317         *_session = state.session;
318         return state.session->status;
319 }
320
321 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
322 {
323         return 0;
324 }
325
326 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
327                                         TALLOC_CTX *mem_ctx,
328                                         struct smbXsrv_session_global0 **_global)
329 {
330         uint32_t i;
331         struct smbXsrv_session_global0 *global = NULL;
332
333         *_global = NULL;
334
335         global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
336         if (global == NULL) {
337                 return NT_STATUS_NO_MEMORY;
338         }
339         talloc_set_destructor(global, smbXsrv_session_global_destructor);
340
341         for (i = 0; i < UINT32_MAX; i++) {
342                 uint32_t id;
343                 uint8_t key_buf[sizeof(uint32_t)];
344                 TDB_DATA key;
345                 TDB_DATA val;
346
347                 id = generate_random();
348                 if (id >= UINT16_MAX) {
349                         id = id & UINT16_MAX;
350                 }
351                 if (id == 0) {
352                         id++;
353                 }
354                 if (id == UINT32_MAX) {
355                         id--;
356                 }
357
358                 RSIVAL(key_buf, 0, id);
359                 key = make_tdb_data(key_buf, sizeof(key_buf));
360
361                 global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
362                 if (global->db_rec == NULL) {
363                         talloc_free(global);
364                         return NT_STATUS_INSUFFICIENT_RESOURCES;
365                 }
366
367                 val = dbwrap_record_get_value(global->db_rec);
368                 if (val.dsize != 0) {
369                         TALLOC_FREE(global->db_rec);
370                         continue;
371                 }
372
373                 global->session_global_id = id;
374
375                 *_global = global;
376                 return NT_STATUS_OK;
377         }
378
379         /* should not be reached */
380         talloc_free(global);
381         return NT_STATUS_INTERNAL_ERROR;
382 }
383
384 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_connection *sconn,
385                                              struct smbXsrv_session_global0 *global)
386 {
387         struct smbXsrv_session_globalB global_blob;
388         DATA_BLOB blob = data_blob_null;
389         TDB_DATA val;
390         NTSTATUS status;
391         enum ndr_err_code ndr_err;
392
393         /*
394          * TODO: if we use other versions than '0'
395          * we would add glue code here, that would be able to
396          * store the information in the old format.
397          */
398
399         if (global->db_rec == NULL) {
400                 return NT_STATUS_INTERNAL_ERROR;
401         }
402
403         val = dbwrap_record_get_value(global->db_rec);
404
405         ZERO_STRUCT(global_blob);
406         global_blob.version = 0;
407         if (val.dsize >= 8) {
408                 global_blob.seqnum = IVAL(val.dptr, 4);
409         }
410         global_blob.seqnum += 1;
411         global_blob.info.info0 = global;
412
413         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
414                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
415         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
416                 //status = ndr_err_code;
417                 TALLOC_FREE(global->db_rec);
418                 return status;
419         }
420
421         val = make_tdb_data(blob.data, blob.length);
422         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
423         TALLOC_FREE(global->db_rec);
424         if (!NT_STATUS_IS_OK(status)) {
425                 return status;
426         }
427
428         return NT_STATUS_OK;
429 }
430
431 struct smbXsrv_session_global_fetch_state {
432         TALLOC_CTX *mem_ctx;
433         struct smbXsrv_session_global *session;
434         NTSTATUS status;
435 };
436
437 static void smbXsrv_session_global_fetch_parser(TDB_DATA key, TDB_DATA data,
438                                                void *private_data)
439 {
440         struct smbXsrv_session_global_fetch_state *state =
441                 (struct smbXsrv_session_global_fetch_state *)private_data;
442
443         state->status = NT_STATUS_NOT_IMPLEMENTED;
444 }
445
446 static NTSTATUS smbXsrv_session_global_lookup(struct smbXsrv_session_table *table,
447                                               uint32_t session_global_id,
448                                               TALLOC_CTX *mem_ctx,
449                                               struct smbXsrv_session_global **_session)
450 {
451         struct smbXsrv_session_global_fetch_state state = {
452                 .mem_ctx = mem_ctx,
453                 .session = NULL,
454                 .status = NT_STATUS_INTERNAL_ERROR,
455         };
456         TDB_DATA key;
457         uint8_t key_buf[sizeof(uint32_t)];
458         NTSTATUS status;
459
460         *_session = NULL;
461
462         if (table->global.db_ctx == NULL) {
463                 return NT_STATUS_INTERNAL_ERROR;
464         }
465
466         /* TODO: key as string */
467         RSIVAL(key_buf, 0, session_global_id);
468         key = make_tdb_data(key_buf, sizeof(key_buf));
469
470         status = dbwrap_parse_record(table->global.db_ctx, key,
471                                      smbXsrv_session_global_fetch_parser, &state);
472         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
473                 return NT_STATUS_USER_SESSION_DELETED;
474         } else if (!NT_STATUS_IS_OK(status)) {
475                 return status;
476         }
477         if (!NT_STATUS_IS_OK(state.status)) {
478                 return state.status;
479         }
480
481         *_session = state.session;
482         return NT_STATUS_OK;
483 }
484
485 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
486 {
487         struct smbXsrv_session_table *table;
488         struct db_record *local_rec = NULL;
489         struct db_record *global_rec = NULL;
490         NTSTATUS status;
491
492         if (session->connection == NULL) {
493                 return 0;
494         }
495
496         table = &session->connection->session_table;
497         session->connection = NULL;
498
499         local_rec = session->db_rec;
500         session->db_rec = NULL;
501         if (local_rec == NULL) {
502                 uint8_t key_buf[sizeof(uint32_t)];
503                 TDB_DATA key;
504
505                 RSIVAL(key_buf, 0, session->local_id);
506                 key = make_tdb_data(key_buf, sizeof(key_buf));
507
508                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
509                                                 session, key);
510         }
511
512         if (local_rec != NULL) {
513                 status = dbwrap_record_delete(local_rec);
514         }
515
516         global_rec = session->global->db_rec;
517         session->global->db_rec = NULL;
518         if (global_rec == NULL) {
519                 uint8_t key_buf[sizeof(uint32_t)];
520                 TDB_DATA key;
521
522                 RSIVAL(key_buf, 0, session->global->session_global_id);
523                 key = make_tdb_data(key_buf, sizeof(key_buf));
524
525                 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
526                                                  session->global, key);
527         }
528
529         if (global_rec != NULL) {
530                 status = dbwrap_record_delete(global_rec);
531         }
532         TALLOC_FREE(session->global);
533
534         return 0;
535 }
536
537 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
538                                 NTTIME now,
539                                 struct smbXsrv_session **_session)
540 {
541         struct smbXsrv_session_table *table = &conn->session_table;
542         uint32_t max_sessions = table->local.highest_id - table->local.lowest_id;
543         struct db_record *local_rec = NULL;
544         struct smbXsrv_session *session = NULL;
545         void *ptr = NULL;
546         TDB_DATA val;
547         struct smbXsrv_session_global0 *global = NULL;
548         struct smbXsrv_channel_global0 *channels = NULL;
549         NTSTATUS status;
550
551         //system("sleep 999999");
552
553         if (table->local.num_sessions >= max_sessions) {
554                 return NT_STATUS_INSUFFICIENT_RESOURCES;
555                 // TODO smb1 return NT_STATUS_TOO_MANY_SESSIONS;
556         }
557
558         session = talloc_zero(conn, struct smbXsrv_session);
559         if (session == NULL) {
560                 return NT_STATUS_NO_MEMORY;
561         }
562         session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
563         session->connection = conn;
564
565         status = smbXsrv_session_global_allocate(table->global.db_ctx,
566                                                  session,
567                                                  &global);
568         if (!NT_STATUS_IS_OK(status)) {
569                 talloc_free(session);
570                 return status;
571         }
572         session->global = global;
573
574         talloc_set_destructor(session, smbXsrv_session_destructor);
575
576         if (conn->protocol >= PROTOCOL_SMB2_02) {
577                 uint64_t id = global->session_global_id;
578                 uint8_t key_buf[sizeof(uint32_t)];
579                 TDB_DATA key;
580
581                 global->session_wire_id = id;
582                 //global->session_wire_id |= (id << 32) & 0xFFFFFFFF00000000ULL;
583
584                 session->local_id = global->session_global_id;
585
586                 RSIVAL(key_buf, 0, session->local_id);
587                 key = make_tdb_data(key_buf, sizeof(key_buf));
588
589                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
590                                                 session, key);
591                 if (local_rec == NULL) {
592                         return NT_STATUS_NO_MEMORY;
593                 }
594
595                 val = dbwrap_record_get_value(local_rec);
596                 if (val.dsize != 0) {
597                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
598                 }
599         } else {
600
601                 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
602                                                         table->local.lowest_id,
603                                                         table->local.highest_id,
604                                                         session,
605                                                         &local_rec,
606                                                         &session->local_id);
607                 if (!NT_STATUS_IS_OK(status)) {
608                         return status;
609                 }
610
611                 global->session_wire_id = session->local_id;
612         }
613
614         ptr = session;
615         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
616         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
617         TALLOC_FREE(local_rec);
618         if (!NT_STATUS_IS_OK(status)) {
619                 talloc_free(session);
620                 return status;
621         }
622
623         global->creation_time = now;
624         global->expiration_time = UINT64_MAX;//NTTIME_INFINITY;
625
626         global->num_channels = 1;
627         channels = talloc_zero_array(global,
628                                      struct smbXsrv_channel_global0,
629                                      global->num_channels);
630         if (channels == NULL) {
631                 talloc_free(session);
632                 return NT_STATUS_NO_MEMORY;
633         }
634         global->channels = channels;
635
636         channels[0].server_id = messaging_server_id(conn->msg_ctx);
637         channels[0].local_address = tsocket_address_string(conn->local_address,
638                                                            channels);
639         if (channels[0].local_address == NULL) {
640                 talloc_free(session);
641                 return NT_STATUS_NO_MEMORY;
642         }
643         channels[0].remote_address = tsocket_address_string(conn->remote_address,
644                                                             channels);
645         if (channels[0].remote_address == NULL) {
646                 talloc_free(session);
647                 return NT_STATUS_NO_MEMORY;
648         }
649         channels[0].remote_name = talloc_strdup(channels, conn->remote_hostname);
650         if (channels[0].remote_name == NULL) {
651                 talloc_free(session);
652                 return NT_STATUS_NO_MEMORY;
653         }
654         channels[0].signing_key = data_blob_null;
655
656         status = smbXsrv_session_global_store(conn,
657                                               global);
658         if (!NT_STATUS_IS_OK(status)) {
659                 talloc_free(session);
660                 return status;
661         }
662
663         {
664                 struct smbXsrv_sessionB session_blob;
665
666                 ZERO_STRUCT(session_blob);
667                 session_blob.version = 0;
668                 session_blob.info.info0 = session;
669
670                 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
671         }
672
673         *_session = session;
674         return NT_STATUS_OK;
675 }
676
677 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
678 {
679         struct smbXsrv_session_table *table = &session->connection->session_table;
680         NTSTATUS status;
681         uint8_t key_buf[sizeof(uint32_t)];
682         TDB_DATA key;
683
684         if (session->global->db_rec != NULL) {
685                 return NT_STATUS_INTERNAL_ERROR;
686         }
687
688         RSIVAL(key_buf, 0, session->global->session_global_id);
689         key = make_tdb_data(key_buf, sizeof(key_buf));
690
691         session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
692                                                       session->global, key);
693         if (session->global->db_rec == NULL) {
694                 // TODO proper return code?
695                 return NT_STATUS_NO_MEMORY;
696         }
697
698         status = smbXsrv_session_global_store(session->connection,
699                                               session->global);
700         if (!NT_STATUS_IS_OK(status)) {
701                 /* debug */
702                 return status;
703         }
704
705         return NT_STATUS_OK;
706 }
707
708 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
709 {
710         /*
711          * Allow a range from 100..65534.
712          */
713         return smbXsrv_session_table_init(conn, 100, UINT16_MAX - 1);
714 }
715
716 NTSTATUS smb1srv_session_lookup(struct smbXsrv_session_table *table,
717                                 uint16_t vuid, NTTIME now,
718                                 struct smbXsrv_session **session)
719 {
720         uint32_t local_id = vuid;
721
722         return smbXsrv_session_local_lookup(table, local_id, now, session);
723 }
724
725 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
726 {
727         /*
728          * For now use the same range as SMB1.
729          *
730          * Allow a range from 100..65534.
731          */
732         return smbXsrv_session_table_init(conn, 100, UINT16_MAX - 1);
733 }
734
735 NTSTATUS smb2srv_session_lookup(struct smbXsrv_session_table *table,
736                                 uint64_t session_id, NTTIME now,
737                                 struct smbXsrv_session **session)
738 {
739         uint32_t local_id = session_id & UINT32_MAX;
740
741         return smbXsrv_session_local_lookup(table, local_id, now, session);
742 }
743