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