Revert "IGNORE add smbXsrv_session_global_lookup""
[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 "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_rbt.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "session.h"
29 #include "auth.h"
30 #include "gensec.h"
31 #include "../lib/tsocket/tsocket.h"
32 #include "../libcli/security/security.h"
33 #include "messages.h"
34 #include "lib/util/util_tdb.h"
35 #include "librpc/gen_ndr/ndr_smbXsrv.h"
36 #include "serverid.h"
37
38 struct smbXsrv_session_table {
39         struct {
40                 struct db_context *db_ctx;
41                 uint32_t lowest_id;
42                 uint32_t highest_id;
43                 uint32_t num_sessions;
44         } local;
45         struct {
46                 struct db_context *db_ctx;
47         } global;
48 };
49
50 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
51
52 NTSTATUS smbXsrv_session_global_init(void)
53 {
54         const char *global_path = NULL;
55         struct db_context *db_ctx = NULL;
56
57         if (smbXsrv_session_global_db_ctx != NULL) {
58                 return NT_STATUS_OK;
59         }
60
61         /*
62          * This contains secret information like session keys!
63          */
64         global_path = lock_path("smbXsrv_session_global.tdb");
65
66         db_ctx = db_open(NULL, global_path,
67                          0, /* hash_size */
68                          TDB_DEFAULT |
69                          TDB_CLEAR_IF_FIRST |
70                          TDB_INCOMPATIBLE_HASH,
71                          O_RDWR | O_CREAT, 0600,
72                          DBWRAP_LOCK_ORDER_1);
73         if (db_ctx == NULL) {
74                 NTSTATUS status;
75
76                 status = map_nt_error_from_unix_common(errno);
77
78                 return status;
79         }
80
81         smbXsrv_session_global_db_ctx = db_ctx;
82
83         return NT_STATUS_OK;
84 }
85
86 /*
87  * NOTE:
88  * We need to store the keys in big endian so that dbwrap_rbt's memcmp
89  * has the same result as integer comparison between the uint32_t
90  * values.
91  *
92  * TODO: implement string based key
93  */
94
95 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
96
97 static TDB_DATA smbXsrv_session_global_id_to_key(uint32_t id,
98                                                  uint8_t *key_buf)
99 {
100         TDB_DATA key;
101
102         RSIVAL(key_buf, 0, id);
103
104         key = make_tdb_data(key_buf, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE);
105
106         return key;
107 }
108
109 static NTSTATUS smbXsrv_session_global_key_to_id(TDB_DATA key, uint32_t *id)
110 {
111         if (id == NULL) {
112                 return NT_STATUS_INVALID_PARAMETER;
113         }
114
115         if (key.dsize != SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE){
116                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
117         }
118
119         *id = RIVAL(key.dptr, 0);
120
121         return NT_STATUS_OK;
122 }
123
124 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
125
126 static TDB_DATA smbXsrv_session_local_id_to_key(uint32_t id,
127                                                 uint8_t *key_buf)
128 {
129         TDB_DATA key;
130
131         RSIVAL(key_buf, 0, id);
132
133         key = make_tdb_data(key_buf, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE);
134
135         return key;
136 }
137
138 static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
139 {
140         if (id == NULL) {
141                 return NT_STATUS_INVALID_PARAMETER;
142         }
143
144         if (key.dsize != SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE){
145                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
146         }
147
148         *id = RIVAL(key.dptr, 0);
149
150         return NT_STATUS_OK;
151 }
152
153 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
154                                            uint32_t lowest_id,
155                                            uint32_t highest_id)
156 {
157         struct smbXsrv_session_table *table;
158         NTSTATUS status;
159
160         table = talloc_zero(conn, struct smbXsrv_session_table);
161         if (table == NULL) {
162                 return NT_STATUS_NO_MEMORY;
163         }
164
165         table->local.db_ctx = db_open_rbt(conn);
166         if (table->local.db_ctx == NULL) {
167                 TALLOC_FREE(table);
168                 return NT_STATUS_NO_MEMORY;
169         }
170         table->local.lowest_id = lowest_id;
171         table->local.highest_id = highest_id;
172
173         status = smbXsrv_session_global_init();
174         if (!NT_STATUS_IS_OK(status)) {
175                 TALLOC_FREE(table);
176                 return status;
177         }
178
179         table->global.db_ctx = smbXsrv_session_global_db_ctx;
180
181         conn->session_table = table;
182         return NT_STATUS_OK;
183 }
184
185 struct smb1srv_session_local_allocate_state {
186         const uint32_t lowest_id;
187         const uint32_t highest_id;
188         uint32_t last_id;
189         uint32_t useable_id;
190         NTSTATUS status;
191 };
192
193 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
194                                                    void *private_data)
195 {
196         struct smb1srv_session_local_allocate_state *state =
197                 (struct smb1srv_session_local_allocate_state *)private_data;
198         TDB_DATA key = dbwrap_record_get_key(rec);
199         uint32_t id = 0;
200         NTSTATUS status;
201
202         status = smbXsrv_session_local_key_to_id(key, &id);
203         if (!NT_STATUS_IS_OK(status)) {
204                 // TODO errno?
205                 state->status = status;
206                 return -1;
207         }
208
209         if (id <= state->last_id) {
210                 //TODO errno?
211                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
212                 return -1;
213         }
214         state->last_id = id;
215
216         if (id > state->useable_id) {
217                 state->status = NT_STATUS_OK;
218                 return -1;
219         }
220
221         state->useable_id +=1;
222         return 0;
223 }
224
225 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
226                                                   uint32_t lowest_id,
227                                                   uint32_t highest_id,
228                                                   TALLOC_CTX *mem_ctx,
229                                                   struct db_record **_rec,
230                                                   uint32_t *_id)
231 {
232         struct smb1srv_session_local_allocate_state state = {
233                 .lowest_id = lowest_id,
234                 .highest_id = highest_id,
235                 .last_id = 0,
236                 .useable_id = lowest_id,
237                 .status = NT_STATUS_INTERNAL_ERROR,
238         };
239         uint32_t i;
240         uint32_t range;
241         NTSTATUS status;
242         int count = 0;
243
244         *_rec = NULL;
245         *_id = 0;
246
247         if (lowest_id > highest_id) {
248                 return NT_STATUS_INSUFFICIENT_RESOURCES;
249         }
250
251         range = (highest_id - lowest_id) + 1;
252
253         for (i = 0; i < range; i++) {
254                 uint32_t id;
255                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
256                 TDB_DATA key;
257                 TDB_DATA val;
258                 struct db_record *rec = NULL;
259
260                 id = generate_random() % range;
261                 id += lowest_id;
262
263                 if (id < lowest_id) {
264                         id = lowest_id;
265                 }
266                 if (id > highest_id) {
267                         id = highest_id;
268                 }
269
270                 key = smbXsrv_session_local_id_to_key(id, key_buf);
271
272                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
273                 if (rec == NULL) {
274                         return NT_STATUS_INSUFFICIENT_RESOURCES;
275                 }
276
277                 val = dbwrap_record_get_value(rec);
278                 if (val.dsize != 0) {
279                         TALLOC_FREE(rec);
280                         continue;
281                 }
282
283                 *_rec = rec;
284                 *_id = id;
285                 return NT_STATUS_OK;
286         }
287
288         status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
289                                       &state, &count);
290         if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
291                 /*
292                  * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
293                  *
294                  * If we get anything else it is an error, because it
295                  * means we did not manage to find a free slot in
296                  * the db.
297                  */
298                 return NT_STATUS_INSUFFICIENT_RESOURCES;
299         }
300
301         if (NT_STATUS_IS_OK(state.status)) {
302                 uint32_t id;
303                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
304                 TDB_DATA key;
305                 TDB_DATA val;
306                 struct db_record *rec = NULL;
307
308                 id = state.useable_id;
309
310                 key = smbXsrv_session_local_id_to_key(id, key_buf);
311
312                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
313                 if (rec == NULL) {
314                         return NT_STATUS_INSUFFICIENT_RESOURCES;
315                 }
316
317                 val = dbwrap_record_get_value(rec);
318                 if (val.dsize != 0) {
319                         TALLOC_FREE(rec);
320                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
321                 }
322
323                 *_rec = rec;
324                 *_id = id;
325                 return NT_STATUS_OK;
326         }
327
328         return state.status;
329 }
330
331 struct smbXsrv_session_local_fetch_state {
332         struct smbXsrv_session *session;
333         NTSTATUS status;
334 };
335
336 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
337                                                void *private_data)
338 {
339         struct smbXsrv_session_local_fetch_state *state =
340                 (struct smbXsrv_session_local_fetch_state *)private_data;
341         void *ptr;
342
343         if (data.dsize != sizeof(ptr)) {
344                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
345                 return;
346         }
347
348         memcpy(&ptr, data.dptr, data.dsize);
349         state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
350         state->status = NT_STATUS_OK;
351 }
352
353 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
354                                              uint32_t session_local_id,
355                                              NTTIME now,
356                                              struct smbXsrv_session **_session)
357 {
358         struct smbXsrv_session_local_fetch_state state = {
359                 .session = NULL,
360                 .status = NT_STATUS_INTERNAL_ERROR,
361         };
362         uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
363         TDB_DATA key;
364         NTSTATUS status;
365
366         *_session = NULL;
367
368         if (session_local_id == 0) {
369                 return NT_STATUS_USER_SESSION_DELETED;
370         }
371
372         if (table == NULL) {
373                 /* this might happen before the end of negprot */
374                 return NT_STATUS_USER_SESSION_DELETED;
375         }
376
377         if (table->local.db_ctx == NULL) {
378                 return NT_STATUS_INTERNAL_ERROR;
379         }
380
381         key = smbXsrv_session_local_id_to_key(session_local_id, key_buf);
382
383         status = dbwrap_parse_record(table->local.db_ctx, key,
384                                      smbXsrv_session_local_fetch_parser,
385                                      &state);
386         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
387                 return NT_STATUS_USER_SESSION_DELETED;
388         } else if (!NT_STATUS_IS_OK(status)) {
389                 return status;
390         }
391         if (!NT_STATUS_IS_OK(state.status)) {
392                 return state.status;
393         }
394
395         state.session->idle_time = now;
396
397         if (!NT_STATUS_IS_OK(state.session->status)) {
398                 *_session = state.session;
399                 return state.session->status;
400         }
401
402         if (now > state.session->global->expiration_time) {
403                 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
404         }
405
406         *_session = state.session;
407         return state.session->status;
408 }
409
410 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
411 {
412         return 0;
413 }
414
415 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
416                                         bool *is_free,
417                                         bool *was_free,
418                                         TALLOC_CTX *mem_ctx,
419                                         struct smbXsrv_session_global0 **_g);
420
421 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
422                                         TALLOC_CTX *mem_ctx,
423                                         struct smbXsrv_session_global0 **_global)
424 {
425         uint32_t i;
426         struct smbXsrv_session_global0 *global = NULL;
427         uint32_t last_free = 0;
428         const uint32_t min_tries = 3;
429
430         *_global = NULL;
431
432         global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
433         if (global == NULL) {
434                 return NT_STATUS_NO_MEMORY;
435         }
436         talloc_set_destructor(global, smbXsrv_session_global_destructor);
437
438         for (i = 0; i < UINT32_MAX; i++) {
439                 bool is_free = false;
440                 bool was_free = false;
441                 uint32_t id;
442                 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
443                 TDB_DATA key;
444
445                 if (i >= min_tries && last_free != 0) {
446                         id = last_free;
447                 } else {
448                         id = generate_random();
449                 }
450                 if (id >= UINT16_MAX) {
451                         /*
452                          * For now we truncate to 16bit,
453                          * as that's what all callers
454                          * expect (uint16_t vuid).
455                          */
456                         id = id & UINT16_MAX;
457                 }
458                 if (id == 0) {
459                         id++;
460                 }
461                 if (id == UINT32_MAX) {
462                         id--;
463                 }
464
465                 key = smbXsrv_session_global_id_to_key(id, key_buf);
466
467                 global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
468                 if (global->db_rec == NULL) {
469                         talloc_free(global);
470                         return NT_STATUS_INSUFFICIENT_RESOURCES;
471                 }
472
473                 smbXsrv_session_global_verify_record(global->db_rec,
474                                                      &is_free,
475                                                      &was_free,
476                                                      NULL, NULL);
477
478                 if (!is_free) {
479                         TALLOC_FREE(global->db_rec);
480                         continue;
481                 }
482
483                 if (!was_free && i < min_tries) {
484                         /*
485                          * The session_id is free now,
486                          * but was not free before.
487                          *
488                          * This happens if a smbd crashed
489                          * and did not cleanup the record.
490                          *
491                          * If this is one of our first tries,
492                          * then we try to find a real free one.
493                          */
494                         if (last_free == 0) {
495                                 last_free = id;
496                         }
497                         TALLOC_FREE(global->db_rec);
498                         continue;
499                 }
500                 global->session_global_id = id;
501
502                 *_global = global;
503                 return NT_STATUS_OK;
504         }
505
506         /* should not be reached */
507         talloc_free(global);
508         return NT_STATUS_INTERNAL_ERROR;
509 }
510
511 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
512                                         bool *is_free,
513                                         bool *was_free,
514                                         TALLOC_CTX *mem_ctx,
515                                         struct smbXsrv_session_global0 **_g)
516 {
517         TDB_DATA val;
518         DATA_BLOB blob;
519         struct smbXsrv_session_globalB global_blob;
520         enum ndr_err_code ndr_err;
521         struct smbXsrv_session_global0 *global = NULL;
522         bool exists;
523         TALLOC_CTX *frame = talloc_stackframe();
524
525         *is_free = false;
526
527         if (was_free) {
528                 *was_free = false;
529         }
530         if (_g) {
531                 *_g = NULL;
532         }
533
534         val = dbwrap_record_get_value(db_rec);
535         if (val.dsize == 0) {
536                 TALLOC_FREE(frame);
537                 *is_free = true;
538                 if (was_free) {
539                         *was_free = true;
540                 }
541                 return;
542         }
543
544         blob = data_blob_const(val.dptr, val.dsize);
545
546         ndr_err = ndr_pull_struct_blob_all(&blob, frame, &global_blob,
547                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
548         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
549                 TALLOC_FREE(frame);
550                 return;
551         }
552
553         DEBUG(0,("smbXsrv_session_global_verify_record\n"));
554         NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
555
556         if (global_blob.version != SMBXSRV_VERSION_0) {
557                 TALLOC_FREE(frame);
558                 return;
559         }
560
561         global = global_blob.info.info0;
562
563         exists = serverid_exists(&global->channels[0].server_id);
564         if (!exists) {
565                 TALLOC_FREE(frame);
566                 dbwrap_record_delete(db_rec);
567                 *is_free = true;
568                 return;
569         }
570
571         if (_g) {
572                 *_g = talloc_move(mem_ctx, &global);
573         }
574         TALLOC_FREE(frame);
575 }
576
577 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_connection *sconn,
578                                              struct smbXsrv_session_global0 *global)
579 {
580         struct smbXsrv_session_globalB global_blob;
581         DATA_BLOB blob = data_blob_null;
582         TDB_DATA val;
583         NTSTATUS status;
584         enum ndr_err_code ndr_err;
585
586         /*
587          * TODO: if we use other versions than '0'
588          * we would add glue code here, that would be able to
589          * store the information in the old format.
590          */
591
592         if (global->db_rec == NULL) {
593                 return NT_STATUS_INTERNAL_ERROR;
594         }
595
596         val = dbwrap_record_get_value(global->db_rec);
597
598         ZERO_STRUCT(global_blob);
599         global_blob.version = smbXsrv_version_global_current();
600         if (val.dsize >= 8) {
601                 global_blob.seqnum = IVAL(val.dptr, 4);
602         }
603         global_blob.seqnum += 1;
604         global_blob.info.info0 = global;
605
606         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
607                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
608         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
609                 //status = ndr_err_code;
610                 TALLOC_FREE(global->db_rec);
611                 //TODO status = map
612                 return status;
613         }
614
615         val = make_tdb_data(blob.data, blob.length);
616         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
617         TALLOC_FREE(global->db_rec);
618         if (!NT_STATUS_IS_OK(status)) {
619                 return status;
620         }
621
622         return NT_STATUS_OK;
623 }
624
625 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
626 {
627         struct smbXsrv_session_table *table;
628         struct db_record *local_rec = NULL;
629         struct db_record *global_rec = NULL;
630         NTSTATUS status;
631
632         if (session->table == NULL) {
633                 return 0;
634         }
635
636         table = session->table;
637         session->table = NULL;
638
639         session->connection = NULL;
640
641         local_rec = session->db_rec;
642         session->db_rec = NULL;
643         if (local_rec == NULL) {
644                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
645                 TDB_DATA key;
646
647                 key = smbXsrv_session_local_id_to_key(session->local_id,
648                                                       key_buf);
649
650                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
651                                                 session, key);
652         }
653
654         if (local_rec != NULL) {
655                 status = dbwrap_record_delete(local_rec);
656         }
657
658         global_rec = session->global->db_rec;
659         session->global->db_rec = NULL;
660         if (global_rec == NULL) {
661                 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
662                 TDB_DATA key;
663
664                 key = smbXsrv_session_global_id_to_key(
665                                         session->global->session_global_id,
666                                         key_buf);
667
668                 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
669                                                  session->global, key);
670         }
671
672         if (global_rec != NULL) {
673                 status = dbwrap_record_delete(global_rec);
674         }
675         TALLOC_FREE(session->global);
676
677         return 0;
678 }
679
680 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
681                                 NTTIME now,
682                                 struct smbXsrv_session **_session)
683 {
684         struct smbXsrv_session_table *table = conn->session_table;
685         uint32_t max_sessions = table->local.highest_id - table->local.lowest_id;
686         struct db_record *local_rec = NULL;
687         struct smbXsrv_session *session = NULL;
688         void *ptr = NULL;
689         TDB_DATA val;
690         struct smbXsrv_session_global0 *global = NULL;
691         struct smbXsrv_channel_global0 *channels = NULL;
692         NTSTATUS status;
693
694         //system("sleep 999999");
695
696         if (table->local.num_sessions >= max_sessions) {
697                 return NT_STATUS_INSUFFICIENT_RESOURCES;
698                 // TODO smb1 return NT_STATUS_TOO_MANY_SESSIONS;
699         }
700
701         session = talloc_zero(conn, struct smbXsrv_session);
702         if (session == NULL) {
703                 return NT_STATUS_NO_MEMORY;
704         }
705         session->table = table;
706         session->idle_time = now;
707         session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
708         session->connection = conn;
709
710         status = smbXsrv_session_global_allocate(table->global.db_ctx,
711                                                  session,
712                                                  &global);
713         if (!NT_STATUS_IS_OK(status)) {
714                 talloc_free(session);
715                 return status;
716         }
717         session->global = global;
718
719         talloc_set_destructor(session, smbXsrv_session_destructor);
720
721         if (conn->protocol >= PROTOCOL_SMB2_02) {
722                 uint16_t dialect = SMB2_DIALECT_REVISION_2FF;
723                 uint64_t id = global->session_global_id;
724                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
725                 TDB_DATA key;
726
727                 global->session_wire_id = id;
728
729                 switch (conn->protocol) {
730                 case PROTOCOL_SMB2_02:
731                         dialect = SMB2_DIALECT_REVISION_202;
732                         break;
733                 case PROTOCOL_SMB2_10:
734                         dialect = SMB2_DIALECT_REVISION_210;
735                         break;
736                 case PROTOCOL_SMB2_22:
737                         dialect = SMB2_DIALECT_REVISION_222;
738                         break;
739                 case PROTOCOL_SMB2_24:
740                         dialect = SMB2_DIALECT_REVISION_224;
741                         break;
742                 case PROTOCOL_SMB3_00:
743                         dialect = SMB3_DIALECT_REVISION_300;
744                         break;
745                 default:
746                         talloc_free(session);
747                         return NT_STATUS_INTERNAL_ERROR;
748                 }
749                 global->connection_dialect = dialect;
750
751                 session->local_id = global->session_global_id;
752
753                 key = smbXsrv_session_local_id_to_key(session->local_id, key_buf);
754
755                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
756                                                 session, key);
757                 if (local_rec == NULL) {
758                         return NT_STATUS_NO_MEMORY;
759                 }
760
761                 val = dbwrap_record_get_value(local_rec);
762                 if (val.dsize != 0) {
763                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
764                 }
765         } else {
766
767                 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
768                                                         table->local.lowest_id,
769                                                         table->local.highest_id,
770                                                         session,
771                                                         &local_rec,
772                                                         &session->local_id);
773                 if (!NT_STATUS_IS_OK(status)) {
774                         return status;
775                 }
776
777                 global->session_wire_id = session->local_id;
778         }
779
780         ptr = session;
781         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
782         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
783         TALLOC_FREE(local_rec);
784         if (!NT_STATUS_IS_OK(status)) {
785                 talloc_free(session);
786                 return status;
787         }
788
789         global->creation_time = now;
790         global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
791
792         global->num_channels = 1;
793         channels = talloc_zero_array(global,
794                                      struct smbXsrv_channel_global0,
795                                      global->num_channels);
796         if (channels == NULL) {
797                 talloc_free(session);
798                 return NT_STATUS_NO_MEMORY;
799         }
800         global->channels = channels;
801
802         channels[0].server_id = messaging_server_id(conn->msg_ctx);
803         channels[0].local_address = tsocket_address_string(conn->local_address,
804                                                            channels);
805         if (channels[0].local_address == NULL) {
806                 talloc_free(session);
807                 return NT_STATUS_NO_MEMORY;
808         }
809         channels[0].remote_address = tsocket_address_string(conn->remote_address,
810                                                             channels);
811         if (channels[0].remote_address == NULL) {
812                 talloc_free(session);
813                 return NT_STATUS_NO_MEMORY;
814         }
815         channels[0].remote_name = talloc_strdup(channels, conn->remote_hostname);
816         if (channels[0].remote_name == NULL) {
817                 talloc_free(session);
818                 return NT_STATUS_NO_MEMORY;
819         }
820         channels[0].signing_key = data_blob_null;
821
822         status = smbXsrv_session_global_store(conn,
823                                               global);
824         if (!NT_STATUS_IS_OK(status)) {
825                 talloc_free(session);
826                 return status;
827         }
828
829         {
830                 struct smbXsrv_sessionB session_blob;
831
832                 ZERO_STRUCT(session_blob);
833                 session_blob.version = SMBXSRV_VERSION_0;
834                 session_blob.info.info0 = session;
835
836                 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
837         }
838
839         *_session = session;
840         return NT_STATUS_OK;
841 }
842
843 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
844 {
845         struct smbXsrv_session_table *table = session->table;
846         NTSTATUS status;
847         uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
848         TDB_DATA key;
849
850         if (session->global->db_rec != NULL) {
851                 return NT_STATUS_INTERNAL_ERROR;
852         }
853
854         key = smbXsrv_session_global_id_to_key(
855                                         session->global->session_global_id,
856                                         key_buf);
857
858         session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
859                                                       session->global, key);
860         if (session->global->db_rec == NULL) {
861                 // TODO proper return code?
862                 return NT_STATUS_NO_MEMORY;
863         }
864
865         status = smbXsrv_session_global_store(session->connection,
866                                               session->global);
867         if (!NT_STATUS_IS_OK(status)) {
868                 /* debug */
869                 return status;
870         }
871
872         {
873                 struct smbXsrv_sessionB session_blob;
874
875                 ZERO_STRUCT(session_blob);
876                 session_blob.version = SMBXSRV_VERSION_0;
877                 session_blob.info.info0 = session;
878
879                 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
880         }
881
882         return NT_STATUS_OK;
883 }
884
885 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
886 {
887         /*
888          * Allow a range from 100..65534.
889          */
890         return smbXsrv_session_table_init(conn, 100, UINT16_MAX - 1);
891 }
892
893 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
894                                 uint16_t vuid, NTTIME now,
895                                 struct smbXsrv_session **session)
896 {
897         struct smbXsrv_session_table *table = conn->session_table;
898         uint32_t local_id = vuid;
899
900         return smbXsrv_session_local_lookup(table, local_id, now, session);
901 }
902
903 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
904 {
905         /*
906          * For now use the same range as SMB1.
907          *
908          * Allow a range from 100..65534.
909          */
910         return smbXsrv_session_table_init(conn, 100, UINT16_MAX - 1);
911 }
912
913 NTSTATUS smb2srv_session_lookup(struct smbXsrv_connection *conn,
914                                 uint64_t session_id, NTTIME now,
915                                 struct smbXsrv_session **session)
916 {
917         struct smbXsrv_session_table *table = conn->session_table;
918         uint32_t local_id = session_id & UINT32_MAX;
919         uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
920
921         if (local_zeros != 0) {
922                 return NT_STATUS_USER_SESSION_DELETED;
923         }
924
925         return smbXsrv_session_local_lookup(table, local_id, now, session);
926 }