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 "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 5079 : NTSTATUS smbXsrv_open_global_init(void)
53 : {
54 5079 : char *global_path = NULL;
55 5079 : struct db_context *db_ctx = NULL;
56 :
57 5079 : if (smbXsrv_open_global_db_ctx != NULL) {
58 5040 : return NT_STATUS_OK;
59 : }
60 :
61 39 : global_path = lock_path(talloc_tos(), "smbXsrv_open_global.tdb");
62 39 : if (global_path == NULL) {
63 0 : return NT_STATUS_NO_MEMORY;
64 : }
65 :
66 39 : 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 39 : TALLOC_FREE(global_path);
75 39 : if (db_ctx == NULL) {
76 : NTSTATUS status;
77 :
78 0 : status = map_nt_error_from_unix_common(errno);
79 :
80 0 : return status;
81 : }
82 :
83 39 : smbXsrv_open_global_db_ctx = db_ctx;
84 :
85 39 : 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 32678 : static TDB_DATA smbXsrv_open_global_id_to_key(uint32_t id,
100 : uint8_t *key_buf)
101 : {
102 : TDB_DATA key;
103 :
104 32678 : RSIVAL(key_buf, 0, id);
105 :
106 32678 : key = make_tdb_data(key_buf, SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE);
107 :
108 32678 : 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 145157 : static TDB_DATA smbXsrv_open_local_id_to_key(uint32_t id,
131 : uint8_t *key_buf)
132 : {
133 : TDB_DATA key;
134 :
135 145157 : RSIVAL(key_buf, 0, id);
136 :
137 145157 : key = make_tdb_data(key_buf, SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE);
138 :
139 145157 : return key;
140 : }
141 :
142 0 : static NTSTATUS smbXsrv_open_local_key_to_id(TDB_DATA key, uint32_t *id)
143 : {
144 0 : if (id == NULL) {
145 0 : return NT_STATUS_INVALID_PARAMETER;
146 : }
147 :
148 0 : if (key.dsize != SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE) {
149 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
150 : }
151 :
152 0 : *id = RIVAL(key.dptr, 0);
153 :
154 0 : return NT_STATUS_OK;
155 : }
156 :
157 32678 : 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 32678 : struct db_record *rec = NULL;
165 :
166 32678 : key = smbXsrv_open_global_id_to_key(id, key_buf);
167 :
168 32678 : rec = dbwrap_fetch_locked(db, mem_ctx, key);
169 :
170 32678 : if (rec == NULL) {
171 0 : 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 32678 : return rec;
176 : }
177 :
178 32678 : 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 32678 : struct db_record *rec = NULL;
186 :
187 32678 : key = smbXsrv_open_local_id_to_key(id, key_buf);
188 :
189 32678 : rec = dbwrap_fetch_locked(db, mem_ctx, key);
190 :
191 32678 : if (rec == NULL) {
192 0 : 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 32678 : return rec;
197 : }
198 :
199 5040 : 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 5040 : struct smbXsrv_client *client = conn->client;
205 : struct smbXsrv_open_table *table;
206 : NTSTATUS status;
207 : uint64_t max_range;
208 :
209 5040 : if (lowest_id > highest_id) {
210 0 : return NT_STATUS_INTERNAL_ERROR;
211 : }
212 :
213 5040 : max_range = highest_id;
214 5040 : max_range -= lowest_id;
215 5040 : max_range += 1;
216 :
217 5040 : if (max_opens > max_range) {
218 0 : return NT_STATUS_INTERNAL_ERROR;
219 : }
220 :
221 5040 : table = talloc_zero(client, struct smbXsrv_open_table);
222 5040 : if (table == NULL) {
223 0 : return NT_STATUS_NO_MEMORY;
224 : }
225 :
226 5040 : table->local.db_ctx = db_open_rbt(table);
227 5040 : if (table->local.db_ctx == NULL) {
228 0 : TALLOC_FREE(table);
229 0 : return NT_STATUS_NO_MEMORY;
230 : }
231 5040 : table->local.replay_cache_db_ctx = db_open_rbt(table);
232 5040 : if (table->local.replay_cache_db_ctx == NULL) {
233 0 : TALLOC_FREE(table);
234 0 : return NT_STATUS_NO_MEMORY;
235 : }
236 5040 : table->local.lowest_id = lowest_id;
237 5040 : table->local.highest_id = highest_id;
238 5040 : table->local.max_opens = max_opens;
239 :
240 5040 : status = smbXsrv_open_global_init();
241 5040 : if (!NT_STATUS_IS_OK(status)) {
242 0 : TALLOC_FREE(table);
243 0 : return status;
244 : }
245 :
246 5040 : table->global.db_ctx = smbXsrv_open_global_db_ctx;
247 :
248 5040 : client->open_table = table;
249 5040 : 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 0 : static int smbXsrv_open_local_allocate_traverse(struct db_record *rec,
261 : void *private_data)
262 : {
263 0 : struct smbXsrv_open_local_allocate_state *state =
264 : (struct smbXsrv_open_local_allocate_state *)private_data;
265 0 : TDB_DATA key = dbwrap_record_get_key(rec);
266 0 : uint32_t id = 0;
267 : NTSTATUS status;
268 :
269 0 : status = smbXsrv_open_local_key_to_id(key, &id);
270 0 : if (!NT_STATUS_IS_OK(status)) {
271 0 : state->status = status;
272 0 : return -1;
273 : }
274 :
275 0 : if (id <= state->last_id) {
276 0 : state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
277 0 : return -1;
278 : }
279 0 : state->last_id = id;
280 :
281 0 : if (id > state->useable_id) {
282 0 : state->status = NT_STATUS_OK;
283 0 : return -1;
284 : }
285 :
286 0 : if (state->useable_id == state->highest_id) {
287 0 : state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
288 0 : return -1;
289 : }
290 :
291 0 : state->useable_id +=1;
292 0 : return 0;
293 : }
294 :
295 16339 : 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 16339 : 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 16339 : int count = 0;
313 :
314 16339 : *_rec = NULL;
315 16339 : *_id = 0;
316 :
317 16339 : if (lowest_id > highest_id) {
318 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
319 : }
320 :
321 : /*
322 : * first we try randomly
323 : */
324 16339 : range = (highest_id - lowest_id) + 1;
325 :
326 30524 : for (i = 0; i < (range / 2); i++) {
327 : uint32_t id;
328 : TDB_DATA val;
329 16339 : struct db_record *rec = NULL;
330 :
331 16339 : id = generate_random() % range;
332 16339 : id += lowest_id;
333 :
334 16339 : if (id < lowest_id) {
335 0 : id = lowest_id;
336 : }
337 16339 : if (id > highest_id) {
338 0 : id = highest_id;
339 : }
340 :
341 16339 : rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
342 16339 : if (rec == NULL) {
343 14185 : return NT_STATUS_INSUFFICIENT_RESOURCES;
344 : }
345 :
346 16339 : val = dbwrap_record_get_value(rec);
347 16339 : if (val.dsize != 0) {
348 0 : TALLOC_FREE(rec);
349 0 : continue;
350 : }
351 :
352 16339 : *_rec = rec;
353 16339 : *_id = id;
354 16339 : 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 0 : status = dbwrap_traverse_read(db, smbXsrv_open_local_allocate_traverse,
363 : &state, &count);
364 0 : if (NT_STATUS_IS_OK(status)) {
365 0 : if (NT_STATUS_IS_OK(state.status)) {
366 0 : return NT_STATUS_INTERNAL_ERROR;
367 : }
368 :
369 0 : if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
370 0 : return state.status;
371 : }
372 :
373 0 : if (state.useable_id <= state.highest_id) {
374 0 : state.status = NT_STATUS_OK;
375 : } else {
376 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
377 : }
378 0 : } 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 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
387 : }
388 :
389 0 : if (NT_STATUS_IS_OK(state.status)) {
390 : uint32_t id;
391 : TDB_DATA val;
392 0 : struct db_record *rec = NULL;
393 :
394 0 : id = state.useable_id;
395 :
396 0 : rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
397 0 : if (rec == NULL) {
398 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
399 : }
400 :
401 0 : val = dbwrap_record_get_value(rec);
402 0 : if (val.dsize != 0) {
403 0 : TALLOC_FREE(rec);
404 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
405 : }
406 :
407 0 : *_rec = rec;
408 0 : *_id = id;
409 0 : return NT_STATUS_OK;
410 : }
411 :
412 0 : return state.status;
413 : }
414 :
415 : struct smbXsrv_open_local_fetch_state {
416 : struct smbXsrv_open *op;
417 : NTSTATUS status;
418 : };
419 :
420 112477 : static void smbXsrv_open_local_fetch_parser(TDB_DATA key, TDB_DATA data,
421 : void *private_data)
422 : {
423 112477 : struct smbXsrv_open_local_fetch_state *state =
424 : (struct smbXsrv_open_local_fetch_state *)private_data;
425 : void *ptr;
426 :
427 112477 : if (data.dsize != sizeof(ptr)) {
428 0 : state->status = NT_STATUS_INTERNAL_DB_ERROR;
429 0 : return;
430 : }
431 :
432 112477 : memcpy(&ptr, data.dptr, data.dsize);
433 112477 : state->op = talloc_get_type_abort(ptr, struct smbXsrv_open);
434 112477 : state->status = NT_STATUS_OK;
435 : }
436 :
437 112479 : 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 112479 : 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 112479 : *_open = NULL;
452 :
453 112479 : if (open_local_id == 0) {
454 0 : return NT_STATUS_FILE_CLOSED;
455 : }
456 :
457 112479 : if (table == NULL) {
458 : /* this might happen before the end of negprot */
459 0 : return NT_STATUS_FILE_CLOSED;
460 : }
461 :
462 112479 : if (table->local.db_ctx == NULL) {
463 0 : return NT_STATUS_INTERNAL_ERROR;
464 : }
465 :
466 112479 : key = smbXsrv_open_local_id_to_key(open_local_id, key_buf);
467 :
468 112479 : status = dbwrap_parse_record(table->local.db_ctx, key,
469 : smbXsrv_open_local_fetch_parser,
470 : &state);
471 112479 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
472 2 : return NT_STATUS_FILE_CLOSED;
473 : }
474 112477 : if (!NT_STATUS_IS_OK(status)) {
475 0 : return status;
476 : }
477 112477 : if (!NT_STATUS_IS_OK(state.status)) {
478 0 : return state.status;
479 : }
480 :
481 112477 : if (NT_STATUS_EQUAL(state.op->status, NT_STATUS_FILE_CLOSED)) {
482 0 : return NT_STATUS_FILE_CLOSED;
483 : }
484 :
485 112477 : if (open_global_id == 0) {
486 : /* make the global check a no-op for SMB1 */
487 0 : open_global_id = state.op->global->open_global_id;
488 : }
489 :
490 112477 : if (state.op->global->open_global_id != open_global_id) {
491 0 : return NT_STATUS_FILE_CLOSED;
492 : }
493 :
494 112477 : if (now != 0) {
495 112477 : state.op->idle_time = now;
496 : }
497 :
498 112477 : *_open = state.op;
499 112477 : return state.op->status;
500 : }
501 :
502 16339 : static int smbXsrv_open_global_destructor(struct smbXsrv_open_global0 *global)
503 : {
504 16339 : 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 16339 : 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 16339 : struct smbXsrv_open_global0 *global = NULL;
519 16339 : uint32_t last_free = 0;
520 16339 : const uint32_t min_tries = 3;
521 :
522 16339 : *_global = NULL;
523 :
524 16339 : global = talloc_zero(mem_ctx, struct smbXsrv_open_global0);
525 16339 : if (global == NULL) {
526 0 : return NT_STATUS_NO_MEMORY;
527 : }
528 16339 : 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 16339 : 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 16339 : for (i = 0; i < UINT32_MAX; i++) {
544 16339 : bool is_free = false;
545 16339 : bool was_free = false;
546 : uint32_t id;
547 :
548 16339 : if (i >= min_tries && last_free != 0) {
549 0 : id = last_free;
550 : } else {
551 16339 : id = generate_random();
552 : }
553 16339 : if (id == 0) {
554 0 : id++;
555 : }
556 16339 : if (id == UINT32_MAX) {
557 0 : id--;
558 : }
559 :
560 16339 : global->db_rec = smbXsrv_open_global_fetch_locked(db, id, mem_ctx);
561 16339 : if (global->db_rec == NULL) {
562 0 : talloc_free(global);
563 14185 : return NT_STATUS_INSUFFICIENT_RESOURCES;
564 : }
565 :
566 16339 : smbXsrv_open_global_verify_record(global->db_rec,
567 : &is_free,
568 : &was_free,
569 : NULL, NULL);
570 :
571 16339 : if (!is_free) {
572 0 : TALLOC_FREE(global->db_rec);
573 0 : continue;
574 : }
575 :
576 16339 : 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 0 : if (last_free == 0) {
588 0 : last_free = id;
589 : }
590 0 : TALLOC_FREE(global->db_rec);
591 0 : continue;
592 : }
593 :
594 16339 : global->open_global_id = id;
595 :
596 16339 : *_global = global;
597 16339 : return NT_STATUS_OK;
598 : }
599 :
600 : /* should not be reached */
601 0 : talloc_free(global);
602 0 : return NT_STATUS_INTERNAL_ERROR;
603 : }
604 :
605 16339 : 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 16339 : struct smbXsrv_open_global0 *global = NULL;
617 : bool exists;
618 16339 : TALLOC_CTX *frame = talloc_stackframe();
619 :
620 16339 : *is_free = false;
621 :
622 16339 : if (was_free) {
623 16339 : *was_free = false;
624 : }
625 16339 : if (_g) {
626 0 : *_g = NULL;
627 : }
628 :
629 16339 : key = dbwrap_record_get_key(db_rec);
630 :
631 16339 : val = dbwrap_record_get_value(db_rec);
632 16339 : if (val.dsize == 0) {
633 16339 : DEBUG(10, ("%s: empty value\n", __func__));
634 16339 : TALLOC_FREE(frame);
635 16339 : *is_free = true;
636 16339 : if (was_free) {
637 16339 : *was_free = true;
638 : }
639 30524 : return;
640 : }
641 :
642 0 : blob = data_blob_const(val.dptr, val.dsize);
643 :
644 0 : ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
645 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB);
646 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
647 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
648 0 : 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 0 : TALLOC_FREE(frame);
653 0 : return;
654 : }
655 :
656 0 : DEBUG(10,("smbXsrv_open_global_verify_record\n"));
657 0 : if (CHECK_DEBUGLVL(10)) {
658 0 : NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
659 : }
660 :
661 0 : if (global_blob.version != SMBXSRV_VERSION_0) {
662 0 : 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 0 : NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
667 0 : TALLOC_FREE(frame);
668 0 : return;
669 : }
670 :
671 0 : global = global_blob.info.info0;
672 :
673 0 : if (server_id_is_disconnected(&global->server_id)) {
674 0 : exists = true;
675 : } else {
676 0 : exists = serverid_exists(&global->server_id);
677 : }
678 0 : if (!exists) {
679 : struct server_id_buf idbuf;
680 0 : 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 0 : if (CHECK_DEBUGLVL(2)) {
685 0 : NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
686 : }
687 0 : TALLOC_FREE(frame);
688 0 : dbwrap_record_delete(db_rec);
689 0 : *is_free = true;
690 0 : return;
691 : }
692 :
693 0 : if (_g) {
694 0 : *_g = talloc_move(mem_ctx, &global);
695 : }
696 0 : TALLOC_FREE(frame);
697 : }
698 :
699 16339 : static NTSTATUS smbXsrv_open_global_store(struct smbXsrv_open_global0 *global)
700 : {
701 : struct smbXsrv_open_globalB global_blob;
702 16339 : 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 16339 : if (global->db_rec == NULL) {
715 0 : return NT_STATUS_INTERNAL_ERROR;
716 : }
717 :
718 16339 : key = dbwrap_record_get_key(global->db_rec);
719 16339 : val = dbwrap_record_get_value(global->db_rec);
720 :
721 16339 : ZERO_STRUCT(global_blob);
722 16339 : global_blob.version = smbXsrv_version_global_current();
723 16339 : if (val.dsize >= 8) {
724 0 : global_blob.seqnum = IVAL(val.dptr, 4);
725 : }
726 16339 : global_blob.seqnum += 1;
727 16339 : global_blob.info.info0 = global;
728 :
729 16339 : ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
730 : (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_globalB);
731 16339 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
732 0 : status = ndr_map_error2ntstatus(ndr_err);
733 0 : 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 0 : TALLOC_FREE(global->db_rec);
737 0 : return status;
738 : }
739 :
740 16339 : val = make_tdb_data(blob.data, blob.length);
741 16339 : status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
742 16339 : if (!NT_STATUS_IS_OK(status)) {
743 0 : 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 0 : TALLOC_FREE(global->db_rec);
747 0 : return status;
748 : }
749 :
750 16339 : if (CHECK_DEBUGLVL(10)) {
751 0 : DEBUG(10,("smbXsrv_open_global_store: key '%s' stored\n",
752 : hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
753 0 : NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
754 : }
755 :
756 16339 : TALLOC_FREE(global->db_rec);
757 :
758 16339 : return NT_STATUS_OK;
759 : }
760 :
761 0 : 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 0 : struct db_record *global_rec = NULL;
767 0 : bool is_free = false;
768 :
769 0 : *_global = NULL;
770 :
771 0 : if (table->global.db_ctx == NULL) {
772 0 : return NT_STATUS_INTERNAL_ERROR;
773 : }
774 :
775 0 : global_rec = smbXsrv_open_global_fetch_locked(table->global.db_ctx,
776 : open_global_id,
777 : mem_ctx);
778 0 : if (global_rec == NULL) {
779 0 : return NT_STATUS_INTERNAL_DB_ERROR;
780 : }
781 :
782 0 : smbXsrv_open_global_verify_record(global_rec,
783 : &is_free,
784 : NULL,
785 : mem_ctx,
786 : _global);
787 0 : if (is_free) {
788 0 : DEBUG(10, ("%s: is_free=true\n", __func__));
789 0 : talloc_free(global_rec);
790 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
791 : }
792 :
793 0 : (*_global)->db_rec = talloc_move(*_global, &global_rec);
794 :
795 0 : talloc_set_destructor(*_global, smbXsrv_open_global_destructor);
796 :
797 0 : return NT_STATUS_OK;
798 : }
799 :
800 16339 : static int smbXsrv_open_destructor(struct smbXsrv_open *op)
801 : {
802 : NTSTATUS status;
803 :
804 16339 : status = smbXsrv_open_close(op, 0);
805 16339 : if (!NT_STATUS_IS_OK(status)) {
806 0 : DEBUG(0, ("smbXsrv_open_destructor: "
807 : "smbXsrv_open_close() failed - %s\n",
808 : nt_errstr(status)));
809 : }
810 :
811 16339 : TALLOC_FREE(op->global);
812 :
813 16339 : return 0;
814 : }
815 :
816 16339 : 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 16339 : struct smbXsrv_open_table *table = conn->client->open_table;
822 16339 : struct db_record *local_rec = NULL;
823 16339 : struct smbXsrv_open *op = NULL;
824 16339 : void *ptr = NULL;
825 : TDB_DATA val;
826 16339 : struct smbXsrv_open_global0 *global = NULL;
827 : NTSTATUS status;
828 16339 : struct dom_sid *current_sid = NULL;
829 16339 : struct security_token *current_token = NULL;
830 :
831 16339 : if (session_info == NULL) {
832 0 : return NT_STATUS_INVALID_HANDLE;
833 : }
834 16339 : current_token = session_info->security_token;
835 :
836 16339 : if (current_token == NULL) {
837 0 : return NT_STATUS_INVALID_HANDLE;
838 : }
839 :
840 16339 : if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
841 16339 : current_sid = ¤t_token->sids[PRIMARY_USER_SID_INDEX];
842 : }
843 :
844 16339 : if (current_sid == NULL) {
845 0 : return NT_STATUS_INVALID_HANDLE;
846 : }
847 :
848 16339 : if (table->local.num_opens >= table->local.max_opens) {
849 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
850 : }
851 :
852 16339 : op = talloc_zero(table, struct smbXsrv_open);
853 16339 : if (op == NULL) {
854 0 : return NT_STATUS_NO_MEMORY;
855 : }
856 16339 : op->table = table;
857 16339 : op->status = NT_STATUS_OK; /* TODO: start with INTERNAL_ERROR */
858 16339 : op->idle_time = now;
859 :
860 16339 : status = smbXsrv_open_global_allocate(table->global.db_ctx,
861 : op, &global);
862 16339 : if (!NT_STATUS_IS_OK(status)) {
863 0 : TALLOC_FREE(op);
864 0 : return status;
865 : }
866 16339 : op->global = global;
867 :
868 16339 : 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 16339 : if (!NT_STATUS_IS_OK(status)) {
875 0 : TALLOC_FREE(op);
876 0 : return status;
877 : }
878 :
879 16339 : global->open_persistent_id = global->open_global_id;
880 16339 : global->open_volatile_id = op->local_id;
881 :
882 16339 : global->server_id = messaging_server_id(conn->client->msg_ctx);
883 16339 : global->open_time = now;
884 16339 : global->open_owner = *current_sid;
885 16339 : if (conn->protocol >= PROTOCOL_SMB2_10) {
886 16335 : global->client_guid = conn->smb2.client.guid;
887 : }
888 :
889 16339 : ptr = op;
890 16339 : val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
891 16339 : status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
892 16339 : TALLOC_FREE(local_rec);
893 16339 : if (!NT_STATUS_IS_OK(status)) {
894 0 : TALLOC_FREE(op);
895 0 : return status;
896 : }
897 16339 : table->local.num_opens += 1;
898 :
899 16339 : talloc_set_destructor(op, smbXsrv_open_destructor);
900 :
901 16339 : status = smbXsrv_open_global_store(global);
902 16339 : if (!NT_STATUS_IS_OK(status)) {
903 0 : 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 0 : TALLOC_FREE(op);
908 0 : return status;
909 : }
910 :
911 16339 : if (CHECK_DEBUGLVL(10)) {
912 0 : struct smbXsrv_openB open_blob = {
913 : .version = SMBXSRV_VERSION_0,
914 : .info.info0 = op,
915 : };
916 :
917 0 : DEBUG(10,("smbXsrv_open_create: global_id (0x%08x) stored\n",
918 : op->global->open_global_id));
919 0 : NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
920 : }
921 :
922 16339 : *_open = op;
923 16339 : return NT_STATUS_OK;
924 : }
925 :
926 0 : 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 0 : struct db_context *db = op->table->local.replay_cache_db_ctx;
932 0 : struct smbXsrv_open_replay_cache rc = {
933 0 : .idle_time = op->idle_time,
934 0 : .local_id = op->local_id,
935 : };
936 0 : uint8_t data[SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE] = { 0 };
937 0 : 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 0 : if (!(op->flags & SMBXSRV_OPEN_NEED_REPLAY_CACHE)) {
944 0 : return NT_STATUS_OK;
945 : }
946 :
947 0 : if (op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE) {
948 0 : return NT_STATUS_OK;
949 : }
950 :
951 0 : create_guid = &op->global->create_guid;
952 0 : guid_string = GUID_buf_string(create_guid, &buf);
953 0 : key = string_term_tdb_data(guid_string);
954 :
955 0 : ndr_err = ndr_push_struct_into_fixed_blob(&blob, &rc,
956 : (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_replay_cache);
957 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
958 0 : status = ndr_map_error2ntstatus(ndr_err);
959 0 : return status;
960 : }
961 0 : val = make_tdb_data(blob.data, blob.length);
962 :
963 0 : status = dbwrap_store(db, key, val, TDB_REPLACE);
964 :
965 0 : if (NT_STATUS_IS_OK(status)) {
966 0 : op->flags |= SMBXSRV_OPEN_HAVE_REPLAY_CACHE;
967 0 : op->flags &= ~SMBXSRV_OPEN_NEED_REPLAY_CACHE;
968 : }
969 :
970 0 : return status;
971 : }
972 :
973 0 : 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 0 : if (client->open_table == NULL) {
981 0 : return NT_STATUS_OK;
982 : }
983 :
984 0 : db = client->open_table->local.replay_cache_db_ctx;
985 :
986 0 : guid_string = GUID_buf_string(create_guid, &buf);
987 0 : if (guid_string == NULL) {
988 0 : return NT_STATUS_INVALID_PARAMETER;
989 : }
990 :
991 0 : return dbwrap_purge_bystring(db, guid_string);
992 : }
993 :
994 128816 : 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 128816 : if (op->table == NULL) {
1003 0 : return NT_STATUS_OK;
1004 : }
1005 :
1006 128816 : db = op->table->local.replay_cache_db_ctx;
1007 :
1008 128816 : if (!(op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE)) {
1009 128816 : return NT_STATUS_OK;
1010 : }
1011 :
1012 0 : create_guid = &op->global->create_guid;
1013 0 : if (GUID_all_zero(create_guid)) {
1014 0 : return NT_STATUS_OK;
1015 : }
1016 :
1017 0 : guid_string = GUID_buf_string(create_guid, &buf);
1018 0 : if (guid_string == NULL) {
1019 0 : return NT_STATUS_INVALID_PARAMETER;
1020 : }
1021 :
1022 0 : status = dbwrap_purge_bystring(db, guid_string);
1023 :
1024 0 : if (NT_STATUS_IS_OK(status)) {
1025 0 : op->flags &= ~SMBXSRV_OPEN_HAVE_REPLAY_CACHE;
1026 : }
1027 :
1028 0 : return status;
1029 : }
1030 :
1031 0 : NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op)
1032 : {
1033 0 : struct smbXsrv_open_table *table = op->table;
1034 : NTSTATUS status;
1035 :
1036 0 : if (op->global->db_rec != NULL) {
1037 0 : DEBUG(0, ("smbXsrv_open_update(0x%08x): "
1038 : "Called with db_rec != NULL'\n",
1039 : op->global->open_global_id));
1040 0 : return NT_STATUS_INTERNAL_ERROR;
1041 : }
1042 :
1043 0 : op->global->db_rec = smbXsrv_open_global_fetch_locked(
1044 : table->global.db_ctx,
1045 0 : op->global->open_global_id,
1046 0 : op->global /* TALLOC_CTX */);
1047 0 : if (op->global->db_rec == NULL) {
1048 0 : return NT_STATUS_INTERNAL_DB_ERROR;
1049 : }
1050 :
1051 0 : status = smbXsrv_open_global_store(op->global);
1052 0 : if (!NT_STATUS_IS_OK(status)) {
1053 0 : 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 0 : return status;
1058 : }
1059 :
1060 0 : status = smbXsrv_open_set_replay_cache(op);
1061 0 : if (!NT_STATUS_IS_OK(status)) {
1062 0 : DBG_ERR("smbXsrv_open_set_replay_cache failed: %s\n",
1063 : nt_errstr(status));
1064 0 : return status;
1065 : }
1066 :
1067 0 : if (CHECK_DEBUGLVL(10)) {
1068 0 : struct smbXsrv_openB open_blob = {
1069 : .version = SMBXSRV_VERSION_0,
1070 : .info.info0 = op,
1071 : };
1072 :
1073 0 : DEBUG(10,("smbXsrv_open_update: global_id (0x%08x) stored\n",
1074 : op->global->open_global_id));
1075 0 : NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
1076 : }
1077 :
1078 0 : return NT_STATUS_OK;
1079 : }
1080 :
1081 16339 : NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
1082 : {
1083 : struct smbXsrv_open_table *table;
1084 16339 : struct db_record *local_rec = NULL;
1085 16339 : struct db_record *global_rec = NULL;
1086 : NTSTATUS status;
1087 16339 : NTSTATUS error = NT_STATUS_OK;
1088 :
1089 16339 : error = smbXsrv_open_clear_replay_cache(op);
1090 16339 : if (!NT_STATUS_IS_OK(error)) {
1091 0 : DBG_ERR("smbXsrv_open_clear_replay_cache failed: %s\n",
1092 : nt_errstr(error));
1093 : }
1094 :
1095 16339 : if (op->table == NULL) {
1096 0 : return error;
1097 : }
1098 :
1099 16339 : table = op->table;
1100 16339 : op->table = NULL;
1101 :
1102 16339 : op->status = NT_STATUS_FILE_CLOSED;
1103 16339 : op->global->disconnect_time = now;
1104 16339 : server_id_set_disconnected(&op->global->server_id);
1105 :
1106 16339 : global_rec = op->global->db_rec;
1107 16339 : op->global->db_rec = NULL;
1108 16339 : if (global_rec == NULL) {
1109 16339 : global_rec = smbXsrv_open_global_fetch_locked(
1110 : table->global.db_ctx,
1111 16339 : op->global->open_global_id,
1112 16339 : op->global /* TALLOC_CTX */);
1113 16339 : if (global_rec == NULL) {
1114 0 : error = NT_STATUS_INTERNAL_ERROR;
1115 : }
1116 : }
1117 :
1118 16339 : 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 0 : op->global->db_rec = global_rec;
1124 0 : status = smbXsrv_open_global_store(op->global);
1125 0 : if (NT_STATUS_IS_OK(status)) {
1126 : /*
1127 : * smbXsrv_open_global_store does the free
1128 : * of op->global->db_rec
1129 : */
1130 0 : global_rec = NULL;
1131 : }
1132 0 : if (!NT_STATUS_IS_OK(status)) {
1133 0 : 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 0 : error = status;
1138 : }
1139 :
1140 0 : if (NT_STATUS_IS_OK(status) && CHECK_DEBUGLVL(10)) {
1141 0 : struct smbXsrv_openB open_blob = {
1142 : .version = SMBXSRV_VERSION_0,
1143 : .info.info0 = op,
1144 : };
1145 :
1146 0 : DEBUG(10,("smbXsrv_open_close(0x%08x): "
1147 : "stored disconnect\n",
1148 : op->global->open_global_id));
1149 0 : NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
1150 : }
1151 : }
1152 :
1153 16339 : if (global_rec != NULL) {
1154 16339 : status = dbwrap_record_delete(global_rec);
1155 16339 : if (!NT_STATUS_IS_OK(status)) {
1156 0 : TDB_DATA key = dbwrap_record_get_key(global_rec);
1157 :
1158 0 : 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 0 : error = status;
1165 : }
1166 : }
1167 16339 : TALLOC_FREE(global_rec);
1168 :
1169 16339 : local_rec = op->db_rec;
1170 16339 : if (local_rec == NULL) {
1171 16339 : local_rec = smbXsrv_open_local_fetch_locked(table->local.db_ctx,
1172 : op->local_id,
1173 : op /* TALLOC_CTX*/);
1174 16339 : if (local_rec == NULL) {
1175 0 : error = NT_STATUS_INTERNAL_ERROR;
1176 : }
1177 : }
1178 :
1179 16339 : if (local_rec != NULL) {
1180 16339 : status = dbwrap_record_delete(local_rec);
1181 16339 : if (!NT_STATUS_IS_OK(status)) {
1182 0 : TDB_DATA key = dbwrap_record_get_key(local_rec);
1183 :
1184 0 : 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 0 : error = status;
1191 : }
1192 16339 : table->local.num_opens -= 1;
1193 : }
1194 16339 : if (op->db_rec == NULL) {
1195 16339 : TALLOC_FREE(local_rec);
1196 : }
1197 16339 : op->db_rec = NULL;
1198 :
1199 16339 : if (op->compat) {
1200 0 : op->compat->op = NULL;
1201 0 : file_free(NULL, op->compat);
1202 0 : op->compat = NULL;
1203 : }
1204 :
1205 16339 : return error;
1206 : }
1207 :
1208 38 : 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 38 : max_opens = conn->client->sconn->real_max_open_files;
1221 38 : max_opens = MIN(max_opens, UINT16_MAX - 1);
1222 :
1223 38 : return smbXsrv_open_table_init(conn, 1, UINT16_MAX - 1, max_opens);
1224 : }
1225 :
1226 0 : NTSTATUS smb1srv_open_lookup(struct smbXsrv_connection *conn,
1227 : uint16_t fnum, NTTIME now,
1228 : struct smbXsrv_open **_open)
1229 : {
1230 0 : struct smbXsrv_open_table *table = conn->client->open_table;
1231 0 : uint32_t local_id = fnum;
1232 0 : uint32_t global_id = 0;
1233 :
1234 0 : return smbXsrv_open_local_lookup(table, local_id, global_id, now, _open);
1235 : }
1236 :
1237 5002 : 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 5002 : max_opens = conn->client->sconn->real_max_open_files;
1255 5002 : max_opens = MIN(max_opens, UINT16_MAX - 1);
1256 :
1257 5002 : return smbXsrv_open_table_init(conn, 1, UINT32_MAX - 1, max_opens);
1258 : }
1259 :
1260 114138 : 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 114138 : struct smbXsrv_open_table *table = conn->client->open_table;
1267 114138 : uint32_t local_id = volatile_id & UINT32_MAX;
1268 114138 : uint64_t local_zeros = volatile_id & 0xFFFFFFFF00000000LLU;
1269 114138 : uint32_t global_id = persistent_id & UINT32_MAX;
1270 114138 : uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
1271 : NTSTATUS status;
1272 :
1273 114138 : if (local_zeros != 0) {
1274 1659 : return NT_STATUS_FILE_CLOSED;
1275 : }
1276 :
1277 112479 : if (global_zeros != 0) {
1278 0 : return NT_STATUS_FILE_CLOSED;
1279 : }
1280 :
1281 112479 : if (global_id == 0) {
1282 0 : return NT_STATUS_FILE_CLOSED;
1283 : }
1284 :
1285 112479 : status = smbXsrv_open_local_lookup(table, local_id, global_id, now,
1286 : _open);
1287 112479 : if (!NT_STATUS_IS_OK(status)) {
1288 2 : 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 112477 : status = smbXsrv_open_clear_replay_cache(*_open);
1301 :
1302 112477 : 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 0 : 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 0 : TALLOC_CTX *frame = talloc_stackframe();
1355 : NTSTATUS status;
1356 0 : struct smbXsrv_open_table *table = conn->client->open_table;
1357 0 : 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 0 : const char *create_guid_str = NULL;
1361 : TDB_DATA create_guid_key;
1362 0 : struct db_record *db_rec = NULL;
1363 0 : struct smbXsrv_open *op = NULL;
1364 0 : 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 0 : DATA_BLOB blob = data_blob_null;
1371 : TDB_DATA val;
1372 :
1373 0 : *_open = NULL;
1374 :
1375 0 : create_guid_str = GUID_buf_string(&create_guid, &_create_guid_buf);
1376 0 : create_guid_key = string_term_tdb_data(create_guid_str);
1377 :
1378 0 : db_rec = dbwrap_fetch_locked(db, frame, create_guid_key);
1379 0 : if (db_rec == NULL) {
1380 0 : TALLOC_FREE(frame);
1381 0 : return NT_STATUS_INTERNAL_DB_ERROR;
1382 : }
1383 :
1384 0 : val = dbwrap_record_get_value(db_rec);
1385 0 : if (val.dsize == 0) {
1386 : uint8_t data[SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE];
1387 :
1388 0 : blob = data_blob_const(data, ARRAY_SIZE(data));
1389 0 : ndr_err = ndr_push_struct_into_fixed_blob(&blob, &rc,
1390 : (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_replay_cache);
1391 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1392 0 : status = ndr_map_error2ntstatus(ndr_err);
1393 0 : TALLOC_FREE(frame);
1394 0 : return status;
1395 : }
1396 :
1397 0 : val = make_tdb_data(blob.data, blob.length);
1398 0 : status = dbwrap_record_store(db_rec, val, TDB_REPLACE);
1399 0 : if (!NT_STATUS_IS_OK(status)) {
1400 0 : TALLOC_FREE(frame);
1401 0 : return status;
1402 : }
1403 :
1404 : /*
1405 : * We're the new holder
1406 : */
1407 0 : *_open = NULL;
1408 0 : TALLOC_FREE(frame);
1409 0 : return NT_STATUS_FWP_RESERVED;
1410 : }
1411 :
1412 0 : if (val.dsize != SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE) {
1413 0 : TALLOC_FREE(frame);
1414 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1415 : }
1416 :
1417 0 : blob = data_blob_const(val.dptr, val.dsize);
1418 0 : ndr_err = ndr_pull_struct_blob_all_noalloc(&blob, &rc,
1419 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_replay_cache);
1420 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1421 0 : status = ndr_map_error2ntstatus(ndr_err);
1422 0 : TALLOC_FREE(frame);
1423 0 : return status;
1424 : }
1425 0 : if (rc.local_id != 0) {
1426 0 : if (GUID_equal(&rc.holder_req_guid, &caller_req_guid)) {
1427 : /*
1428 : * This should not happen
1429 : */
1430 0 : status = NT_STATUS_INTERNAL_ERROR;
1431 0 : 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 0 : TALLOC_FREE(frame);
1439 0 : return status;
1440 : }
1441 :
1442 0 : status = smbXsrv_open_local_lookup(table,
1443 : rc.local_id,
1444 : 0, /* global_id */
1445 : now,
1446 : &op);
1447 0 : if (!NT_STATUS_IS_OK(status)) {
1448 0 : 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 0 : TALLOC_FREE(frame);
1456 0 : return status;
1457 : }
1458 :
1459 : /*
1460 : * We found an open the caller can reuse.
1461 : */
1462 0 : SMB_ASSERT(op != NULL);
1463 0 : *_open = op;
1464 0 : TALLOC_FREE(frame);
1465 0 : return NT_STATUS_OK;
1466 : }
1467 :
1468 0 : if (GUID_equal(&rc.holder_req_guid, &caller_req_guid)) {
1469 : /*
1470 : * We're still the holder
1471 : */
1472 0 : *_open = NULL;
1473 0 : TALLOC_FREE(frame);
1474 0 : 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 0 : status = NT_STATUS_FILE_NOT_AVAILABLE;
1482 0 : 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 0 : TALLOC_FREE(frame);
1488 0 : return status;
1489 : }
1490 :
1491 0 : 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 0 : struct smbXsrv_open_table *table = conn->client->open_table;
1499 0 : struct db_record *local_rec = NULL;
1500 0 : struct smbXsrv_open *op = NULL;
1501 0 : void *ptr = NULL;
1502 : TDB_DATA val;
1503 0 : uint32_t global_id = persistent_id & UINT32_MAX;
1504 0 : uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
1505 : NTSTATUS status;
1506 0 : struct security_token *current_token = NULL;
1507 :
1508 0 : if (session_info == NULL) {
1509 0 : DEBUG(10, ("session_info=NULL\n"));
1510 0 : return NT_STATUS_INVALID_HANDLE;
1511 : }
1512 0 : current_token = session_info->security_token;
1513 :
1514 0 : if (current_token == NULL) {
1515 0 : DEBUG(10, ("current_token=NULL\n"));
1516 0 : return NT_STATUS_INVALID_HANDLE;
1517 : }
1518 :
1519 0 : if (global_zeros != 0) {
1520 0 : DEBUG(10, ("global_zeros!=0\n"));
1521 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1522 : }
1523 :
1524 0 : op = talloc_zero(table, struct smbXsrv_open);
1525 0 : if (op == NULL) {
1526 0 : return NT_STATUS_NO_MEMORY;
1527 : }
1528 0 : op->table = table;
1529 :
1530 0 : status = smbXsrv_open_global_lookup(table, global_id, op, &op->global);
1531 0 : if (!NT_STATUS_IS_OK(status)) {
1532 0 : TALLOC_FREE(op);
1533 0 : DEBUG(10, ("smbXsrv_open_global_lookup returned %s\n",
1534 : nt_errstr(status)));
1535 0 : 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 0 : if ((create_guid != NULL) &&
1545 0 : !GUID_equal(&op->global->create_guid, create_guid))
1546 : {
1547 0 : TALLOC_FREE(op);
1548 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1549 : }
1550 :
1551 0 : if (!security_token_is_sid(current_token, &op->global->open_owner)) {
1552 0 : TALLOC_FREE(op);
1553 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1554 : }
1555 :
1556 0 : if (!op->global->durable) {
1557 0 : TALLOC_FREE(op);
1558 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1559 : }
1560 :
1561 0 : if (table->local.num_opens >= table->local.max_opens) {
1562 0 : TALLOC_FREE(op);
1563 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
1564 : }
1565 :
1566 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
1573 0 : TALLOC_FREE(op);
1574 0 : return status;
1575 : }
1576 :
1577 0 : op->idle_time = now;
1578 0 : op->status = NT_STATUS_FILE_CLOSED;
1579 :
1580 0 : op->global->open_volatile_id = op->local_id;
1581 0 : op->global->server_id = messaging_server_id(conn->client->msg_ctx);
1582 :
1583 0 : ptr = op;
1584 0 : val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1585 0 : status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1586 0 : TALLOC_FREE(local_rec);
1587 0 : if (!NT_STATUS_IS_OK(status)) {
1588 0 : TALLOC_FREE(op);
1589 0 : return status;
1590 : }
1591 0 : table->local.num_opens += 1;
1592 :
1593 0 : talloc_set_destructor(op, smbXsrv_open_destructor);
1594 :
1595 0 : status = smbXsrv_open_global_store(op->global);
1596 0 : if (!NT_STATUS_IS_OK(status)) {
1597 0 : TALLOC_FREE(op);
1598 0 : return status;
1599 : }
1600 :
1601 0 : if (CHECK_DEBUGLVL(10)) {
1602 0 : struct smbXsrv_openB open_blob = {
1603 : .info.info0 = op,
1604 : };
1605 :
1606 0 : DEBUG(10,("smbXsrv_open_recreate: global_id (0x%08x) stored\n",
1607 : op->global->open_global_id));
1608 0 : NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
1609 : }
1610 :
1611 0 : *_open = op;
1612 0 : return NT_STATUS_OK;
1613 : }
1614 :
1615 :
1616 0 : static NTSTATUS smbXsrv_open_global_parse_record(TALLOC_CTX *mem_ctx,
1617 : struct db_record *rec,
1618 : struct smbXsrv_open_global0 **global)
1619 : {
1620 0 : TDB_DATA key = dbwrap_record_get_key(rec);
1621 0 : TDB_DATA val = dbwrap_record_get_value(rec);
1622 0 : 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 0 : TALLOC_CTX *frame = talloc_stackframe();
1627 :
1628 0 : ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
1629 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB);
1630 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1631 0 : 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 0 : status = ndr_map_error2ntstatus(ndr_err);
1636 0 : goto done;
1637 : }
1638 :
1639 0 : if (global_blob.version != SMBXSRV_VERSION_0) {
1640 0 : status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1641 0 : 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 0 : goto done;
1647 : }
1648 :
1649 0 : if (global_blob.info.info0 == NULL) {
1650 0 : status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1651 0 : 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 0 : goto done;
1656 : }
1657 :
1658 0 : *global = talloc_move(mem_ctx, &global_blob.info.info0);
1659 0 : status = NT_STATUS_OK;
1660 0 : done:
1661 0 : talloc_free(frame);
1662 0 : 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 0 : static int smbXsrv_open_global_traverse_fn(struct db_record *rec, void *data)
1671 : {
1672 0 : struct smbXsrv_open_global_traverse_state *state =
1673 : (struct smbXsrv_open_global_traverse_state*)data;
1674 0 : struct smbXsrv_open_global0 *global = NULL;
1675 : NTSTATUS status;
1676 0 : int ret = -1;
1677 :
1678 0 : status = smbXsrv_open_global_parse_record(talloc_tos(), rec, &global);
1679 0 : if (!NT_STATUS_IS_OK(status)) {
1680 0 : return -1;
1681 : }
1682 :
1683 0 : global->db_rec = rec;
1684 0 : ret = state->fn(global, state->private_data);
1685 0 : talloc_free(global);
1686 0 : return ret;
1687 : }
1688 :
1689 0 : NTSTATUS smbXsrv_open_global_traverse(
1690 : int (*fn)(struct smbXsrv_open_global0 *, void *),
1691 : void *private_data)
1692 : {
1693 :
1694 : NTSTATUS status;
1695 0 : int count = 0;
1696 0 : struct smbXsrv_open_global_traverse_state state = {
1697 : .fn = fn,
1698 : .private_data = private_data,
1699 : };
1700 :
1701 0 : become_root();
1702 0 : status = smbXsrv_open_global_init();
1703 0 : if (!NT_STATUS_IS_OK(status)) {
1704 0 : unbecome_root();
1705 0 : DEBUG(0, ("Failed to initialize open_global: %s\n",
1706 : nt_errstr(status)));
1707 0 : return status;
1708 : }
1709 :
1710 0 : status = dbwrap_traverse_read(smbXsrv_open_global_db_ctx,
1711 : smbXsrv_open_global_traverse_fn,
1712 : &state,
1713 : &count);
1714 0 : unbecome_root();
1715 :
1716 0 : return status;
1717 : }
1718 :
1719 0 : NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id)
1720 : {
1721 0 : NTSTATUS status = NT_STATUS_OK;
1722 0 : TALLOC_CTX *frame = talloc_stackframe();
1723 0 : struct smbXsrv_open_global0 *op = NULL;
1724 : TDB_DATA val;
1725 : struct db_record *rec;
1726 0 : bool delete_open = false;
1727 0 : uint32_t global_id = persistent_id & UINT32_MAX;
1728 :
1729 0 : rec = smbXsrv_open_global_fetch_locked(smbXsrv_open_global_db_ctx,
1730 : global_id,
1731 : frame);
1732 0 : if (rec == NULL) {
1733 0 : status = NT_STATUS_NOT_FOUND;
1734 0 : goto done;
1735 : }
1736 :
1737 0 : val = dbwrap_record_get_value(rec);
1738 0 : if (val.dsize == 0) {
1739 0 : 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 0 : goto done;
1743 : }
1744 :
1745 0 : status = smbXsrv_open_global_parse_record(talloc_tos(), rec, &op);
1746 0 : if (!NT_STATUS_IS_OK(status)) {
1747 0 : DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1748 : "failed to read record: %s\n",
1749 : global_id, nt_errstr(status)));
1750 0 : goto done;
1751 : }
1752 :
1753 0 : if (server_id_is_disconnected(&op->server_id)) {
1754 : struct timeval now, disconnect_time;
1755 : int64_t tdiff;
1756 0 : now = timeval_current();
1757 0 : nttime_to_timeval(&disconnect_time, op->disconnect_time);
1758 0 : tdiff = usec_time_diff(&now, &disconnect_time);
1759 0 : delete_open = (tdiff >= 1000*op->durable_timeout_msec);
1760 :
1761 0 : 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 0 : } else if (!serverid_exists(&op->server_id)) {
1770 : struct server_id_buf idbuf;
1771 0 : 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 0 : delete_open = true;
1776 : }
1777 :
1778 0 : if (!delete_open) {
1779 0 : goto done;
1780 : }
1781 :
1782 0 : status = dbwrap_record_delete(rec);
1783 0 : if (!NT_STATUS_IS_OK(status)) {
1784 0 : 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 0 : goto done;
1790 : }
1791 :
1792 0 : 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 0 : done:
1798 0 : talloc_free(frame);
1799 0 : return status;
1800 : }
|