s3:smbXsrv_session: add smb2srv_session_close_previous_send/recv
[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 <tevent.h>
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_rbt.h"
28 #include "dbwrap/dbwrap_open.h"
29 #include "dbwrap/dbwrap_watch.h"
30 #include "session.h"
31 #include "auth.h"
32 #include "auth/gensec/gensec.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "../libcli/security/security.h"
35 #include "messages.h"
36 #include "lib/util/util_tdb.h"
37 #include "librpc/gen_ndr/ndr_smbXsrv.h"
38 #include "serverid.h"
39 #include "lib/util/tevent_ntstatus.h"
40
41 struct smbXsrv_session_table {
42         struct {
43                 struct db_context *db_ctx;
44                 uint32_t lowest_id;
45                 uint32_t highest_id;
46                 uint32_t num_sessions;
47         } local;
48         struct {
49                 struct db_context *db_ctx;
50         } global;
51 };
52
53 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
54
55 NTSTATUS smbXsrv_session_global_init(void)
56 {
57         const char *global_path = NULL;
58         struct db_context *db_ctx = NULL;
59
60         if (smbXsrv_session_global_db_ctx != NULL) {
61                 return NT_STATUS_OK;
62         }
63
64         /*
65          * This contains secret information like session keys!
66          */
67         global_path = lock_path("smbXsrv_session_global.tdb");
68
69         db_ctx = db_open(NULL, global_path,
70                          0, /* hash_size */
71                          TDB_DEFAULT |
72                          TDB_CLEAR_IF_FIRST |
73                          TDB_INCOMPATIBLE_HASH,
74                          O_RDWR | O_CREAT, 0600,
75                          DBWRAP_LOCK_ORDER_1);
76         if (db_ctx == NULL) {
77                 NTSTATUS status;
78
79                 status = map_nt_error_from_unix_common(errno);
80
81                 return status;
82         }
83
84         smbXsrv_session_global_db_ctx = db_ctx;
85
86         return NT_STATUS_OK;
87 }
88
89 /*
90  * NOTE:
91  * We need to store the keys in big endian so that dbwrap_rbt's memcmp
92  * has the same result as integer comparison between the uint32_t
93  * values.
94  *
95  * TODO: implement string based key
96  */
97
98 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
99
100 static TDB_DATA smbXsrv_session_global_id_to_key(uint32_t id,
101                                                  uint8_t *key_buf)
102 {
103         TDB_DATA key;
104
105         RSIVAL(key_buf, 0, id);
106
107         key = make_tdb_data(key_buf, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE);
108
109         return key;
110 }
111
112 #if 0
113 static NTSTATUS smbXsrv_session_global_key_to_id(TDB_DATA key, uint32_t *id)
114 {
115         if (id == NULL) {
116                 return NT_STATUS_INVALID_PARAMETER;
117         }
118
119         if (key.dsize != SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE) {
120                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
121         }
122
123         *id = RIVAL(key.dptr, 0);
124
125         return NT_STATUS_OK;
126 }
127 #endif
128
129 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
130
131 static TDB_DATA smbXsrv_session_local_id_to_key(uint32_t id,
132                                                 uint8_t *key_buf)
133 {
134         TDB_DATA key;
135
136         RSIVAL(key_buf, 0, id);
137
138         key = make_tdb_data(key_buf, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE);
139
140         return key;
141 }
142
143 static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
144 {
145         if (id == NULL) {
146                 return NT_STATUS_INVALID_PARAMETER;
147         }
148
149         if (key.dsize != SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE) {
150                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
151         }
152
153         *id = RIVAL(key.dptr, 0);
154
155         return NT_STATUS_OK;
156 }
157
158 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
159                                            uint32_t lowest_id,
160                                            uint32_t highest_id)
161 {
162         struct smbXsrv_session_table *table;
163         NTSTATUS status;
164
165         table = talloc_zero(conn, struct smbXsrv_session_table);
166         if (table == NULL) {
167                 return NT_STATUS_NO_MEMORY;
168         }
169
170         table->local.db_ctx = db_open_rbt(table);
171         if (table->local.db_ctx == NULL) {
172                 TALLOC_FREE(table);
173                 return NT_STATUS_NO_MEMORY;
174         }
175         table->local.lowest_id = lowest_id;
176         table->local.highest_id = highest_id;
177
178         status = smbXsrv_session_global_init();
179         if (!NT_STATUS_IS_OK(status)) {
180                 TALLOC_FREE(table);
181                 return status;
182         }
183
184         table->global.db_ctx = smbXsrv_session_global_db_ctx;
185
186         conn->session_table = table;
187         return NT_STATUS_OK;
188 }
189
190 struct smb1srv_session_local_allocate_state {
191         const uint32_t lowest_id;
192         const uint32_t highest_id;
193         uint32_t last_id;
194         uint32_t useable_id;
195         NTSTATUS status;
196 };
197
198 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
199                                                    void *private_data)
200 {
201         struct smb1srv_session_local_allocate_state *state =
202                 (struct smb1srv_session_local_allocate_state *)private_data;
203         TDB_DATA key = dbwrap_record_get_key(rec);
204         uint32_t id = 0;
205         NTSTATUS status;
206
207         status = smbXsrv_session_local_key_to_id(key, &id);
208         if (!NT_STATUS_IS_OK(status)) {
209                 state->status = status;
210                 return -1;
211         }
212
213         if (id <= state->last_id) {
214                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
215                 return -1;
216         }
217         state->last_id = id;
218
219         if (id > state->useable_id) {
220                 state->status = NT_STATUS_OK;
221                 return -1;
222         }
223
224         if (state->useable_id == state->highest_id) {
225                 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
226                 return -1;
227         }
228
229         state->useable_id +=1;
230         return 0;
231 }
232
233 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
234                                                   uint32_t lowest_id,
235                                                   uint32_t highest_id,
236                                                   TALLOC_CTX *mem_ctx,
237                                                   struct db_record **_rec,
238                                                   uint32_t *_id)
239 {
240         struct smb1srv_session_local_allocate_state state = {
241                 .lowest_id = lowest_id,
242                 .highest_id = highest_id,
243                 .last_id = 0,
244                 .useable_id = lowest_id,
245                 .status = NT_STATUS_INTERNAL_ERROR,
246         };
247         uint32_t i;
248         uint32_t range;
249         NTSTATUS status;
250         int count = 0;
251
252         *_rec = NULL;
253         *_id = 0;
254
255         if (lowest_id > highest_id) {
256                 return NT_STATUS_INSUFFICIENT_RESOURCES;
257         }
258
259         /*
260          * first we try randomly
261          */
262         range = (highest_id - lowest_id) + 1;
263
264         for (i = 0; i < (range / 2); i++) {
265                 uint32_t id;
266                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
267                 TDB_DATA key;
268                 TDB_DATA val;
269                 struct db_record *rec = NULL;
270
271                 id = generate_random() % range;
272                 id += lowest_id;
273
274                 if (id < lowest_id) {
275                         id = lowest_id;
276                 }
277                 if (id > highest_id) {
278                         id = highest_id;
279                 }
280
281                 key = smbXsrv_session_local_id_to_key(id, key_buf);
282
283                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
284                 if (rec == NULL) {
285                         return NT_STATUS_INSUFFICIENT_RESOURCES;
286                 }
287
288                 val = dbwrap_record_get_value(rec);
289                 if (val.dsize != 0) {
290                         TALLOC_FREE(rec);
291                         continue;
292                 }
293
294                 *_rec = rec;
295                 *_id = id;
296                 return NT_STATUS_OK;
297         }
298
299         /*
300          * if the range is almost full,
301          * we traverse the whole table
302          * (this relies on sorted behavior of dbwrap_rbt)
303          */
304         status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
305                                       &state, &count);
306         if (NT_STATUS_IS_OK(status)) {
307                 if (NT_STATUS_IS_OK(state.status)) {
308                         return NT_STATUS_INTERNAL_ERROR;
309                 }
310
311                 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
312                         return state.status;
313                 }
314
315                 if (state.useable_id <= state.highest_id) {
316                         state.status = NT_STATUS_OK;
317                 } else {
318                         return NT_STATUS_INSUFFICIENT_RESOURCES;
319                 }
320         } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
321                 /*
322                  * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
323                  *
324                  * If we get anything else it is an error, because it
325                  * means we did not manage to find a free slot in
326                  * the db.
327                  */
328                 return NT_STATUS_INSUFFICIENT_RESOURCES;
329         }
330
331         if (NT_STATUS_IS_OK(state.status)) {
332                 uint32_t id;
333                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
334                 TDB_DATA key;
335                 TDB_DATA val;
336                 struct db_record *rec = NULL;
337
338                 id = state.useable_id;
339
340                 key = smbXsrv_session_local_id_to_key(id, key_buf);
341
342                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
343                 if (rec == NULL) {
344                         return NT_STATUS_INSUFFICIENT_RESOURCES;
345                 }
346
347                 val = dbwrap_record_get_value(rec);
348                 if (val.dsize != 0) {
349                         TALLOC_FREE(rec);
350                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
351                 }
352
353                 *_rec = rec;
354                 *_id = id;
355                 return NT_STATUS_OK;
356         }
357
358         return state.status;
359 }
360
361 struct smbXsrv_session_local_fetch_state {
362         struct smbXsrv_session *session;
363         NTSTATUS status;
364 };
365
366 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
367                                                void *private_data)
368 {
369         struct smbXsrv_session_local_fetch_state *state =
370                 (struct smbXsrv_session_local_fetch_state *)private_data;
371         void *ptr;
372
373         if (data.dsize != sizeof(ptr)) {
374                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
375                 return;
376         }
377
378         memcpy(&ptr, data.dptr, data.dsize);
379         state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
380         state->status = NT_STATUS_OK;
381 }
382
383 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
384                                              uint32_t session_local_id,
385                                              NTTIME now,
386                                              struct smbXsrv_session **_session)
387 {
388         struct smbXsrv_session_local_fetch_state state = {
389                 .session = NULL,
390                 .status = NT_STATUS_INTERNAL_ERROR,
391         };
392         uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
393         TDB_DATA key;
394         NTSTATUS status;
395
396         *_session = NULL;
397
398         if (session_local_id == 0) {
399                 return NT_STATUS_USER_SESSION_DELETED;
400         }
401
402         if (table == NULL) {
403                 /* this might happen before the end of negprot */
404                 return NT_STATUS_USER_SESSION_DELETED;
405         }
406
407         if (table->local.db_ctx == NULL) {
408                 return NT_STATUS_INTERNAL_ERROR;
409         }
410
411         key = smbXsrv_session_local_id_to_key(session_local_id, key_buf);
412
413         status = dbwrap_parse_record(table->local.db_ctx, key,
414                                      smbXsrv_session_local_fetch_parser,
415                                      &state);
416         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
417                 return NT_STATUS_USER_SESSION_DELETED;
418         } else if (!NT_STATUS_IS_OK(status)) {
419                 return status;
420         }
421         if (!NT_STATUS_IS_OK(state.status)) {
422                 return state.status;
423         }
424
425         if (NT_STATUS_EQUAL(state.session->status, NT_STATUS_USER_SESSION_DELETED)) {
426                 return NT_STATUS_USER_SESSION_DELETED;
427         }
428
429         state.session->idle_time = now;
430
431         if (!NT_STATUS_IS_OK(state.session->status)) {
432                 *_session = state.session;
433                 return state.session->status;
434         }
435
436         if (now > state.session->global->expiration_time) {
437                 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
438         }
439
440         *_session = state.session;
441         return state.session->status;
442 }
443
444 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
445 {
446         return 0;
447 }
448
449 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
450                                         bool *is_free,
451                                         bool *was_free,
452                                         TALLOC_CTX *mem_ctx,
453                                         struct smbXsrv_session_global0 **_g);
454
455 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
456                                         TALLOC_CTX *mem_ctx,
457                                         struct smbXsrv_session_global0 **_global)
458 {
459         uint32_t i;
460         struct smbXsrv_session_global0 *global = NULL;
461         uint32_t last_free = 0;
462         const uint32_t min_tries = 3;
463
464         *_global = NULL;
465
466         global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
467         if (global == NULL) {
468                 return NT_STATUS_NO_MEMORY;
469         }
470         talloc_set_destructor(global, smbXsrv_session_global_destructor);
471
472         /*
473          * Here we just randomly try the whole 32-bit space
474          *
475          * We use just 32-bit, because we want to reuse the
476          * ID for SRVSVC.
477          */
478         for (i = 0; i < UINT32_MAX; i++) {
479                 bool is_free = false;
480                 bool was_free = false;
481                 uint32_t id;
482                 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
483                 TDB_DATA key;
484
485                 if (i >= min_tries && last_free != 0) {
486                         id = last_free;
487                 } else {
488                         id = generate_random();
489                 }
490                 if (id == 0) {
491                         id++;
492                 }
493                 if (id == UINT32_MAX) {
494                         id--;
495                 }
496
497                 key = smbXsrv_session_global_id_to_key(id, key_buf);
498
499                 global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
500                 if (global->db_rec == NULL) {
501                         talloc_free(global);
502                         return NT_STATUS_INSUFFICIENT_RESOURCES;
503                 }
504
505                 smbXsrv_session_global_verify_record(global->db_rec,
506                                                      &is_free,
507                                                      &was_free,
508                                                      NULL, NULL);
509
510                 if (!is_free) {
511                         TALLOC_FREE(global->db_rec);
512                         continue;
513                 }
514
515                 if (!was_free && i < min_tries) {
516                         /*
517                          * The session_id is free now,
518                          * but was not free before.
519                          *
520                          * This happens if a smbd crashed
521                          * and did not cleanup the record.
522                          *
523                          * If this is one of our first tries,
524                          * then we try to find a real free one.
525                          */
526                         if (last_free == 0) {
527                                 last_free = id;
528                         }
529                         TALLOC_FREE(global->db_rec);
530                         continue;
531                 }
532
533                 global->session_global_id = id;
534
535                 *_global = global;
536                 return NT_STATUS_OK;
537         }
538
539         /* should not be reached */
540         talloc_free(global);
541         return NT_STATUS_INTERNAL_ERROR;
542 }
543
544 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
545                                         bool *is_free,
546                                         bool *was_free,
547                                         TALLOC_CTX *mem_ctx,
548                                         struct smbXsrv_session_global0 **_g)
549 {
550         TDB_DATA key;
551         TDB_DATA val;
552         DATA_BLOB blob;
553         struct smbXsrv_session_globalB global_blob;
554         enum ndr_err_code ndr_err;
555         struct smbXsrv_session_global0 *global = NULL;
556         bool exists;
557         TALLOC_CTX *frame = talloc_stackframe();
558
559         *is_free = false;
560
561         if (was_free) {
562                 *was_free = false;
563         }
564         if (_g) {
565                 *_g = NULL;
566         }
567
568         key = dbwrap_record_get_key(db_rec);
569
570         val = dbwrap_record_get_value(db_rec);
571         if (val.dsize == 0) {
572                 TALLOC_FREE(frame);
573                 *is_free = true;
574                 if (was_free) {
575                         *was_free = true;
576                 }
577                 return;
578         }
579
580         blob = data_blob_const(val.dptr, val.dsize);
581
582         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
583                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
584         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
585                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
586                 DEBUG(1,("smbXsrv_session_global_verify_record: "
587                          "key '%s' ndr_pull_struct_blob - %s\n",
588                          hex_encode_talloc(frame, key.dptr, key.dsize),
589                          nt_errstr(status)));
590                 TALLOC_FREE(frame);
591                 return;
592         }
593
594         DEBUG(10,("smbXsrv_session_global_verify_record\n"));
595         if (DEBUGLVL(10)) {
596                 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
597         }
598
599         if (global_blob.version != SMBXSRV_VERSION_0) {
600                 DEBUG(0,("smbXsrv_session_global_verify_record: "
601                          "key '%s' use unsupported version %u\n",
602                          hex_encode_talloc(frame, key.dptr, key.dsize),
603                          global_blob.version));
604                 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
605                 TALLOC_FREE(frame);
606                 return;
607         }
608
609         global = global_blob.info.info0;
610
611         exists = serverid_exists(&global->channels[0].server_id);
612         if (!exists) {
613                 DEBUG(2,("smbXsrv_session_global_verify_record: "
614                          "key '%s' server_id %s does not exist.\n",
615                          hex_encode_talloc(frame, key.dptr, key.dsize),
616                          server_id_str(frame, &global->channels[0].server_id)));
617                 if (DEBUGLVL(2)) {
618                         NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
619                 }
620                 TALLOC_FREE(frame);
621                 dbwrap_record_delete(db_rec);
622                 *is_free = true;
623                 return;
624         }
625
626         if (_g) {
627                 *_g = talloc_move(mem_ctx, &global);
628         }
629         TALLOC_FREE(frame);
630 }
631
632 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_session_global0 *global)
633 {
634         struct smbXsrv_session_globalB global_blob;
635         DATA_BLOB blob = data_blob_null;
636         TDB_DATA key;
637         TDB_DATA val;
638         NTSTATUS status;
639         enum ndr_err_code ndr_err;
640
641         /*
642          * TODO: if we use other versions than '0'
643          * we would add glue code here, that would be able to
644          * store the information in the old format.
645          */
646
647         if (global->db_rec == NULL) {
648                 return NT_STATUS_INTERNAL_ERROR;
649         }
650
651         key = dbwrap_record_get_key(global->db_rec);
652         val = dbwrap_record_get_value(global->db_rec);
653
654         ZERO_STRUCT(global_blob);
655         global_blob.version = smbXsrv_version_global_current();
656         if (val.dsize >= 8) {
657                 global_blob.seqnum = IVAL(val.dptr, 4);
658         }
659         global_blob.seqnum += 1;
660         global_blob.info.info0 = global;
661
662         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
663                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
664         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
665                 status = ndr_map_error2ntstatus(ndr_err);
666                 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
667                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
668                          nt_errstr(status)));
669                 TALLOC_FREE(global->db_rec);
670                 return status;
671         }
672
673         val = make_tdb_data(blob.data, blob.length);
674         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
675         if (!NT_STATUS_IS_OK(status)) {
676                 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
677                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
678                          nt_errstr(status)));
679                 TALLOC_FREE(global->db_rec);
680                 return status;
681         }
682
683         if (DEBUGLVL(10)) {
684                 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
685                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
686                 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
687         }
688
689         TALLOC_FREE(global->db_rec);
690
691         return NT_STATUS_OK;
692 }
693
694 struct smb2srv_session_close_previous_state {
695         struct tevent_context *ev;
696         struct smbXsrv_connection *connection;
697         struct dom_sid *current_sid;
698         uint64_t current_session_id;
699         struct db_record *db_rec;
700 };
701
702 static void smb2srv_session_close_previous_check(struct tevent_req *req);
703 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq);
704
705 struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
706                                         struct tevent_context *ev,
707                                         struct smbXsrv_connection *conn,
708                                         struct auth_session_info *session_info,
709                                         uint64_t previous_session_id,
710                                         uint64_t current_session_id)
711 {
712         struct tevent_req *req;
713         struct smb2srv_session_close_previous_state *state;
714         uint32_t global_id = previous_session_id & UINT32_MAX;
715         uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU;
716         struct smbXsrv_session_table *table = conn->session_table;
717         struct security_token *current_token = NULL;
718         uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
719         TDB_DATA key;
720
721         req = tevent_req_create(mem_ctx, &state,
722                                 struct smb2srv_session_close_previous_state);
723         if (req == NULL) {
724                 return NULL;
725         }
726         state->ev = ev;
727         state->connection = conn;
728         state->current_session_id = current_session_id;
729
730         if (global_zeros != 0) {
731                 tevent_req_done(req);
732                 return tevent_req_post(req, ev);
733         }
734
735         if (session_info == NULL) {
736                 tevent_req_done(req);
737                 return tevent_req_post(req, ev);
738         }
739         current_token = session_info->security_token;
740
741         if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
742                 state->current_sid = &current_token->sids[PRIMARY_USER_SID_INDEX];
743         }
744
745         if (state->current_sid == NULL) {
746                 tevent_req_done(req);
747                 return tevent_req_post(req, ev);
748         }
749
750         if (!security_token_has_nt_authenticated_users(current_token)) {
751                 /* TODO */
752                 tevent_req_done(req);
753                 return tevent_req_post(req, ev);
754         }
755
756         key = smbXsrv_session_global_id_to_key(global_id, key_buf);
757
758         state->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
759                                             state, key);
760         if (state->db_rec == NULL) {
761                 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
762                 return tevent_req_post(req, ev);
763         }
764
765         smb2srv_session_close_previous_check(req);
766         if (!tevent_req_is_in_progress(req)) {
767                 return tevent_req_post(req, ev);
768         }
769
770         return req;
771 }
772
773 static void smb2srv_session_close_previous_check(struct tevent_req *req)
774 {
775         struct smb2srv_session_close_previous_state *state =
776                 tevent_req_data(req,
777                 struct smb2srv_session_close_previous_state);
778         struct smbXsrv_connection *conn = state->connection;
779         DATA_BLOB blob;
780         struct security_token *previous_token = NULL;
781         struct smbXsrv_session_global0 *global = NULL;
782         enum ndr_err_code ndr_err;
783         struct smbXsrv_session_close0 close_info0;
784         struct smbXsrv_session_closeB close_blob;
785         struct tevent_req *subreq = NULL;
786         NTSTATUS status;
787         bool is_free = false;
788
789         smbXsrv_session_global_verify_record(state->db_rec,
790                                              &is_free,
791                                              NULL,
792                                              state,
793                                              &global);
794
795         if (is_free) {
796                 TALLOC_FREE(state->db_rec);
797                 tevent_req_done(req);
798                 return;
799         }
800
801         if (global->auth_session_info == NULL) {
802                 TALLOC_FREE(state->db_rec);
803                 tevent_req_done(req);
804                 return;
805         }
806
807         previous_token = global->auth_session_info->security_token;
808
809         if (!security_token_is_sid(previous_token, state->current_sid)) {
810                 TALLOC_FREE(state->db_rec);
811                 tevent_req_done(req);
812                 return;
813         }
814
815         subreq = dbwrap_record_watch_send(state, state->ev,
816                                           state->db_rec, conn->msg_ctx);
817         if (tevent_req_nomem(subreq, req)) {
818                 TALLOC_FREE(state->db_rec);
819                 return;
820         }
821         tevent_req_set_callback(subreq,
822                                 smb2srv_session_close_previous_modified,
823                                 req);
824
825         close_info0.old_session_global_id = global->session_global_id;
826         close_info0.old_session_wire_id = global->session_wire_id;
827         close_info0.old_creation_time = global->creation_time;
828         close_info0.new_session_wire_id = state->current_session_id;
829
830         ZERO_STRUCT(close_blob);
831         close_blob.version = smbXsrv_version_global_current();
832         close_blob.info.info0 = &close_info0;
833
834         ndr_err = ndr_push_struct_blob(&blob, state, &close_blob,
835                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_closeB);
836         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
837                 TALLOC_FREE(state->db_rec);
838                 status = ndr_map_error2ntstatus(ndr_err);
839                 DEBUG(1,("smb2srv_session_close_previous_check: "
840                          "old_session[%llu] new_session[%llu] ndr_push - %s\n",
841                          (unsigned long long)close_info0.old_session_wire_id,
842                          (unsigned long long)close_info0.new_session_wire_id,
843                          nt_errstr(status)));
844                 tevent_req_nterror(req, status);
845                 return;
846         }
847
848         status = messaging_send(conn->msg_ctx,
849                                 global->channels[0].server_id,
850                                 MSG_SMBXSRV_SESSION_CLOSE, &blob);
851         TALLOC_FREE(state->db_rec);
852         if (tevent_req_nterror(req, status)) {
853                 return;
854         }
855
856         TALLOC_FREE(global);
857         return;
858 }
859
860 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
861 {
862         struct tevent_req *req =
863                 tevent_req_callback_data(subreq,
864                 struct tevent_req);
865         struct smb2srv_session_close_previous_state *state =
866                 tevent_req_data(req,
867                 struct smb2srv_session_close_previous_state);
868         NTSTATUS status;
869
870         status = dbwrap_record_watch_recv(subreq, state, &state->db_rec);
871         TALLOC_FREE(subreq);
872         if (tevent_req_nterror(req, status)) {
873                 return;
874         }
875
876         smb2srv_session_close_previous_check(req);
877 }
878
879 NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req)
880 {
881         NTSTATUS status;
882
883         if (tevent_req_is_nterror(req, &status)) {
884                 tevent_req_received(req);
885                 return status;
886         }
887
888         tevent_req_received(req);
889         return NT_STATUS_OK;
890 }
891
892 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
893 {
894         NTSTATUS status;
895
896         status = smbXsrv_session_logoff(session);
897         if (!NT_STATUS_IS_OK(status)) {
898                 DEBUG(0, ("smbXsrv_session_destructor: "
899                           "smbXsrv_session_logoff() failed: %s\n",
900                           nt_errstr(status)));
901         }
902
903         TALLOC_FREE(session->global);
904
905         return 0;
906 }
907
908 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
909                                 NTTIME now,
910                                 struct smbXsrv_session **_session)
911 {
912         struct smbXsrv_session_table *table = conn->session_table;
913         uint32_t max_sessions = table->local.highest_id - table->local.lowest_id;
914         struct db_record *local_rec = NULL;
915         struct smbXsrv_session *session = NULL;
916         void *ptr = NULL;
917         TDB_DATA val;
918         struct smbXsrv_session_global0 *global = NULL;
919         struct smbXsrv_channel_global0 *channels = NULL;
920         NTSTATUS status;
921
922         if (table->local.num_sessions >= max_sessions) {
923                 return NT_STATUS_INSUFFICIENT_RESOURCES;
924         }
925
926         session = talloc_zero(table, struct smbXsrv_session);
927         if (session == NULL) {
928                 return NT_STATUS_NO_MEMORY;
929         }
930         session->table = table;
931         session->idle_time = now;
932         session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
933         session->connection = conn;
934
935         status = smbXsrv_session_global_allocate(table->global.db_ctx,
936                                                  session,
937                                                  &global);
938         if (!NT_STATUS_IS_OK(status)) {
939                 TALLOC_FREE(session);
940                 return status;
941         }
942         session->global = global;
943
944         if (conn->protocol >= PROTOCOL_SMB2_02) {
945                 uint64_t id = global->session_global_id;
946                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
947                 TDB_DATA key;
948
949                 global->connection_dialect = conn->smb2.server.dialect;
950
951                 global->session_wire_id = id;
952
953                 status = smb2srv_tcon_table_init(session);
954                 if (!NT_STATUS_IS_OK(status)) {
955                         TALLOC_FREE(session);
956                         return status;
957                 }
958
959                 session->local_id = global->session_global_id;
960
961                 key = smbXsrv_session_local_id_to_key(session->local_id, key_buf);
962
963                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
964                                                 session, key);
965                 if (local_rec == NULL) {
966                         TALLOC_FREE(session);
967                         return NT_STATUS_NO_MEMORY;
968                 }
969
970                 val = dbwrap_record_get_value(local_rec);
971                 if (val.dsize != 0) {
972                         TALLOC_FREE(session);
973                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
974                 }
975         } else {
976
977                 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
978                                                         table->local.lowest_id,
979                                                         table->local.highest_id,
980                                                         session,
981                                                         &local_rec,
982                                                         &session->local_id);
983                 if (!NT_STATUS_IS_OK(status)) {
984                         TALLOC_FREE(session);
985                         return status;
986                 }
987
988                 global->session_wire_id = session->local_id;
989         }
990
991         global->creation_time = now;
992         global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
993
994         global->num_channels = 1;
995         channels = talloc_zero_array(global,
996                                      struct smbXsrv_channel_global0,
997                                      global->num_channels);
998         if (channels == NULL) {
999                 TALLOC_FREE(session);
1000                 return NT_STATUS_NO_MEMORY;
1001         }
1002         global->channels = channels;
1003
1004         channels[0].server_id = messaging_server_id(conn->msg_ctx);
1005         channels[0].local_address = tsocket_address_string(conn->local_address,
1006                                                            channels);
1007         if (channels[0].local_address == NULL) {
1008                 TALLOC_FREE(session);
1009                 return NT_STATUS_NO_MEMORY;
1010         }
1011         channels[0].remote_address = tsocket_address_string(conn->remote_address,
1012                                                             channels);
1013         if (channels[0].remote_address == NULL) {
1014                 TALLOC_FREE(session);
1015                 return NT_STATUS_NO_MEMORY;
1016         }
1017         channels[0].remote_name = talloc_strdup(channels, conn->remote_hostname);
1018         if (channels[0].remote_name == NULL) {
1019                 TALLOC_FREE(session);
1020                 return NT_STATUS_NO_MEMORY;
1021         }
1022         channels[0].signing_key = data_blob_null;
1023
1024         ptr = session;
1025         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1026         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1027         TALLOC_FREE(local_rec);
1028         if (!NT_STATUS_IS_OK(status)) {
1029                 TALLOC_FREE(session);
1030                 return status;
1031         }
1032         table->local.num_sessions += 1;
1033
1034         talloc_set_destructor(session, smbXsrv_session_destructor);
1035
1036         status = smbXsrv_session_global_store(global);
1037         if (!NT_STATUS_IS_OK(status)) {
1038                 DEBUG(0,("smbXsrv_session_create: "
1039                          "global_id (0x%08x) store failed - %s\n",
1040                          session->global->session_global_id,
1041                          nt_errstr(status)));
1042                 TALLOC_FREE(session);
1043                 return status;
1044         }
1045
1046         if (DEBUGLVL(10)) {
1047                 struct smbXsrv_sessionB session_blob;
1048
1049                 ZERO_STRUCT(session_blob);
1050                 session_blob.version = SMBXSRV_VERSION_0;
1051                 session_blob.info.info0 = session;
1052
1053                 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1054                          session->global->session_global_id));
1055                 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1056         }
1057
1058         *_session = session;
1059         return NT_STATUS_OK;
1060 }
1061
1062 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
1063 {
1064         struct smbXsrv_session_table *table = session->table;
1065         NTSTATUS status;
1066         uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
1067         TDB_DATA key;
1068
1069         if (session->global->db_rec != NULL) {
1070                 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1071                           "Called with db_rec != NULL'\n",
1072                           session->global->session_global_id));
1073                 return NT_STATUS_INTERNAL_ERROR;
1074         }
1075
1076         key = smbXsrv_session_global_id_to_key(
1077                                         session->global->session_global_id,
1078                                         key_buf);
1079
1080         session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
1081                                                       session->global, key);
1082         if (session->global->db_rec == NULL) {
1083                 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1084                           "Failed to lock global key '%s'\n",
1085                           session->global->session_global_id,
1086                           hex_encode_talloc(talloc_tos(), key.dptr,
1087                                             key.dsize)));
1088                 return NT_STATUS_INTERNAL_DB_ERROR;
1089         }
1090
1091         status = smbXsrv_session_global_store(session->global);
1092         if (!NT_STATUS_IS_OK(status)) {
1093                 DEBUG(0,("smbXsrv_session_update: "
1094                          "global_id (0x%08x) store failed - %s\n",
1095                          session->global->session_global_id,
1096                          nt_errstr(status)));
1097                 return status;
1098         }
1099
1100         if (DEBUGLVL(10)) {
1101                 struct smbXsrv_sessionB session_blob;
1102
1103                 ZERO_STRUCT(session_blob);
1104                 session_blob.version = SMBXSRV_VERSION_0;
1105                 session_blob.info.info0 = session;
1106
1107                 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1108                           session->global->session_global_id));
1109                 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1110         }
1111
1112         return NT_STATUS_OK;
1113 }
1114
1115 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
1116 {
1117         struct smbXsrv_session_table *table;
1118         struct db_record *local_rec = NULL;
1119         struct db_record *global_rec = NULL;
1120         struct smbXsrv_connection *conn;
1121         NTSTATUS status;
1122         NTSTATUS error = NT_STATUS_OK;
1123
1124         if (session->table == NULL) {
1125                 return NT_STATUS_OK;
1126         }
1127
1128         table = session->table;
1129         session->table = NULL;
1130
1131         conn = session->connection;
1132         session->connection = NULL;
1133         session->status = NT_STATUS_USER_SESSION_DELETED;
1134
1135         global_rec = session->global->db_rec;
1136         session->global->db_rec = NULL;
1137         if (global_rec == NULL) {
1138                 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
1139                 TDB_DATA key;
1140
1141                 key = smbXsrv_session_global_id_to_key(
1142                                         session->global->session_global_id,
1143                                         key_buf);
1144
1145                 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
1146                                                  session->global, key);
1147                 if (global_rec == NULL) {
1148                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1149                                   "Failed to lock global key '%s'\n",
1150                                   session->global->session_global_id,
1151                                   hex_encode_talloc(global_rec, key.dptr,
1152                                                     key.dsize)));
1153                         error = NT_STATUS_INTERNAL_ERROR;
1154                 }
1155         }
1156
1157         if (global_rec != NULL) {
1158                 status = dbwrap_record_delete(global_rec);
1159                 if (!NT_STATUS_IS_OK(status)) {
1160                         TDB_DATA key = dbwrap_record_get_key(global_rec);
1161
1162                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1163                                   "failed to delete global key '%s': %s\n",
1164                                   session->global->session_global_id,
1165                                   hex_encode_talloc(global_rec, key.dptr,
1166                                                     key.dsize),
1167                                   nt_errstr(status)));
1168                         error = status;
1169                 }
1170         }
1171         TALLOC_FREE(global_rec);
1172
1173         local_rec = session->db_rec;
1174         if (local_rec == NULL) {
1175                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
1176                 TDB_DATA key;
1177
1178                 key = smbXsrv_session_local_id_to_key(session->local_id,
1179                                                       key_buf);
1180
1181                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
1182                                                 session, key);
1183                 if (local_rec == NULL) {
1184                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1185                                   "Failed to lock local key '%s'\n",
1186                                   session->global->session_global_id,
1187                                   hex_encode_talloc(local_rec, key.dptr,
1188                                                     key.dsize)));
1189                         error = NT_STATUS_INTERNAL_ERROR;
1190                 }
1191         }
1192
1193         if (local_rec != NULL) {
1194                 status = dbwrap_record_delete(local_rec);
1195                 if (!NT_STATUS_IS_OK(status)) {
1196                         TDB_DATA key = dbwrap_record_get_key(local_rec);
1197
1198                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1199                                   "failed to delete local key '%s': %s\n",
1200                                   session->global->session_global_id,
1201                                   hex_encode_talloc(local_rec, key.dptr,
1202                                                     key.dsize),
1203                                   nt_errstr(status)));
1204                         error = status;
1205                 }
1206                 table->local.num_sessions -= 1;
1207         }
1208         if (session->db_rec == NULL) {
1209                 TALLOC_FREE(local_rec);
1210         }
1211         session->db_rec = NULL;
1212
1213         if (session->compat) {
1214                 file_close_user(conn->sconn, session->compat->vuid);
1215         }
1216
1217         if (conn->protocol >= PROTOCOL_SMB2_02) {
1218                 status = smb2srv_tcon_disconnect_all(session);
1219                 if (!NT_STATUS_IS_OK(status)) {
1220                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1221                                   "smb2srv_tcon_disconnect_all() failed: %s\n",
1222                                   session->global->session_global_id,
1223                                   nt_errstr(status)));
1224                         error = status;
1225                 }
1226         }
1227
1228         if (session->compat) {
1229                 invalidate_vuid(conn->sconn, session->compat->vuid);
1230                 session->compat = NULL;
1231         }
1232
1233         return error;
1234 }
1235
1236 struct smbXsrv_session_logoff_all_state {
1237         NTSTATUS first_status;
1238         int errors;
1239 };
1240
1241 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1242                                                void *private_data);
1243
1244 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_connection *conn)
1245 {
1246         struct smbXsrv_session_table *table = conn->session_table;
1247         struct smbXsrv_session_logoff_all_state state;
1248         NTSTATUS status;
1249         int count = 0;
1250
1251         if (table == NULL) {
1252                 DEBUG(10, ("smbXsrv_session_logoff_all: "
1253                            "empty session_table, nothing to do.\n"));
1254                 return NT_STATUS_OK;
1255         }
1256
1257         ZERO_STRUCT(state);
1258
1259         status = dbwrap_traverse(table->local.db_ctx,
1260                                  smbXsrv_session_logoff_all_callback,
1261                                  &state, &count);
1262         if (!NT_STATUS_IS_OK(status)) {
1263                 DEBUG(0, ("smbXsrv_session_logoff_all: "
1264                           "dbwrap_traverse() failed: %s\n",
1265                           nt_errstr(status)));
1266                 return status;
1267         }
1268
1269         if (!NT_STATUS_IS_OK(state.first_status)) {
1270                 DEBUG(0, ("smbXsrv_session_logoff_all: "
1271                           "count[%d] errors[%d] first[%s]\n",
1272                           count, state.errors,
1273                           nt_errstr(state.first_status)));
1274                 return state.first_status;
1275         }
1276
1277         return NT_STATUS_OK;
1278 }
1279
1280 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1281                                                void *private_data)
1282 {
1283         struct smbXsrv_session_logoff_all_state *state =
1284                 (struct smbXsrv_session_logoff_all_state *)private_data;
1285         TDB_DATA val;
1286         void *ptr = NULL;
1287         struct smbXsrv_session *session = NULL;
1288         NTSTATUS status;
1289
1290         val = dbwrap_record_get_value(local_rec);
1291         if (val.dsize != sizeof(ptr)) {
1292                 status = NT_STATUS_INTERNAL_ERROR;
1293                 if (NT_STATUS_IS_OK(state->first_status)) {
1294                         state->first_status = status;
1295                 }
1296                 state->errors++;
1297                 return 0;
1298         }
1299
1300         memcpy(&ptr, val.dptr, val.dsize);
1301         session = talloc_get_type_abort(ptr, struct smbXsrv_session);
1302
1303         session->db_rec = local_rec;
1304         status = smbXsrv_session_logoff(session);
1305         if (!NT_STATUS_IS_OK(status)) {
1306                 if (NT_STATUS_IS_OK(state->first_status)) {
1307                         state->first_status = status;
1308                 }
1309                 state->errors++;
1310                 return 0;
1311         }
1312
1313         return 0;
1314 }
1315
1316 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
1317 {
1318         /*
1319          * Allow a range from 1..65534.
1320          */
1321         return smbXsrv_session_table_init(conn, 1, UINT16_MAX - 1);
1322 }
1323
1324 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
1325                                 uint16_t vuid, NTTIME now,
1326                                 struct smbXsrv_session **session)
1327 {
1328         struct smbXsrv_session_table *table = conn->session_table;
1329         uint32_t local_id = vuid;
1330
1331         return smbXsrv_session_local_lookup(table, local_id, now, session);
1332 }
1333
1334 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
1335 {
1336         /*
1337          * For now use the same range as SMB1.
1338          *
1339          * Allow a range from 1..65534.
1340          */
1341         return smbXsrv_session_table_init(conn, 1, UINT16_MAX - 1);
1342 }
1343
1344 NTSTATUS smb2srv_session_lookup(struct smbXsrv_connection *conn,
1345                                 uint64_t session_id, NTTIME now,
1346                                 struct smbXsrv_session **session)
1347 {
1348         struct smbXsrv_session_table *table = conn->session_table;
1349         uint32_t local_id = session_id & UINT32_MAX;
1350         uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
1351
1352         if (local_zeros != 0) {
1353                 return NT_STATUS_USER_SESSION_DELETED;
1354         }
1355
1356         return smbXsrv_session_local_lookup(table, local_id, now, session);
1357 }