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