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