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