s3:smbd: move smbXsrv_{session,tcon,open} tables to smbXsrv_client
[ambi/samba-autobuild/.git] / source3 / smbd / smbXsrv_open.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 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 "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_rbt.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "../libcli/security/security.h"
29 #include "messages.h"
30 #include "lib/util/util_tdb.h"
31 #include "librpc/gen_ndr/ndr_smbXsrv.h"
32 #include <ccan/hash/hash.h>
33 #include "serverid.h"
34
35 struct smbXsrv_open_table {
36         struct {
37                 struct db_context *db_ctx;
38                 uint32_t lowest_id;
39                 uint32_t highest_id;
40                 uint32_t max_opens;
41                 uint32_t num_opens;
42         } local;
43         struct {
44                 struct db_context *db_ctx;
45         } global;
46 };
47
48 static struct db_context *smbXsrv_open_global_db_ctx = NULL;
49
50 NTSTATUS smbXsrv_open_global_init(void)
51 {
52         const char *global_path = NULL;
53         struct db_context *db_ctx = NULL;
54
55         if (smbXsrv_open_global_db_ctx != NULL) {
56                 return NT_STATUS_OK;
57         }
58
59         global_path = lock_path("smbXsrv_open_global.tdb");
60
61         db_ctx = db_open(NULL, global_path,
62                          0, /* hash_size */
63                          TDB_DEFAULT |
64                          TDB_CLEAR_IF_FIRST |
65                          TDB_INCOMPATIBLE_HASH,
66                          O_RDWR | O_CREAT, 0600,
67                          DBWRAP_LOCK_ORDER_1,
68                          DBWRAP_FLAG_NONE);
69         if (db_ctx == NULL) {
70                 NTSTATUS status;
71
72                 status = map_nt_error_from_unix_common(errno);
73
74                 return status;
75         }
76
77         smbXsrv_open_global_db_ctx = db_ctx;
78
79         return NT_STATUS_OK;
80 }
81
82 /*
83  * NOTE:
84  * We need to store the keys in big endian so that dbwrap_rbt's memcmp
85  * has the same result as integer comparison between the uint32_t
86  * values.
87  *
88  * TODO: implement string based key
89  */
90
91 #define SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
92
93 static TDB_DATA smbXsrv_open_global_id_to_key(uint32_t id,
94                                               uint8_t *key_buf)
95 {
96         TDB_DATA key;
97
98         RSIVAL(key_buf, 0, id);
99
100         key = make_tdb_data(key_buf, SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE);
101
102         return key;
103 }
104
105 #if 0
106 static NTSTATUS smbXsrv_open_global_key_to_id(TDB_DATA key, uint32_t *id)
107 {
108         if (id == NULL) {
109                 return NT_STATUS_INVALID_PARAMETER;
110         }
111
112         if (key.dsize != SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE) {
113                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
114         }
115
116         *id = RIVAL(key.dptr, 0);
117
118         return NT_STATUS_OK;
119 }
120 #endif
121
122 #define SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
123
124 static TDB_DATA smbXsrv_open_local_id_to_key(uint32_t id,
125                                              uint8_t *key_buf)
126 {
127         TDB_DATA key;
128
129         RSIVAL(key_buf, 0, id);
130
131         key = make_tdb_data(key_buf, SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE);
132
133         return key;
134 }
135
136 static NTSTATUS smbXsrv_open_local_key_to_id(TDB_DATA key, uint32_t *id)
137 {
138         if (id == NULL) {
139                 return NT_STATUS_INVALID_PARAMETER;
140         }
141
142         if (key.dsize != SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE) {
143                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
144         }
145
146         *id = RIVAL(key.dptr, 0);
147
148         return NT_STATUS_OK;
149 }
150
151 static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
152                                         uint32_t lowest_id,
153                                         uint32_t highest_id,
154                                         uint32_t max_opens)
155 {
156         struct smbXsrv_client *client = conn->client;
157         struct smbXsrv_open_table *table;
158         NTSTATUS status;
159         uint64_t max_range;
160
161         if (lowest_id > highest_id) {
162                 return NT_STATUS_INTERNAL_ERROR;
163         }
164
165         max_range = highest_id;
166         max_range -= lowest_id;
167         max_range += 1;
168
169         if (max_opens > max_range) {
170                 return NT_STATUS_INTERNAL_ERROR;
171         }
172
173         table = talloc_zero(client, struct smbXsrv_open_table);
174         if (table == NULL) {
175                 return NT_STATUS_NO_MEMORY;
176         }
177
178         table->local.db_ctx = db_open_rbt(table);
179         if (table->local.db_ctx == NULL) {
180                 TALLOC_FREE(table);
181                 return NT_STATUS_NO_MEMORY;
182         }
183         table->local.lowest_id = lowest_id;
184         table->local.highest_id = highest_id;
185         table->local.max_opens = max_opens;
186
187         status = smbXsrv_open_global_init();
188         if (!NT_STATUS_IS_OK(status)) {
189                 TALLOC_FREE(table);
190                 return status;
191         }
192
193         table->global.db_ctx = smbXsrv_open_global_db_ctx;
194
195         client->open_table = table;
196         return NT_STATUS_OK;
197 }
198
199 struct smbXsrv_open_local_allocate_state {
200         const uint32_t lowest_id;
201         const uint32_t highest_id;
202         uint32_t last_id;
203         uint32_t useable_id;
204         NTSTATUS status;
205 };
206
207 static int smbXsrv_open_local_allocate_traverse(struct db_record *rec,
208                                                    void *private_data)
209 {
210         struct smbXsrv_open_local_allocate_state *state =
211                 (struct smbXsrv_open_local_allocate_state *)private_data;
212         TDB_DATA key = dbwrap_record_get_key(rec);
213         uint32_t id = 0;
214         NTSTATUS status;
215
216         status = smbXsrv_open_local_key_to_id(key, &id);
217         if (!NT_STATUS_IS_OK(status)) {
218                 state->status = status;
219                 return -1;
220         }
221
222         if (id <= state->last_id) {
223                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
224                 return -1;
225         }
226         state->last_id = id;
227
228         if (id > state->useable_id) {
229                 state->status = NT_STATUS_OK;
230                 return -1;
231         }
232
233         if (state->useable_id == state->highest_id) {
234                 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
235                 return -1;
236         }
237
238         state->useable_id +=1;
239         return 0;
240 }
241
242 static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db,
243                                                uint32_t lowest_id,
244                                                uint32_t highest_id,
245                                                TALLOC_CTX *mem_ctx,
246                                                struct db_record **_rec,
247                                                uint32_t *_id)
248 {
249         struct smbXsrv_open_local_allocate_state state = {
250                 .lowest_id = lowest_id,
251                 .highest_id = highest_id,
252                 .last_id = 0,
253                 .useable_id = lowest_id,
254                 .status = NT_STATUS_INTERNAL_ERROR,
255         };
256         uint32_t i;
257         uint32_t range;
258         NTSTATUS status;
259         int count = 0;
260
261         *_rec = NULL;
262         *_id = 0;
263
264         if (lowest_id > highest_id) {
265                 return NT_STATUS_INSUFFICIENT_RESOURCES;
266         }
267
268         /*
269          * first we try randomly
270          */
271         range = (highest_id - lowest_id) + 1;
272
273         for (i = 0; i < (range / 2); i++) {
274                 uint32_t id;
275                 uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
276                 TDB_DATA key;
277                 TDB_DATA val;
278                 struct db_record *rec = NULL;
279
280                 id = generate_random() % range;
281                 id += lowest_id;
282
283                 if (id < lowest_id) {
284                         id = lowest_id;
285                 }
286                 if (id > highest_id) {
287                         id = highest_id;
288                 }
289
290                 key = smbXsrv_open_local_id_to_key(id, key_buf);
291
292                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
293                 if (rec == NULL) {
294                         return NT_STATUS_INSUFFICIENT_RESOURCES;
295                 }
296
297                 val = dbwrap_record_get_value(rec);
298                 if (val.dsize != 0) {
299                         TALLOC_FREE(rec);
300                         continue;
301                 }
302
303                 *_rec = rec;
304                 *_id = id;
305                 return NT_STATUS_OK;
306         }
307
308         /*
309          * if the range is almost full,
310          * we traverse the whole table
311          * (this relies on sorted behavior of dbwrap_rbt)
312          */
313         status = dbwrap_traverse_read(db, smbXsrv_open_local_allocate_traverse,
314                                       &state, &count);
315         if (NT_STATUS_IS_OK(status)) {
316                 if (NT_STATUS_IS_OK(state.status)) {
317                         return NT_STATUS_INTERNAL_ERROR;
318                 }
319
320                 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
321                         return state.status;
322                 }
323
324                 if (state.useable_id <= state.highest_id) {
325                         state.status = NT_STATUS_OK;
326                 } else {
327                         return NT_STATUS_INSUFFICIENT_RESOURCES;
328                 }
329         } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
330                 /*
331                  * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
332                  *
333                  * If we get anything else it is an error, because it
334                  * means we did not manage to find a free slot in
335                  * the db.
336                  */
337                 return NT_STATUS_INSUFFICIENT_RESOURCES;
338         }
339
340         if (NT_STATUS_IS_OK(state.status)) {
341                 uint32_t id;
342                 uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
343                 TDB_DATA key;
344                 TDB_DATA val;
345                 struct db_record *rec = NULL;
346
347                 id = state.useable_id;
348
349                 key = smbXsrv_open_local_id_to_key(id, key_buf);
350
351                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
352                 if (rec == NULL) {
353                         return NT_STATUS_INSUFFICIENT_RESOURCES;
354                 }
355
356                 val = dbwrap_record_get_value(rec);
357                 if (val.dsize != 0) {
358                         TALLOC_FREE(rec);
359                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
360                 }
361
362                 *_rec = rec;
363                 *_id = id;
364                 return NT_STATUS_OK;
365         }
366
367         return state.status;
368 }
369
370 struct smbXsrv_open_local_fetch_state {
371         struct smbXsrv_open *op;
372         NTSTATUS status;
373 };
374
375 static void smbXsrv_open_local_fetch_parser(TDB_DATA key, TDB_DATA data,
376                                             void *private_data)
377 {
378         struct smbXsrv_open_local_fetch_state *state =
379                 (struct smbXsrv_open_local_fetch_state *)private_data;
380         void *ptr;
381
382         if (data.dsize != sizeof(ptr)) {
383                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
384                 return;
385         }
386
387         memcpy(&ptr, data.dptr, data.dsize);
388         state->op = talloc_get_type_abort(ptr, struct smbXsrv_open);
389         state->status = NT_STATUS_OK;
390 }
391
392 static NTSTATUS smbXsrv_open_local_lookup(struct smbXsrv_open_table *table,
393                                           uint32_t open_local_id,
394                                           uint32_t open_global_id,
395                                           NTTIME now,
396                                           struct smbXsrv_open **_open)
397 {
398         struct smbXsrv_open_local_fetch_state state = {
399                 .op = NULL,
400                 .status = NT_STATUS_INTERNAL_ERROR,
401         };
402         uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
403         TDB_DATA key;
404         NTSTATUS status;
405
406         *_open = NULL;
407
408         if (open_local_id == 0) {
409                 return NT_STATUS_FILE_CLOSED;
410         }
411
412         if (table == NULL) {
413                 /* this might happen before the end of negprot */
414                 return NT_STATUS_FILE_CLOSED;
415         }
416
417         if (table->local.db_ctx == NULL) {
418                 return NT_STATUS_INTERNAL_ERROR;
419         }
420
421         key = smbXsrv_open_local_id_to_key(open_local_id, key_buf);
422
423         status = dbwrap_parse_record(table->local.db_ctx, key,
424                                      smbXsrv_open_local_fetch_parser,
425                                      &state);
426         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
427                 return NT_STATUS_FILE_CLOSED;
428         } else if (!NT_STATUS_IS_OK(status)) {
429                 return status;
430         }
431         if (!NT_STATUS_IS_OK(state.status)) {
432                 return state.status;
433         }
434
435         if (NT_STATUS_EQUAL(state.op->status, NT_STATUS_FILE_CLOSED)) {
436                 return NT_STATUS_FILE_CLOSED;
437         }
438
439         if (open_global_id == 0) {
440                 /* make the global check a no-op for SMB1 */
441                 open_global_id = state.op->global->open_global_id;
442         }
443
444         if (state.op->global->open_global_id != open_global_id) {
445                 return NT_STATUS_FILE_CLOSED;
446         }
447
448         if (now != 0) {
449                 state.op->idle_time = now;
450         }
451
452         *_open = state.op;
453         return state.op->status;
454 }
455
456 static int smbXsrv_open_global_destructor(struct smbXsrv_open_global0 *global)
457 {
458         return 0;
459 }
460
461 static void smbXsrv_open_global_verify_record(struct db_record *db_rec,
462                                         bool *is_free,
463                                         bool *was_free,
464                                         TALLOC_CTX *mem_ctx,
465                                         struct smbXsrv_open_global0 **_g);
466
467 static NTSTATUS smbXsrv_open_global_allocate(struct db_context *db,
468                                         TALLOC_CTX *mem_ctx,
469                                         struct smbXsrv_open_global0 **_global)
470 {
471         uint32_t i;
472         struct smbXsrv_open_global0 *global = NULL;
473         uint32_t last_free = 0;
474         const uint32_t min_tries = 3;
475
476         *_global = NULL;
477
478         global = talloc_zero(mem_ctx, struct smbXsrv_open_global0);
479         if (global == NULL) {
480                 return NT_STATUS_NO_MEMORY;
481         }
482         talloc_set_destructor(global, smbXsrv_open_global_destructor);
483
484         /*
485          * Here we just randomly try the whole 32-bit space
486          *
487          * We use just 32-bit, because we want to reuse the
488          * ID for SRVSVC.
489          */
490         for (i = 0; i < UINT32_MAX; i++) {
491                 bool is_free = false;
492                 bool was_free = false;
493                 uint32_t id;
494                 uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
495                 TDB_DATA key;
496
497                 if (i >= min_tries && last_free != 0) {
498                         id = last_free;
499                 } else {
500                         id = generate_random();
501                 }
502                 if (id == 0) {
503                         id++;
504                 }
505                 if (id == UINT32_MAX) {
506                         id--;
507                 }
508
509                 key = smbXsrv_open_global_id_to_key(id, key_buf);
510
511                 global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
512                 if (global->db_rec == NULL) {
513                         talloc_free(global);
514                         return NT_STATUS_INSUFFICIENT_RESOURCES;
515                 }
516
517                 smbXsrv_open_global_verify_record(global->db_rec,
518                                                   &is_free,
519                                                   &was_free,
520                                                   NULL, NULL);
521
522                 if (!is_free) {
523                         TALLOC_FREE(global->db_rec);
524                         continue;
525                 }
526
527                 if (!was_free && i < min_tries) {
528                         /*
529                          * The session_id is free now,
530                          * but was not free before.
531                          *
532                          * This happens if a smbd crashed
533                          * and did not cleanup the record.
534                          *
535                          * If this is one of our first tries,
536                          * then we try to find a real free one.
537                          */
538                         if (last_free == 0) {
539                                 last_free = id;
540                         }
541                         TALLOC_FREE(global->db_rec);
542                         continue;
543                 }
544
545                 global->open_global_id = id;
546
547                 *_global = global;
548                 return NT_STATUS_OK;
549         }
550
551         /* should not be reached */
552         talloc_free(global);
553         return NT_STATUS_INTERNAL_ERROR;
554 }
555
556 static void smbXsrv_open_global_verify_record(struct db_record *db_rec,
557                                         bool *is_free,
558                                         bool *was_free,
559                                         TALLOC_CTX *mem_ctx,
560                                         struct smbXsrv_open_global0 **_g)
561 {
562         TDB_DATA key;
563         TDB_DATA val;
564         DATA_BLOB blob;
565         struct smbXsrv_open_globalB global_blob;
566         enum ndr_err_code ndr_err;
567         struct smbXsrv_open_global0 *global = NULL;
568         bool exists;
569         TALLOC_CTX *frame = talloc_stackframe();
570
571         *is_free = false;
572
573         if (was_free) {
574                 *was_free = false;
575         }
576         if (_g) {
577                 *_g = NULL;
578         }
579
580         key = dbwrap_record_get_key(db_rec);
581
582         val = dbwrap_record_get_value(db_rec);
583         if (val.dsize == 0) {
584                 DEBUG(10, ("%s: empty value\n", __func__));
585                 TALLOC_FREE(frame);
586                 *is_free = true;
587                 if (was_free) {
588                         *was_free = true;
589                 }
590                 return;
591         }
592
593         blob = data_blob_const(val.dptr, val.dsize);
594
595         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
596                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB);
597         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
598                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
599                 DEBUG(1,("smbXsrv_open_global_verify_record: "
600                          "key '%s' ndr_pull_struct_blob - %s\n",
601                          hex_encode_talloc(frame, key.dptr, key.dsize),
602                          nt_errstr(status)));
603                 TALLOC_FREE(frame);
604                 return;
605         }
606
607         DEBUG(10,("smbXsrv_open_global_verify_record\n"));
608         if (CHECK_DEBUGLVL(10)) {
609                 NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
610         }
611
612         if (global_blob.version != SMBXSRV_VERSION_0) {
613                 DEBUG(0,("smbXsrv_open_global_verify_record: "
614                          "key '%s' use unsupported version %u\n",
615                          hex_encode_talloc(frame, key.dptr, key.dsize),
616                          global_blob.version));
617                 NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
618                 TALLOC_FREE(frame);
619                 return;
620         }
621
622         global = global_blob.info.info0;
623
624         if (server_id_is_disconnected(&global->server_id)) {
625                 exists = true;
626         } else {
627                 exists = serverid_exists(&global->server_id);
628         }
629         if (!exists) {
630                 DEBUG(2,("smbXsrv_open_global_verify_record: "
631                          "key '%s' server_id %s does not exist.\n",
632                          hex_encode_talloc(frame, key.dptr, key.dsize),
633                          server_id_str(frame, &global->server_id)));
634                 if (CHECK_DEBUGLVL(2)) {
635                         NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
636                 }
637                 TALLOC_FREE(frame);
638                 dbwrap_record_delete(db_rec);
639                 *is_free = true;
640                 return;
641         }
642
643         if (_g) {
644                 *_g = talloc_move(mem_ctx, &global);
645         }
646         TALLOC_FREE(frame);
647 }
648
649 static NTSTATUS smbXsrv_open_global_store(struct smbXsrv_open_global0 *global)
650 {
651         struct smbXsrv_open_globalB global_blob;
652         DATA_BLOB blob = data_blob_null;
653         TDB_DATA key;
654         TDB_DATA val;
655         NTSTATUS status;
656         enum ndr_err_code ndr_err;
657
658         /*
659          * TODO: if we use other versions than '0'
660          * we would add glue code here, that would be able to
661          * store the information in the old format.
662          */
663
664         if (global->db_rec == NULL) {
665                 return NT_STATUS_INTERNAL_ERROR;
666         }
667
668         key = dbwrap_record_get_key(global->db_rec);
669         val = dbwrap_record_get_value(global->db_rec);
670
671         ZERO_STRUCT(global_blob);
672         global_blob.version = smbXsrv_version_global_current();
673         if (val.dsize >= 8) {
674                 global_blob.seqnum = IVAL(val.dptr, 4);
675         }
676         global_blob.seqnum += 1;
677         global_blob.info.info0 = global;
678
679         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
680                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_globalB);
681         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
682                 status = ndr_map_error2ntstatus(ndr_err);
683                 DEBUG(1,("smbXsrv_open_global_store: key '%s' ndr_push - %s\n",
684                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
685                          nt_errstr(status)));
686                 TALLOC_FREE(global->db_rec);
687                 return status;
688         }
689
690         val = make_tdb_data(blob.data, blob.length);
691         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
692         if (!NT_STATUS_IS_OK(status)) {
693                 DEBUG(1,("smbXsrv_open_global_store: key '%s' store - %s\n",
694                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
695                          nt_errstr(status)));
696                 TALLOC_FREE(global->db_rec);
697                 return status;
698         }
699
700         if (CHECK_DEBUGLVL(10)) {
701                 DEBUG(10,("smbXsrv_open_global_store: key '%s' stored\n",
702                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
703                 NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
704         }
705
706         TALLOC_FREE(global->db_rec);
707
708         return NT_STATUS_OK;
709 }
710
711 static NTSTATUS smbXsrv_open_global_lookup(struct smbXsrv_open_table *table,
712                                            uint32_t open_global_id,
713                                            TALLOC_CTX *mem_ctx,
714                                            struct smbXsrv_open_global0 **_global)
715 {
716         TDB_DATA key;
717         uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
718         struct db_record *global_rec = NULL;
719         bool is_free = false;
720
721         *_global = NULL;
722
723         if (table->global.db_ctx == NULL) {
724                 return NT_STATUS_INTERNAL_ERROR;
725         }
726
727         key = smbXsrv_open_global_id_to_key(open_global_id, key_buf);
728
729         global_rec = dbwrap_fetch_locked(table->global.db_ctx, mem_ctx, key);
730         if (global_rec == NULL) {
731                 DEBUG(0, ("smbXsrv_open_global_lookup(0x%08x): "
732                           "Failed to lock global key '%s'\n",
733                           open_global_id,
734                           hex_encode_talloc(talloc_tos(), key.dptr,
735                                             key.dsize)));
736                 return NT_STATUS_INTERNAL_DB_ERROR;
737         }
738
739         smbXsrv_open_global_verify_record(global_rec,
740                                           &is_free,
741                                           NULL,
742                                           mem_ctx,
743                                           _global);
744         if (is_free) {
745                 DEBUG(10, ("%s: is_free=true\n", __func__));
746                 talloc_free(global_rec);
747                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
748         }
749
750         (*_global)->db_rec = talloc_move(*_global, &global_rec);
751
752         talloc_set_destructor(*_global, smbXsrv_open_global_destructor);
753
754         return NT_STATUS_OK;
755 }
756
757 static int smbXsrv_open_destructor(struct smbXsrv_open *op)
758 {
759         NTSTATUS status;
760
761         status = smbXsrv_open_close(op, 0);
762         if (!NT_STATUS_IS_OK(status)) {
763                 DEBUG(0, ("smbXsrv_open_destructor: "
764                           "smbXsrv_open_close() failed - %s\n",
765                           nt_errstr(status)));
766         }
767
768         TALLOC_FREE(op->global);
769
770         return 0;
771 }
772
773 NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn,
774                              struct auth_session_info *session_info,
775                              NTTIME now,
776                              struct smbXsrv_open **_open)
777 {
778         struct smbXsrv_open_table *table = conn->client->open_table;
779         struct db_record *local_rec = NULL;
780         struct smbXsrv_open *op = NULL;
781         void *ptr = NULL;
782         TDB_DATA val;
783         struct smbXsrv_open_global0 *global = NULL;
784         NTSTATUS status;
785         struct dom_sid *current_sid = NULL;
786         struct security_token *current_token = NULL;
787
788         if (session_info == NULL) {
789                 return NT_STATUS_INVALID_HANDLE;
790         }
791         current_token = session_info->security_token;
792
793         if (current_token == NULL) {
794                 return NT_STATUS_INVALID_HANDLE;
795         }
796
797         if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
798                 current_sid = &current_token->sids[PRIMARY_USER_SID_INDEX];
799         }
800
801         if (current_sid == NULL) {
802                 return NT_STATUS_INVALID_HANDLE;
803         }
804
805         if (table->local.num_opens >= table->local.max_opens) {
806                 return NT_STATUS_INSUFFICIENT_RESOURCES;
807         }
808
809         op = talloc_zero(table, struct smbXsrv_open);
810         if (op == NULL) {
811                 return NT_STATUS_NO_MEMORY;
812         }
813         op->table = table;
814         op->status = NT_STATUS_OK; /* TODO: start with INTERNAL_ERROR */
815         op->idle_time = now;
816
817         status = smbXsrv_open_global_allocate(table->global.db_ctx,
818                                               op, &global);
819         if (!NT_STATUS_IS_OK(status)) {
820                 TALLOC_FREE(op);
821                 return status;
822         }
823         op->global = global;
824
825         status = smbXsrv_open_local_allocate_id(table->local.db_ctx,
826                                                 table->local.lowest_id,
827                                                 table->local.highest_id,
828                                                 op,
829                                                 &local_rec,
830                                                 &op->local_id);
831         if (!NT_STATUS_IS_OK(status)) {
832                 TALLOC_FREE(op);
833                 return status;
834         }
835
836         global->open_persistent_id = global->open_global_id;
837         global->open_volatile_id = op->local_id;
838
839         global->server_id = messaging_server_id(conn->msg_ctx);
840         global->open_time = now;
841         global->open_owner = *current_sid;
842         if (conn->protocol >= PROTOCOL_SMB2_10) {
843                 global->client_guid = conn->smb2.client.guid;
844         }
845
846         ptr = op;
847         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
848         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
849         TALLOC_FREE(local_rec);
850         if (!NT_STATUS_IS_OK(status)) {
851                 TALLOC_FREE(op);
852                 return status;
853         }
854         table->local.num_opens += 1;
855
856         talloc_set_destructor(op, smbXsrv_open_destructor);
857
858         status = smbXsrv_open_global_store(global);
859         if (!NT_STATUS_IS_OK(status)) {
860                 DEBUG(0,("smbXsrv_open_create: "
861                          "global_id (0x%08x) store failed - %s\n",
862                          op->global->open_global_id,
863                          nt_errstr(status)));
864                 TALLOC_FREE(op);
865                 return status;
866         }
867
868         if (CHECK_DEBUGLVL(10)) {
869                 struct smbXsrv_openB open_blob;
870
871                 ZERO_STRUCT(open_blob);
872                 open_blob.version = SMBXSRV_VERSION_0;
873                 open_blob.info.info0 = op;
874
875                 DEBUG(10,("smbXsrv_open_create: global_id (0x%08x) stored\n",
876                          op->global->open_global_id));
877                 NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
878         }
879
880         *_open = op;
881         return NT_STATUS_OK;
882 }
883
884 uint32_t smbXsrv_open_hash(struct smbXsrv_open *_open)
885 {
886         uint8_t buf[8+8+8];
887         uint32_t ret;
888
889         SBVAL(buf,  0, _open->global->open_persistent_id);
890         SBVAL(buf,  8, _open->global->open_volatile_id);
891         SBVAL(buf, 16, _open->global->open_time);
892
893         ret = hash(buf, sizeof(buf), 0);
894
895         if (ret == 0) {
896                 ret = 1;
897         }
898
899         return ret;
900 }
901
902 NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op)
903 {
904         struct smbXsrv_open_table *table = op->table;
905         NTSTATUS status;
906         uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
907         TDB_DATA key;
908
909         if (op->global->db_rec != NULL) {
910                 DEBUG(0, ("smbXsrv_open_update(0x%08x): "
911                           "Called with db_rec != NULL'\n",
912                           op->global->open_global_id));
913                 return NT_STATUS_INTERNAL_ERROR;
914         }
915
916         key = smbXsrv_open_global_id_to_key(op->global->open_global_id,
917                                             key_buf);
918
919         op->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
920                                                  op->global, key);
921         if (op->global->db_rec == NULL) {
922                 DEBUG(0, ("smbXsrv_open_update(0x%08x): "
923                           "Failed to lock global key '%s'\n",
924                           op->global->open_global_id,
925                           hex_encode_talloc(talloc_tos(), key.dptr,
926                                             key.dsize)));
927                 return NT_STATUS_INTERNAL_DB_ERROR;
928         }
929
930         status = smbXsrv_open_global_store(op->global);
931         if (!NT_STATUS_IS_OK(status)) {
932                 DEBUG(0,("smbXsrv_open_update: "
933                          "global_id (0x%08x) store failed - %s\n",
934                          op->global->open_global_id,
935                          nt_errstr(status)));
936                 return status;
937         }
938
939         if (CHECK_DEBUGLVL(10)) {
940                 struct smbXsrv_openB open_blob;
941
942                 ZERO_STRUCT(open_blob);
943                 open_blob.version = SMBXSRV_VERSION_0;
944                 open_blob.info.info0 = op;
945
946                 DEBUG(10,("smbXsrv_open_update: global_id (0x%08x) stored\n",
947                           op->global->open_global_id));
948                 NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
949         }
950
951         return NT_STATUS_OK;
952 }
953
954 NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
955 {
956         struct smbXsrv_open_table *table;
957         struct db_record *local_rec = NULL;
958         struct db_record *global_rec = NULL;
959         NTSTATUS status;
960         NTSTATUS error = NT_STATUS_OK;
961
962         if (op->table == NULL) {
963                 return NT_STATUS_OK;
964         }
965
966         table = op->table;
967         op->table = NULL;
968
969         op->status = NT_STATUS_FILE_CLOSED;
970         op->global->disconnect_time = now;
971         server_id_set_disconnected(&op->global->server_id);
972
973         global_rec = op->global->db_rec;
974         op->global->db_rec = NULL;
975         if (global_rec == NULL) {
976                 uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
977                 TDB_DATA key;
978
979                 key = smbXsrv_open_global_id_to_key(
980                                                 op->global->open_global_id,
981                                                 key_buf);
982
983                 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
984                                                  op->global, key);
985                 if (global_rec == NULL) {
986                         DEBUG(0, ("smbXsrv_open_close(0x%08x): "
987                                   "Failed to lock global key '%s'\n",
988                                   op->global->open_global_id,
989                                   hex_encode_talloc(global_rec, key.dptr,
990                                                     key.dsize)));
991                         error = NT_STATUS_INTERNAL_ERROR;
992                 }
993         }
994
995         if (global_rec != NULL && op->global->durable) {
996                 /*
997                  * If it is a durable open we need to update the global part
998                  * instead of deleting it
999                  */
1000                 op->global->db_rec = global_rec;
1001                 status = smbXsrv_open_global_store(op->global);
1002                 if (NT_STATUS_IS_OK(status)) {
1003                         /*
1004                          * smbXsrv_open_global_store does the free
1005                          * of op->global->db_rec
1006                          */
1007                         global_rec = NULL;
1008                 }
1009                 if (!NT_STATUS_IS_OK(status)) {
1010                         DEBUG(0,("smbXsrv_open_close(0x%08x)"
1011                                  "smbXsrv_open_global_store() failed - %s\n",
1012                                  op->global->open_global_id,
1013                                  nt_errstr(status)));
1014                         error = status;
1015                 }
1016
1017                 if (NT_STATUS_IS_OK(status) && CHECK_DEBUGLVL(10)) {
1018                         struct smbXsrv_openB open_blob;
1019
1020                         ZERO_STRUCT(open_blob);
1021                         open_blob.version = SMBXSRV_VERSION_0;
1022                         open_blob.info.info0 = op;
1023
1024                         DEBUG(10,("smbXsrv_open_close(0x%08x): "
1025                                   "stored disconnect\n",
1026                                   op->global->open_global_id));
1027                         NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
1028                 }
1029         }
1030
1031         if (global_rec != NULL) {
1032                 status = dbwrap_record_delete(global_rec);
1033                 if (!NT_STATUS_IS_OK(status)) {
1034                         TDB_DATA key = dbwrap_record_get_key(global_rec);
1035
1036                         DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1037                                   "failed to delete global key '%s': %s\n",
1038                                   op->global->open_global_id,
1039                                   hex_encode_talloc(global_rec, key.dptr,
1040                                                     key.dsize),
1041                                   nt_errstr(status)));
1042                         error = status;
1043                 }
1044         }
1045         TALLOC_FREE(global_rec);
1046
1047         local_rec = op->db_rec;
1048         if (local_rec == NULL) {
1049                 uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
1050                 TDB_DATA key;
1051
1052                 key = smbXsrv_open_local_id_to_key(op->local_id, key_buf);
1053
1054                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
1055                                                 op, key);
1056                 if (local_rec == NULL) {
1057                         DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1058                                   "Failed to lock local key '%s'\n",
1059                                   op->global->open_global_id,
1060                                   hex_encode_talloc(local_rec, key.dptr,
1061                                                     key.dsize)));
1062                         error = NT_STATUS_INTERNAL_ERROR;
1063                 }
1064         }
1065
1066         if (local_rec != NULL) {
1067                 status = dbwrap_record_delete(local_rec);
1068                 if (!NT_STATUS_IS_OK(status)) {
1069                         TDB_DATA key = dbwrap_record_get_key(local_rec);
1070
1071                         DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1072                                   "failed to delete local key '%s': %s\n",
1073                                   op->global->open_global_id,
1074                                   hex_encode_talloc(local_rec, key.dptr,
1075                                                     key.dsize),
1076                                   nt_errstr(status)));
1077                         error = status;
1078                 }
1079                 table->local.num_opens -= 1;
1080         }
1081         if (op->db_rec == NULL) {
1082                 TALLOC_FREE(local_rec);
1083         }
1084         op->db_rec = NULL;
1085
1086         if (op->compat) {
1087                 op->compat->op = NULL;
1088                 file_free(NULL, op->compat);
1089                 op->compat = NULL;
1090         }
1091
1092         return error;
1093 }
1094
1095 NTSTATUS smb1srv_open_table_init(struct smbXsrv_connection *conn)
1096 {
1097         uint32_t max_opens;
1098
1099         /*
1100          * Allow a range from 1..65534.
1101          *
1102          * With real_max_open_files possible ids,
1103          * truncated to the SMB1 limit of 16-bit.
1104          *
1105          * 0 and 0xFFFF are no valid ids.
1106          */
1107         max_opens = conn->client->sconn->real_max_open_files;
1108         max_opens = MIN(max_opens, UINT16_MAX - 1);
1109
1110         return smbXsrv_open_table_init(conn, 1, UINT16_MAX - 1, max_opens);
1111 }
1112
1113 NTSTATUS smb1srv_open_lookup(struct smbXsrv_connection *conn,
1114                              uint16_t fnum, NTTIME now,
1115                              struct smbXsrv_open **_open)
1116 {
1117         struct smbXsrv_open_table *table = conn->client->open_table;
1118         uint32_t local_id = fnum;
1119         uint32_t global_id = 0;
1120
1121         return smbXsrv_open_local_lookup(table, local_id, global_id, now, _open);
1122 }
1123
1124 NTSTATUS smb2srv_open_table_init(struct smbXsrv_connection *conn)
1125 {
1126         uint32_t max_opens;
1127
1128         /*
1129          * Allow a range from 1..4294967294.
1130          *
1131          * With real_max_open_files possible ids,
1132          * truncated to 16-bit (the same as SMB1 for now).
1133          *
1134          * 0 and 0xFFFFFFFF are no valid ids.
1135          *
1136          * The usage of conn->sconn->real_max_open_files
1137          * is the reason that we use one open table per
1138          * transport connection (as we still have a 1:1 mapping
1139          * between process and transport connection).
1140          */
1141         max_opens = conn->client->sconn->real_max_open_files;
1142         max_opens = MIN(max_opens, UINT16_MAX - 1);
1143
1144         return smbXsrv_open_table_init(conn, 1, UINT32_MAX - 1, max_opens);
1145 }
1146
1147 NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn,
1148                              uint64_t persistent_id,
1149                              uint64_t volatile_id,
1150                              NTTIME now,
1151                              struct smbXsrv_open **_open)
1152 {
1153         struct smbXsrv_open_table *table = conn->client->open_table;
1154         uint32_t local_id = volatile_id & UINT32_MAX;
1155         uint64_t local_zeros = volatile_id & 0xFFFFFFFF00000000LLU;
1156         uint32_t global_id = persistent_id & UINT32_MAX;
1157         uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
1158
1159         if (local_zeros != 0) {
1160                 return NT_STATUS_FILE_CLOSED;
1161         }
1162
1163         if (global_zeros != 0) {
1164                 return NT_STATUS_FILE_CLOSED;
1165         }
1166
1167         if (global_id == 0) {
1168                 return NT_STATUS_FILE_CLOSED;
1169         }
1170
1171         return smbXsrv_open_local_lookup(table, local_id, global_id, now, _open);
1172 }
1173
1174 NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
1175                                struct auth_session_info *session_info,
1176                                uint64_t persistent_id,
1177                                const struct GUID *create_guid,
1178                                NTTIME now,
1179                                struct smbXsrv_open **_open)
1180 {
1181         struct smbXsrv_open_table *table = conn->client->open_table;
1182         struct db_record *local_rec = NULL;
1183         struct smbXsrv_open *op = NULL;
1184         void *ptr = NULL;
1185         TDB_DATA val;
1186         uint32_t global_id = persistent_id & UINT32_MAX;
1187         uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
1188         NTSTATUS status;
1189         struct security_token *current_token = NULL;
1190
1191         if (session_info == NULL) {
1192                 DEBUG(10, ("session_info=NULL\n"));
1193                 return NT_STATUS_INVALID_HANDLE;
1194         }
1195         current_token = session_info->security_token;
1196
1197         if (current_token == NULL) {
1198                 DEBUG(10, ("current_token=NULL\n"));
1199                 return NT_STATUS_INVALID_HANDLE;
1200         }
1201
1202         if (global_zeros != 0) {
1203                 DEBUG(10, ("global_zeros!=0\n"));
1204                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1205         }
1206
1207         op = talloc_zero(table, struct smbXsrv_open);
1208         if (op == NULL) {
1209                 return NT_STATUS_NO_MEMORY;
1210         }
1211         op->table = table;
1212
1213         status = smbXsrv_open_global_lookup(table, global_id, op, &op->global);
1214         if (!NT_STATUS_IS_OK(status)) {
1215                 TALLOC_FREE(op);
1216                 DEBUG(10, ("smbXsrv_open_global_lookup returned %s\n",
1217                            nt_errstr(status)));
1218                 return status;
1219         }
1220
1221         /*
1222          * If the provided create_guid is NULL, this means that
1223          * the reconnect request was a v1 request. In that case
1224          * we should skipt the create GUID verification, since
1225          * it is valid to v1-reconnect a v2-opened handle.
1226          */
1227         if ((create_guid != NULL) &&
1228             !GUID_equal(&op->global->create_guid, create_guid))
1229         {
1230                 TALLOC_FREE(op);
1231                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1232         }
1233
1234         if (!security_token_is_sid(current_token, &op->global->open_owner)) {
1235                 TALLOC_FREE(op);
1236                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1237         }
1238
1239         if (!op->global->durable) {
1240                 TALLOC_FREE(op);
1241                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1242         }
1243
1244         if (table->local.num_opens >= table->local.max_opens) {
1245                 TALLOC_FREE(op);
1246                 return NT_STATUS_INSUFFICIENT_RESOURCES;
1247         }
1248
1249         status = smbXsrv_open_local_allocate_id(table->local.db_ctx,
1250                                                 table->local.lowest_id,
1251                                                 table->local.highest_id,
1252                                                 op,
1253                                                 &local_rec,
1254                                                 &op->local_id);
1255         if (!NT_STATUS_IS_OK(status)) {
1256                 TALLOC_FREE(op);
1257                 return status;
1258         }
1259
1260         op->idle_time = now;
1261         op->status = NT_STATUS_FILE_CLOSED;
1262
1263         op->global->open_volatile_id = op->local_id;
1264         op->global->server_id = messaging_server_id(conn->msg_ctx);
1265
1266         ptr = op;
1267         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1268         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1269         TALLOC_FREE(local_rec);
1270         if (!NT_STATUS_IS_OK(status)) {
1271                 TALLOC_FREE(op);
1272                 return status;
1273         }
1274         table->local.num_opens += 1;
1275
1276         talloc_set_destructor(op, smbXsrv_open_destructor);
1277
1278         status = smbXsrv_open_global_store(op->global);
1279         if (!NT_STATUS_IS_OK(status)) {
1280                 TALLOC_FREE(op);
1281                 return status;
1282         }
1283
1284         if (CHECK_DEBUGLVL(10)) {
1285                 struct smbXsrv_openB open_blob;
1286
1287                 ZERO_STRUCT(open_blob);
1288                 open_blob.version = 0;
1289                 open_blob.info.info0 = op;
1290
1291                 DEBUG(10,("smbXsrv_open_recreate: global_id (0x%08x) stored\n",
1292                          op->global->open_global_id));
1293                 NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
1294         }
1295
1296         *_open = op;
1297         return NT_STATUS_OK;
1298 }
1299
1300
1301 static NTSTATUS smbXsrv_open_global_parse_record(TALLOC_CTX *mem_ctx,
1302                                                  struct db_record *rec,
1303                                                  struct smbXsrv_open_global0 **global)
1304 {
1305         TDB_DATA key = dbwrap_record_get_key(rec);
1306         TDB_DATA val = dbwrap_record_get_value(rec);
1307         DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
1308         struct smbXsrv_open_globalB global_blob;
1309         enum ndr_err_code ndr_err;
1310         NTSTATUS status;
1311         TALLOC_CTX *frame = talloc_stackframe();
1312
1313         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
1314                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB);
1315         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1316                 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
1317                          "key '%s' ndr_pull_struct_blob - %s\n",
1318                          hex_encode_talloc(frame, key.dptr, key.dsize),
1319                          ndr_errstr(ndr_err)));
1320                 status = ndr_map_error2ntstatus(ndr_err);
1321                 goto done;
1322         }
1323
1324         if (global_blob.version != SMBXSRV_VERSION_0) {
1325                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1326                 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
1327                          "key '%s' unsuported version - %d - %s\n",
1328                          hex_encode_talloc(frame, key.dptr, key.dsize),
1329                          (int)global_blob.version,
1330                          nt_errstr(status)));
1331                 goto done;
1332         }
1333
1334         *global = talloc_move(mem_ctx, &global_blob.info.info0);
1335         status = NT_STATUS_OK;
1336 done:
1337         talloc_free(frame);
1338         return status;
1339 }
1340
1341 struct smbXsrv_open_global_traverse_state {
1342         int (*fn)(struct smbXsrv_open_global0 *, void *);
1343         void *private_data;
1344 };
1345
1346 static int smbXsrv_open_global_traverse_fn(struct db_record *rec, void *data)
1347 {
1348         struct smbXsrv_open_global_traverse_state *state =
1349                 (struct smbXsrv_open_global_traverse_state*)data;
1350         struct smbXsrv_open_global0 *global = NULL;
1351         NTSTATUS status;
1352         int ret = -1;
1353
1354         status = smbXsrv_open_global_parse_record(talloc_tos(), rec, &global);
1355         if (!NT_STATUS_IS_OK(status)) {
1356                 return -1;
1357         }
1358
1359         global->db_rec = rec;
1360         ret = state->fn(global, state->private_data);
1361         talloc_free(global);
1362         return ret;
1363 }
1364
1365 NTSTATUS smbXsrv_open_global_traverse(
1366                         int (*fn)(struct smbXsrv_open_global0 *, void *),
1367                         void *private_data)
1368 {
1369
1370         NTSTATUS status;
1371         int count = 0;
1372         struct smbXsrv_open_global_traverse_state state = {
1373                 .fn = fn,
1374                 .private_data = private_data,
1375         };
1376
1377         become_root();
1378         status = smbXsrv_open_global_init();
1379         if (!NT_STATUS_IS_OK(status)) {
1380                 unbecome_root();
1381                 DEBUG(0, ("Failed to initialize open_global: %s\n",
1382                           nt_errstr(status)));
1383                 return status;
1384         }
1385
1386         status = dbwrap_traverse_read(smbXsrv_open_global_db_ctx,
1387                                       smbXsrv_open_global_traverse_fn,
1388                                       &state,
1389                                       &count);
1390         unbecome_root();
1391
1392         return status;
1393 }
1394
1395 NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id)
1396 {
1397         NTSTATUS status = NT_STATUS_OK;
1398         TALLOC_CTX *frame = talloc_stackframe();
1399         struct smbXsrv_open_global0 *op = NULL;
1400         uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
1401         TDB_DATA key;
1402         TDB_DATA val;
1403         struct db_record *rec;
1404         bool delete_open = false;
1405         uint32_t global_id = persistent_id & UINT32_MAX;
1406
1407         key = smbXsrv_open_global_id_to_key(global_id, key_buf);
1408         rec = dbwrap_fetch_locked(smbXsrv_open_global_db_ctx, frame, key);
1409         if (rec == NULL) {
1410                 status = NT_STATUS_NOT_FOUND;
1411                 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1412                           "failed to fetch record from %s - %s\n",
1413                            global_id, dbwrap_name(smbXsrv_open_global_db_ctx),
1414                            nt_errstr(status)));
1415                 goto done;
1416         }
1417
1418         val = dbwrap_record_get_value(rec);
1419         if (val.dsize == 0) {
1420                 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1421                           "empty record in %s, skipping...\n",
1422                            global_id, dbwrap_name(smbXsrv_open_global_db_ctx)));
1423                 goto done;
1424         }
1425
1426         status = smbXsrv_open_global_parse_record(talloc_tos(), rec, &op);
1427         if (!NT_STATUS_IS_OK(status)) {
1428                 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1429                           "failed to read record: %s\n",
1430                           global_id, nt_errstr(status)));
1431                 goto done;
1432         }
1433
1434         if (server_id_is_disconnected(&op->server_id)) {
1435                 struct timeval now, disconnect_time;
1436                 int64_t tdiff;
1437                 now = timeval_current();
1438                 nttime_to_timeval(&disconnect_time, op->disconnect_time);
1439                 tdiff = usec_time_diff(&now, &disconnect_time);
1440                 delete_open = (tdiff >= 1000*op->durable_timeout_msec);
1441
1442                 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1443                            "disconnected at [%s] %us ago with "
1444                            "timeout of %us -%s reached\n",
1445                            global_id,
1446                            nt_time_string(frame, op->disconnect_time),
1447                            (unsigned)(tdiff/1000000),
1448                            op->durable_timeout_msec / 1000,
1449                            delete_open ? "" : " not"));
1450         } else if (!serverid_exists(&op->server_id)) {
1451                 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1452                            "server[%s] does not exist\n",
1453                            global_id, server_id_str(frame, &op->server_id)));
1454                 delete_open = true;
1455         }
1456
1457         if (!delete_open) {
1458                 goto done;
1459         }
1460
1461         status = dbwrap_record_delete(rec);
1462         if (!NT_STATUS_IS_OK(status)) {
1463                 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1464                           "failed to delete record"
1465                           "from %s: %s\n", global_id,
1466                           dbwrap_name(smbXsrv_open_global_db_ctx),
1467                           nt_errstr(status)));
1468                 goto done;
1469         }
1470
1471         DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1472                    "delete record from %s\n",
1473                    global_id,
1474                    dbwrap_name(smbXsrv_open_global_db_ctx)));
1475
1476 done:
1477         talloc_free(frame);
1478         return status;
1479 }