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