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