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