Merge branch 'master' of ctdb into 'master' of samba
[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
1066         status = smbXsrv_session_logoff(session);
1067         if (!NT_STATUS_IS_OK(status)) {
1068                 DEBUG(0, ("smbXsrv_session_destructor: "
1069                           "smbXsrv_session_logoff() failed: %s\n",
1070                           nt_errstr(status)));
1071         }
1072
1073         TALLOC_FREE(session->global);
1074
1075         return 0;
1076 }
1077
1078 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
1079                                 NTTIME now,
1080                                 struct smbXsrv_session **_session)
1081 {
1082         struct smbXsrv_session_table *table = conn->session_table;
1083         struct db_record *local_rec = NULL;
1084         struct smbXsrv_session *session = NULL;
1085         void *ptr = NULL;
1086         TDB_DATA val;
1087         struct smbXsrv_session_global0 *global = NULL;
1088         struct smbXsrv_channel_global0 *channels = NULL;
1089         NTSTATUS status;
1090
1091         if (table->local.num_sessions >= table->local.max_sessions) {
1092                 return NT_STATUS_INSUFFICIENT_RESOURCES;
1093         }
1094
1095         session = talloc_zero(table, struct smbXsrv_session);
1096         if (session == NULL) {
1097                 return NT_STATUS_NO_MEMORY;
1098         }
1099         session->table = table;
1100         session->idle_time = now;
1101         session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1102         session->connection = conn;
1103
1104         status = smbXsrv_session_global_allocate(table->global.db_ctx,
1105                                                  session,
1106                                                  &global);
1107         if (!NT_STATUS_IS_OK(status)) {
1108                 TALLOC_FREE(session);
1109                 return status;
1110         }
1111         session->global = global;
1112
1113         if (conn->protocol >= PROTOCOL_SMB2_02) {
1114                 uint64_t id = global->session_global_id;
1115                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
1116                 TDB_DATA key;
1117
1118                 global->connection_dialect = conn->smb2.server.dialect;
1119
1120                 global->session_wire_id = id;
1121
1122                 status = smb2srv_tcon_table_init(session);
1123                 if (!NT_STATUS_IS_OK(status)) {
1124                         TALLOC_FREE(session);
1125                         return status;
1126                 }
1127
1128                 session->local_id = global->session_global_id;
1129
1130                 key = smbXsrv_session_local_id_to_key(session->local_id, key_buf);
1131
1132                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
1133                                                 session, key);
1134                 if (local_rec == NULL) {
1135                         TALLOC_FREE(session);
1136                         return NT_STATUS_NO_MEMORY;
1137                 }
1138
1139                 val = dbwrap_record_get_value(local_rec);
1140                 if (val.dsize != 0) {
1141                         TALLOC_FREE(session);
1142                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1143                 }
1144         } else {
1145
1146                 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
1147                                                         table->local.lowest_id,
1148                                                         table->local.highest_id,
1149                                                         session,
1150                                                         &local_rec,
1151                                                         &session->local_id);
1152                 if (!NT_STATUS_IS_OK(status)) {
1153                         TALLOC_FREE(session);
1154                         return status;
1155                 }
1156
1157                 global->session_wire_id = session->local_id;
1158         }
1159
1160         global->creation_time = now;
1161         global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
1162
1163         global->num_channels = 1;
1164         channels = talloc_zero_array(global,
1165                                      struct smbXsrv_channel_global0,
1166                                      global->num_channels);
1167         if (channels == NULL) {
1168                 TALLOC_FREE(session);
1169                 return NT_STATUS_NO_MEMORY;
1170         }
1171         global->channels = channels;
1172
1173         channels[0].server_id = messaging_server_id(conn->msg_ctx);
1174         channels[0].local_address = tsocket_address_string(conn->local_address,
1175                                                            channels);
1176         if (channels[0].local_address == NULL) {
1177                 TALLOC_FREE(session);
1178                 return NT_STATUS_NO_MEMORY;
1179         }
1180         channels[0].remote_address = tsocket_address_string(conn->remote_address,
1181                                                             channels);
1182         if (channels[0].remote_address == NULL) {
1183                 TALLOC_FREE(session);
1184                 return NT_STATUS_NO_MEMORY;
1185         }
1186         channels[0].remote_name = talloc_strdup(channels, conn->remote_hostname);
1187         if (channels[0].remote_name == NULL) {
1188                 TALLOC_FREE(session);
1189                 return NT_STATUS_NO_MEMORY;
1190         }
1191         channels[0].signing_key = data_blob_null;
1192
1193         ptr = session;
1194         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1195         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1196         TALLOC_FREE(local_rec);
1197         if (!NT_STATUS_IS_OK(status)) {
1198                 TALLOC_FREE(session);
1199                 return status;
1200         }
1201         table->local.num_sessions += 1;
1202
1203         talloc_set_destructor(session, smbXsrv_session_destructor);
1204
1205         status = smbXsrv_session_global_store(global);
1206         if (!NT_STATUS_IS_OK(status)) {
1207                 DEBUG(0,("smbXsrv_session_create: "
1208                          "global_id (0x%08x) store failed - %s\n",
1209                          session->global->session_global_id,
1210                          nt_errstr(status)));
1211                 TALLOC_FREE(session);
1212                 return status;
1213         }
1214
1215         if (DEBUGLVL(10)) {
1216                 struct smbXsrv_sessionB session_blob;
1217
1218                 ZERO_STRUCT(session_blob);
1219                 session_blob.version = SMBXSRV_VERSION_0;
1220                 session_blob.info.info0 = session;
1221
1222                 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1223                          session->global->session_global_id));
1224                 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1225         }
1226
1227         *_session = session;
1228         return NT_STATUS_OK;
1229 }
1230
1231 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
1232 {
1233         struct smbXsrv_session_table *table = session->table;
1234         NTSTATUS status;
1235         uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
1236         TDB_DATA key;
1237
1238         if (session->global->db_rec != NULL) {
1239                 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1240                           "Called with db_rec != NULL'\n",
1241                           session->global->session_global_id));
1242                 return NT_STATUS_INTERNAL_ERROR;
1243         }
1244
1245         key = smbXsrv_session_global_id_to_key(
1246                                         session->global->session_global_id,
1247                                         key_buf);
1248
1249         session->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
1250                                                       session->global, key);
1251         if (session->global->db_rec == NULL) {
1252                 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1253                           "Failed to lock global key '%s'\n",
1254                           session->global->session_global_id,
1255                           hex_encode_talloc(talloc_tos(), key.dptr,
1256                                             key.dsize)));
1257                 return NT_STATUS_INTERNAL_DB_ERROR;
1258         }
1259
1260         status = smbXsrv_session_global_store(session->global);
1261         if (!NT_STATUS_IS_OK(status)) {
1262                 DEBUG(0,("smbXsrv_session_update: "
1263                          "global_id (0x%08x) store failed - %s\n",
1264                          session->global->session_global_id,
1265                          nt_errstr(status)));
1266                 return status;
1267         }
1268
1269         if (DEBUGLVL(10)) {
1270                 struct smbXsrv_sessionB session_blob;
1271
1272                 ZERO_STRUCT(session_blob);
1273                 session_blob.version = SMBXSRV_VERSION_0;
1274                 session_blob.info.info0 = session;
1275
1276                 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1277                           session->global->session_global_id));
1278                 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1279         }
1280
1281         return NT_STATUS_OK;
1282 }
1283
1284 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
1285 {
1286         struct smbXsrv_session_table *table;
1287         struct db_record *local_rec = NULL;
1288         struct db_record *global_rec = NULL;
1289         struct smbXsrv_connection *conn;
1290         NTSTATUS status;
1291         NTSTATUS error = NT_STATUS_OK;
1292
1293         if (session->table == NULL) {
1294                 return NT_STATUS_OK;
1295         }
1296
1297         table = session->table;
1298         session->table = NULL;
1299
1300         conn = session->connection;
1301         session->connection = NULL;
1302         session->status = NT_STATUS_USER_SESSION_DELETED;
1303
1304         global_rec = session->global->db_rec;
1305         session->global->db_rec = NULL;
1306         if (global_rec == NULL) {
1307                 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
1308                 TDB_DATA key;
1309
1310                 key = smbXsrv_session_global_id_to_key(
1311                                         session->global->session_global_id,
1312                                         key_buf);
1313
1314                 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
1315                                                  session->global, key);
1316                 if (global_rec == NULL) {
1317                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1318                                   "Failed to lock global key '%s'\n",
1319                                   session->global->session_global_id,
1320                                   hex_encode_talloc(global_rec, key.dptr,
1321                                                     key.dsize)));
1322                         error = NT_STATUS_INTERNAL_ERROR;
1323                 }
1324         }
1325
1326         if (global_rec != NULL) {
1327                 status = dbwrap_record_delete(global_rec);
1328                 if (!NT_STATUS_IS_OK(status)) {
1329                         TDB_DATA key = dbwrap_record_get_key(global_rec);
1330
1331                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1332                                   "failed to delete global key '%s': %s\n",
1333                                   session->global->session_global_id,
1334                                   hex_encode_talloc(global_rec, key.dptr,
1335                                                     key.dsize),
1336                                   nt_errstr(status)));
1337                         error = status;
1338                 }
1339         }
1340         TALLOC_FREE(global_rec);
1341
1342         local_rec = session->db_rec;
1343         if (local_rec == NULL) {
1344                 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
1345                 TDB_DATA key;
1346
1347                 key = smbXsrv_session_local_id_to_key(session->local_id,
1348                                                       key_buf);
1349
1350                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
1351                                                 session, key);
1352                 if (local_rec == NULL) {
1353                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1354                                   "Failed to lock local key '%s'\n",
1355                                   session->global->session_global_id,
1356                                   hex_encode_talloc(local_rec, key.dptr,
1357                                                     key.dsize)));
1358                         error = NT_STATUS_INTERNAL_ERROR;
1359                 }
1360         }
1361
1362         if (local_rec != NULL) {
1363                 status = dbwrap_record_delete(local_rec);
1364                 if (!NT_STATUS_IS_OK(status)) {
1365                         TDB_DATA key = dbwrap_record_get_key(local_rec);
1366
1367                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1368                                   "failed to delete local key '%s': %s\n",
1369                                   session->global->session_global_id,
1370                                   hex_encode_talloc(local_rec, key.dptr,
1371                                                     key.dsize),
1372                                   nt_errstr(status)));
1373                         error = status;
1374                 }
1375                 table->local.num_sessions -= 1;
1376         }
1377         if (session->db_rec == NULL) {
1378                 TALLOC_FREE(local_rec);
1379         }
1380         session->db_rec = NULL;
1381
1382         if (session->compat) {
1383                 file_close_user(conn->sconn, session->compat->vuid);
1384         }
1385
1386         if (conn->protocol >= PROTOCOL_SMB2_02) {
1387                 status = smb2srv_tcon_disconnect_all(session);
1388                 if (!NT_STATUS_IS_OK(status)) {
1389                         DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1390                                   "smb2srv_tcon_disconnect_all() failed: %s\n",
1391                                   session->global->session_global_id,
1392                                   nt_errstr(status)));
1393                         error = status;
1394                 }
1395         }
1396
1397         if (session->compat) {
1398                 invalidate_vuid(conn->sconn, session->compat->vuid);
1399                 session->compat = NULL;
1400         }
1401
1402         return error;
1403 }
1404
1405 struct smbXsrv_session_logoff_all_state {
1406         NTSTATUS first_status;
1407         int errors;
1408 };
1409
1410 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1411                                                void *private_data);
1412
1413 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_connection *conn)
1414 {
1415         struct smbXsrv_session_table *table = conn->session_table;
1416         struct smbXsrv_session_logoff_all_state state;
1417         NTSTATUS status;
1418         int count = 0;
1419
1420         if (table == NULL) {
1421                 DEBUG(10, ("smbXsrv_session_logoff_all: "
1422                            "empty session_table, nothing to do.\n"));
1423                 return NT_STATUS_OK;
1424         }
1425
1426         ZERO_STRUCT(state);
1427
1428         status = dbwrap_traverse(table->local.db_ctx,
1429                                  smbXsrv_session_logoff_all_callback,
1430                                  &state, &count);
1431         if (!NT_STATUS_IS_OK(status)) {
1432                 DEBUG(0, ("smbXsrv_session_logoff_all: "
1433                           "dbwrap_traverse() failed: %s\n",
1434                           nt_errstr(status)));
1435                 return status;
1436         }
1437
1438         if (!NT_STATUS_IS_OK(state.first_status)) {
1439                 DEBUG(0, ("smbXsrv_session_logoff_all: "
1440                           "count[%d] errors[%d] first[%s]\n",
1441                           count, state.errors,
1442                           nt_errstr(state.first_status)));
1443                 return state.first_status;
1444         }
1445
1446         return NT_STATUS_OK;
1447 }
1448
1449 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1450                                                void *private_data)
1451 {
1452         struct smbXsrv_session_logoff_all_state *state =
1453                 (struct smbXsrv_session_logoff_all_state *)private_data;
1454         TDB_DATA val;
1455         void *ptr = NULL;
1456         struct smbXsrv_session *session = NULL;
1457         NTSTATUS status;
1458
1459         val = dbwrap_record_get_value(local_rec);
1460         if (val.dsize != sizeof(ptr)) {
1461                 status = NT_STATUS_INTERNAL_ERROR;
1462                 if (NT_STATUS_IS_OK(state->first_status)) {
1463                         state->first_status = status;
1464                 }
1465                 state->errors++;
1466                 return 0;
1467         }
1468
1469         memcpy(&ptr, val.dptr, val.dsize);
1470         session = talloc_get_type_abort(ptr, struct smbXsrv_session);
1471
1472         session->db_rec = local_rec;
1473         status = smbXsrv_session_logoff(session);
1474         if (!NT_STATUS_IS_OK(status)) {
1475                 if (NT_STATUS_IS_OK(state->first_status)) {
1476                         state->first_status = status;
1477                 }
1478                 state->errors++;
1479                 return 0;
1480         }
1481
1482         return 0;
1483 }
1484
1485 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
1486 {
1487         /*
1488          * Allow a range from 1..65534 with 65534 values.
1489          */
1490         return smbXsrv_session_table_init(conn, 1, UINT16_MAX - 1,
1491                                           UINT16_MAX - 1);
1492 }
1493
1494 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
1495                                 uint16_t vuid, NTTIME now,
1496                                 struct smbXsrv_session **session)
1497 {
1498         struct smbXsrv_session_table *table = conn->session_table;
1499         uint32_t local_id = vuid;
1500
1501         return smbXsrv_session_local_lookup(table, local_id, now, session);
1502 }
1503
1504 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
1505 {
1506         /*
1507          * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1508          */
1509         return smbXsrv_session_table_init(conn, 1, UINT32_MAX - 1,
1510                                           UINT16_MAX - 1);
1511 }
1512
1513 NTSTATUS smb2srv_session_lookup(struct smbXsrv_connection *conn,
1514                                 uint64_t session_id, NTTIME now,
1515                                 struct smbXsrv_session **session)
1516 {
1517         struct smbXsrv_session_table *table = conn->session_table;
1518         uint32_t local_id = session_id & UINT32_MAX;
1519         uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
1520
1521         if (local_zeros != 0) {
1522                 return NT_STATUS_USER_SESSION_DELETED;
1523         }
1524
1525         return smbXsrv_session_local_lookup(table, local_id, now, session);
1526 }
1527
1528 struct smbXsrv_session_global_traverse_state {
1529         int (*fn)(struct smbXsrv_session_global0 *, void *);
1530         void *private_data;
1531 };
1532
1533 static int smbXsrv_session_global_traverse_fn(struct db_record *rec, void *data)
1534 {
1535         int ret = -1;
1536         struct smbXsrv_session_global_traverse_state *state =
1537                 (struct smbXsrv_session_global_traverse_state*)data;
1538         TDB_DATA key = dbwrap_record_get_key(rec);
1539         TDB_DATA val = dbwrap_record_get_value(rec);
1540         DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
1541         struct smbXsrv_session_globalB global_blob;
1542         enum ndr_err_code ndr_err;
1543         TALLOC_CTX *frame = talloc_stackframe();
1544
1545         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
1546                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
1547         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1548                 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1549                          "key '%s' ndr_pull_struct_blob - %s\n",
1550                          hex_encode_talloc(frame, key.dptr, key.dsize),
1551                          ndr_errstr(ndr_err)));
1552                 goto done;
1553         }
1554
1555         if (global_blob.version != SMBXSRV_VERSION_0) {
1556                 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1557                          "key '%s' unsuported version - %d\n",
1558                          hex_encode_talloc(frame, key.dptr, key.dsize),
1559                          (int)global_blob.version));
1560                 goto done;
1561         }
1562
1563         global_blob.info.info0->db_rec = rec;
1564         ret = state->fn(global_blob.info.info0, state->private_data);
1565 done:
1566         TALLOC_FREE(frame);
1567         return ret;
1568 }
1569
1570 NTSTATUS smbXsrv_session_global_traverse(
1571                         int (*fn)(struct smbXsrv_session_global0 *, void *),
1572                         void *private_data)
1573 {
1574
1575         NTSTATUS status;
1576         int count = 0;
1577         struct smbXsrv_session_global_traverse_state state = {
1578                 .fn = fn,
1579                 .private_data = private_data,
1580         };
1581
1582         become_root();
1583         status = smbXsrv_session_global_init();
1584         if (!NT_STATUS_IS_OK(status)) {
1585                 unbecome_root();
1586                 DEBUG(0, ("Failed to initialize session_global: %s\n",
1587                           nt_errstr(status)));
1588                 return status;
1589         }
1590
1591         status = dbwrap_traverse_read(smbXsrv_session_global_db_ctx,
1592                                       smbXsrv_session_global_traverse_fn,
1593                                       &state,
1594                                       &count);
1595         unbecome_root();
1596
1597         return status;
1598 }