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