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