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