Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Stefan Metzmacher 2011-2012
5 : Copyright (C) Michael Adam 2012
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/filesys.h"
23 : #include "lib/util/server_id.h"
24 : #include "smbd/smbd.h"
25 : #include "smbd/globals.h"
26 : #include "dbwrap/dbwrap.h"
27 : #include "dbwrap/dbwrap_rbt.h"
28 : #include "dbwrap/dbwrap_open.h"
29 : #include "messages.h"
30 : #include "lib/util/util_tdb.h"
31 : #include "librpc/gen_ndr/ndr_smbXsrv.h"
32 : #include "serverid.h"
33 : #include "source3/include/util_tdb.h"
34 :
35 : struct smbXsrv_tcon_table {
36 : struct {
37 : struct db_context *db_ctx;
38 : uint32_t lowest_id;
39 : uint32_t highest_id;
40 : uint32_t max_tcons;
41 : uint32_t num_tcons;
42 : } local;
43 : struct {
44 : struct db_context *db_ctx;
45 : } global;
46 : };
47 :
48 : static struct db_context *smbXsrv_tcon_global_db_ctx = NULL;
49 :
50 31057 : NTSTATUS smbXsrv_tcon_global_init(void)
51 : {
52 31057 : char *global_path = NULL;
53 31057 : struct db_context *db_ctx = NULL;
54 :
55 31057 : if (smbXsrv_tcon_global_db_ctx != NULL) {
56 31026 : return NT_STATUS_OK;
57 : }
58 :
59 31 : global_path = lock_path(talloc_tos(), "smbXsrv_tcon_global.tdb");
60 31 : if (global_path == NULL) {
61 0 : return NT_STATUS_NO_MEMORY;
62 : }
63 :
64 31 : db_ctx = db_open(NULL, global_path,
65 : SMBD_VOLATILE_TDB_HASH_SIZE,
66 : SMBD_VOLATILE_TDB_FLAGS,
67 : O_RDWR | O_CREAT, 0600,
68 : DBWRAP_LOCK_ORDER_1,
69 : DBWRAP_FLAG_NONE);
70 31 : TALLOC_FREE(global_path);
71 31 : if (db_ctx == NULL) {
72 0 : NTSTATUS status;
73 :
74 0 : status = map_nt_error_from_unix_common(errno);
75 :
76 0 : return status;
77 : }
78 :
79 31 : smbXsrv_tcon_global_db_ctx = db_ctx;
80 :
81 31 : return NT_STATUS_OK;
82 : }
83 :
84 : /*
85 : * NOTE:
86 : * We need to store the keys in big endian so that dbwrap_rbt's memcmp
87 : * has the same result as integer comparison between the uint32_t
88 : * values.
89 : *
90 : * TODO: implement string based key
91 : */
92 :
93 : #define SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
94 :
95 145361 : static TDB_DATA smbXsrv_tcon_global_id_to_key(uint32_t id,
96 : uint8_t *key_buf)
97 : {
98 2159 : TDB_DATA key;
99 :
100 145361 : RSIVAL(key_buf, 0, id);
101 :
102 145361 : key = make_tdb_data(key_buf, SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE);
103 :
104 145361 : return key;
105 : }
106 :
107 : #if 0
108 : static NTSTATUS smbXsrv_tcon_global_key_to_id(TDB_DATA key, uint32_t *id)
109 : {
110 : if (id == NULL) {
111 : return NT_STATUS_INVALID_PARAMETER;
112 : }
113 :
114 : if (key.dsize != SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE) {
115 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
116 : }
117 :
118 : *id = RIVAL(key.dptr, 0);
119 :
120 : return NT_STATUS_OK;
121 : }
122 : #endif
123 :
124 : #define SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
125 :
126 2066390 : static TDB_DATA smbXsrv_tcon_local_id_to_key(uint32_t id,
127 : uint8_t *key_buf)
128 : {
129 17033 : TDB_DATA key;
130 :
131 2066390 : RSIVAL(key_buf, 0, id);
132 :
133 2066390 : key = make_tdb_data(key_buf, SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE);
134 :
135 2066390 : return key;
136 : }
137 :
138 0 : static NTSTATUS smbXsrv_tcon_local_key_to_id(TDB_DATA key, uint32_t *id)
139 : {
140 0 : if (id == NULL) {
141 0 : return NT_STATUS_INVALID_PARAMETER;
142 : }
143 :
144 0 : if (key.dsize != SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE) {
145 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
146 : }
147 :
148 0 : *id = RIVAL(key.dptr, 0);
149 :
150 0 : return NT_STATUS_OK;
151 : }
152 :
153 145361 : static struct db_record *smbXsrv_tcon_global_fetch_locked(
154 : struct db_context *db,
155 : uint32_t id,
156 : TALLOC_CTX *mem_ctx)
157 : {
158 2159 : TDB_DATA key;
159 2159 : uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE];
160 145361 : struct db_record *rec = NULL;
161 :
162 145361 : key = smbXsrv_tcon_global_id_to_key(id, key_buf);
163 :
164 145361 : rec = dbwrap_fetch_locked(db, mem_ctx, key);
165 :
166 145361 : if (rec == NULL) {
167 0 : DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
168 : tdb_data_dbg(key));
169 : }
170 :
171 145361 : return rec;
172 : }
173 :
174 81890 : static struct db_record *smbXsrv_tcon_local_fetch_locked(
175 : struct db_context *db,
176 : uint32_t id,
177 : TALLOC_CTX *mem_ctx)
178 : {
179 787 : TDB_DATA key;
180 787 : uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
181 81890 : struct db_record *rec = NULL;
182 :
183 81890 : key = smbXsrv_tcon_local_id_to_key(id, key_buf);
184 :
185 81890 : rec = dbwrap_fetch_locked(db, mem_ctx, key);
186 :
187 81890 : if (rec == NULL) {
188 0 : DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
189 : tdb_data_dbg(key));
190 : }
191 :
192 81890 : return rec;
193 : }
194 :
195 30988 : static NTSTATUS smbXsrv_tcon_table_init(TALLOC_CTX *mem_ctx,
196 : struct smbXsrv_tcon_table *table,
197 : uint32_t lowest_id,
198 : uint32_t highest_id,
199 : uint32_t max_tcons)
200 : {
201 760 : NTSTATUS status;
202 760 : uint64_t max_range;
203 :
204 30988 : if (lowest_id > highest_id) {
205 0 : return NT_STATUS_INTERNAL_ERROR;
206 : }
207 :
208 30988 : max_range = highest_id;
209 30988 : max_range -= lowest_id;
210 30988 : max_range += 1;
211 :
212 30988 : if (max_tcons > max_range) {
213 0 : return NT_STATUS_INTERNAL_ERROR;
214 : }
215 :
216 30988 : ZERO_STRUCTP(table);
217 30988 : table->local.db_ctx = db_open_rbt(table);
218 30988 : if (table->local.db_ctx == NULL) {
219 0 : return NT_STATUS_NO_MEMORY;
220 : }
221 30988 : table->local.lowest_id = lowest_id;
222 30988 : table->local.highest_id = highest_id;
223 30988 : table->local.max_tcons = max_tcons;
224 :
225 30988 : status = smbXsrv_tcon_global_init();
226 30988 : if (!NT_STATUS_IS_OK(status)) {
227 0 : return status;
228 : }
229 :
230 30988 : table->global.db_ctx = smbXsrv_tcon_global_db_ctx;
231 :
232 30988 : return NT_STATUS_OK;
233 : }
234 :
235 : struct smb1srv_tcon_local_allocate_state {
236 : const uint32_t lowest_id;
237 : const uint32_t highest_id;
238 : uint32_t last_id;
239 : uint32_t useable_id;
240 : NTSTATUS status;
241 : };
242 :
243 0 : static int smb1srv_tcon_local_allocate_traverse(struct db_record *rec,
244 : void *private_data)
245 : {
246 0 : struct smb1srv_tcon_local_allocate_state *state =
247 : (struct smb1srv_tcon_local_allocate_state *)private_data;
248 0 : TDB_DATA key = dbwrap_record_get_key(rec);
249 0 : uint32_t id = 0;
250 0 : NTSTATUS status;
251 :
252 0 : status = smbXsrv_tcon_local_key_to_id(key, &id);
253 0 : if (!NT_STATUS_IS_OK(status)) {
254 0 : state->status = status;
255 0 : return -1;
256 : }
257 :
258 0 : if (id <= state->last_id) {
259 0 : state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
260 0 : return -1;
261 : }
262 0 : state->last_id = id;
263 :
264 0 : if (id > state->useable_id) {
265 0 : state->status = NT_STATUS_OK;
266 0 : return -1;
267 : }
268 :
269 0 : if (state->useable_id == state->highest_id) {
270 0 : state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
271 0 : return -1;
272 : }
273 :
274 0 : state->useable_id +=1;
275 0 : return 0;
276 : }
277 :
278 9303 : static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db,
279 : uint32_t lowest_id,
280 : uint32_t highest_id,
281 : TALLOC_CTX *mem_ctx,
282 : struct db_record **_rec,
283 : uint32_t *_id)
284 : {
285 9303 : struct smb1srv_tcon_local_allocate_state state = {
286 : .lowest_id = lowest_id,
287 : .highest_id = highest_id,
288 : .last_id = 0,
289 : .useable_id = lowest_id,
290 : .status = NT_STATUS_INTERNAL_ERROR,
291 : };
292 144 : uint32_t i;
293 144 : uint32_t range;
294 144 : NTSTATUS status;
295 9303 : int count = 0;
296 :
297 9303 : *_rec = NULL;
298 9303 : *_id = 0;
299 :
300 9303 : if (lowest_id > highest_id) {
301 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
302 : }
303 :
304 : /*
305 : * first we try randomly
306 : */
307 9303 : range = (highest_id - lowest_id) + 1;
308 :
309 9303 : for (i = 0; i < (range / 2); i++) {
310 144 : uint32_t id;
311 144 : TDB_DATA val;
312 9303 : struct db_record *rec = NULL;
313 :
314 9303 : id = generate_random() % range;
315 9303 : id += lowest_id;
316 :
317 9303 : if (id < lowest_id) {
318 0 : id = lowest_id;
319 : }
320 9303 : if (id > highest_id) {
321 0 : id = highest_id;
322 : }
323 :
324 9303 : rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
325 9303 : if (rec == NULL) {
326 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
327 : }
328 :
329 9303 : val = dbwrap_record_get_value(rec);
330 9303 : if (val.dsize != 0) {
331 0 : TALLOC_FREE(rec);
332 0 : continue;
333 : }
334 :
335 9303 : *_rec = rec;
336 9303 : *_id = id;
337 9303 : return NT_STATUS_OK;
338 : }
339 :
340 : /*
341 : * if the range is almost full,
342 : * we traverse the whole table
343 : * (this relies on sorted behavior of dbwrap_rbt)
344 : */
345 0 : status = dbwrap_traverse_read(db, smb1srv_tcon_local_allocate_traverse,
346 : &state, &count);
347 0 : if (NT_STATUS_IS_OK(status)) {
348 0 : if (NT_STATUS_IS_OK(state.status)) {
349 0 : return NT_STATUS_INTERNAL_ERROR;
350 : }
351 :
352 0 : if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
353 0 : return state.status;
354 : }
355 :
356 0 : if (state.useable_id <= state.highest_id) {
357 0 : state.status = NT_STATUS_OK;
358 : } else {
359 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
360 : }
361 0 : } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
362 : /*
363 : * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
364 : *
365 : * If we get anything else it is an error, because it
366 : * means we did not manage to find a free slot in
367 : * the db.
368 : */
369 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
370 : }
371 :
372 0 : if (NT_STATUS_IS_OK(state.status)) {
373 0 : uint32_t id;
374 0 : TDB_DATA val;
375 0 : struct db_record *rec = NULL;
376 :
377 0 : id = state.useable_id;
378 :
379 0 : rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
380 0 : if (rec == NULL) {
381 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
382 : }
383 :
384 0 : val = dbwrap_record_get_value(rec);
385 0 : if (val.dsize != 0) {
386 0 : TALLOC_FREE(rec);
387 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
388 : }
389 :
390 0 : *_rec = rec;
391 0 : *_id = id;
392 0 : return NT_STATUS_OK;
393 : }
394 :
395 0 : return state.status;
396 : }
397 :
398 : struct smbXsrv_tcon_local_fetch_state {
399 : struct smbXsrv_tcon *tcon;
400 : NTSTATUS status;
401 : };
402 :
403 1977177 : static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key, TDB_DATA data,
404 : void *private_data)
405 : {
406 1977177 : struct smbXsrv_tcon_local_fetch_state *state =
407 : (struct smbXsrv_tcon_local_fetch_state *)private_data;
408 16245 : void *ptr;
409 :
410 1977177 : if (data.dsize != sizeof(ptr)) {
411 0 : state->status = NT_STATUS_INTERNAL_DB_ERROR;
412 0 : return;
413 : }
414 :
415 1977177 : memcpy(&ptr, data.dptr, data.dsize);
416 1977177 : state->tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
417 1977177 : state->status = NT_STATUS_OK;
418 : }
419 :
420 2024732 : static NTSTATUS smbXsrv_tcon_local_lookup(struct smbXsrv_tcon_table *table,
421 : uint32_t tcon_local_id,
422 : NTTIME now,
423 : struct smbXsrv_tcon **_tcon)
424 : {
425 2024732 : struct smbXsrv_tcon_local_fetch_state state = {
426 : .tcon = NULL,
427 : .status = NT_STATUS_INTERNAL_ERROR,
428 : };
429 17183 : uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
430 17183 : TDB_DATA key;
431 17183 : NTSTATUS status;
432 :
433 2024732 : *_tcon = NULL;
434 :
435 2024732 : if (tcon_local_id == 0) {
436 40230 : return NT_STATUS_NETWORK_NAME_DELETED;
437 : }
438 :
439 1984502 : if (table == NULL) {
440 : /* this might happen before the end of negprot */
441 2 : return NT_STATUS_NETWORK_NAME_DELETED;
442 : }
443 :
444 1984500 : if (table->local.db_ctx == NULL) {
445 0 : return NT_STATUS_INTERNAL_ERROR;
446 : }
447 :
448 1984500 : key = smbXsrv_tcon_local_id_to_key(tcon_local_id, key_buf);
449 :
450 1984500 : status = dbwrap_parse_record(table->local.db_ctx, key,
451 : smbXsrv_tcon_local_fetch_parser,
452 : &state);
453 1984500 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
454 7323 : return NT_STATUS_NETWORK_NAME_DELETED;
455 1977177 : } else if (!NT_STATUS_IS_OK(status)) {
456 0 : return status;
457 : }
458 1977177 : if (!NT_STATUS_IS_OK(state.status)) {
459 0 : return state.status;
460 : }
461 :
462 1977177 : if (NT_STATUS_EQUAL(state.tcon->status, NT_STATUS_NETWORK_NAME_DELETED)) {
463 2 : return NT_STATUS_NETWORK_NAME_DELETED;
464 : }
465 :
466 1977175 : state.tcon->idle_time = now;
467 :
468 1977175 : *_tcon = state.tcon;
469 1977175 : return state.tcon->status;
470 : }
471 :
472 48799 : static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0 *global)
473 : {
474 48799 : return 0;
475 : }
476 :
477 : static void smbXsrv_tcon_global_verify_record(struct db_record *db_rec,
478 : bool *is_free,
479 : bool *was_free,
480 : TALLOC_CTX *mem_ctx,
481 : struct smbXsrv_tcon_global0 **_g);
482 :
483 48813 : static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db,
484 : TALLOC_CTX *mem_ctx,
485 : struct smbXsrv_tcon_global0 **_global)
486 : {
487 765 : uint32_t i;
488 48813 : struct smbXsrv_tcon_global0 *global = NULL;
489 48813 : uint32_t last_free = 0;
490 48813 : const uint32_t min_tries = 3;
491 :
492 48813 : *_global = NULL;
493 :
494 48813 : global = talloc_zero(mem_ctx, struct smbXsrv_tcon_global0);
495 48813 : if (global == NULL) {
496 0 : return NT_STATUS_NO_MEMORY;
497 : }
498 48813 : talloc_set_destructor(global, smbXsrv_tcon_global_destructor);
499 :
500 : /*
501 : * Here we just randomly try the whole 32-bit space
502 : *
503 : * We use just 32-bit, because we want to reuse the
504 : * ID for SRVSVC.
505 : */
506 49578 : for (i = 0; i < UINT32_MAX; i++) {
507 48813 : bool is_free = false;
508 48813 : bool was_free = false;
509 765 : uint32_t id;
510 :
511 48813 : if (i >= min_tries && last_free != 0) {
512 0 : id = last_free;
513 : } else {
514 48813 : id = generate_random();
515 : }
516 48813 : if (id == 0) {
517 0 : id++;
518 : }
519 48813 : if (id == UINT32_MAX) {
520 0 : id--;
521 : }
522 :
523 48813 : global->db_rec = smbXsrv_tcon_global_fetch_locked(db, id,
524 : mem_ctx);
525 48813 : if (global->db_rec == NULL) {
526 0 : talloc_free(global);
527 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
528 : }
529 :
530 48813 : smbXsrv_tcon_global_verify_record(global->db_rec,
531 : &is_free,
532 : &was_free,
533 : NULL, NULL);
534 :
535 48813 : if (!is_free) {
536 0 : TALLOC_FREE(global->db_rec);
537 0 : continue;
538 : }
539 :
540 48813 : if (!was_free && i < min_tries) {
541 : /*
542 : * The session_id is free now,
543 : * but was not free before.
544 : *
545 : * This happens if a smbd crashed
546 : * and did not cleanup the record.
547 : *
548 : * If this is one of our first tries,
549 : * then we try to find a real free one.
550 : */
551 0 : if (last_free == 0) {
552 0 : last_free = id;
553 : }
554 0 : TALLOC_FREE(global->db_rec);
555 0 : continue;
556 : }
557 :
558 48813 : global->tcon_global_id = id;
559 :
560 48813 : *_global = global;
561 48813 : return NT_STATUS_OK;
562 : }
563 :
564 : /* should not be reached */
565 0 : talloc_free(global);
566 0 : return NT_STATUS_INTERNAL_ERROR;
567 : }
568 :
569 48813 : static void smbXsrv_tcon_global_verify_record(struct db_record *db_rec,
570 : bool *is_free,
571 : bool *was_free,
572 : TALLOC_CTX *mem_ctx,
573 : struct smbXsrv_tcon_global0 **_g)
574 : {
575 765 : TDB_DATA key;
576 765 : TDB_DATA val;
577 765 : DATA_BLOB blob;
578 765 : struct smbXsrv_tcon_globalB global_blob;
579 765 : enum ndr_err_code ndr_err;
580 48813 : struct smbXsrv_tcon_global0 *global = NULL;
581 765 : bool exists;
582 48813 : TALLOC_CTX *frame = talloc_stackframe();
583 :
584 48813 : *is_free = false;
585 :
586 48813 : if (was_free) {
587 48813 : *was_free = false;
588 : }
589 48813 : if (_g) {
590 0 : *_g = NULL;
591 : }
592 :
593 48813 : key = dbwrap_record_get_key(db_rec);
594 :
595 48813 : val = dbwrap_record_get_value(db_rec);
596 48813 : if (val.dsize == 0) {
597 48813 : TALLOC_FREE(frame);
598 48813 : *is_free = true;
599 48813 : if (was_free) {
600 48813 : *was_free = true;
601 : }
602 48813 : return;
603 : }
604 :
605 0 : blob = data_blob_const(val.dptr, val.dsize);
606 :
607 0 : ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
608 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB);
609 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
610 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
611 0 : DBG_WARNING("key '%s' ndr_pull_struct_blob - %s\n",
612 : tdb_data_dbg(key),
613 : nt_errstr(status));
614 0 : TALLOC_FREE(frame);
615 0 : return;
616 : }
617 :
618 0 : DBG_DEBUG("smbXsrv_tcon_global_verify_record\n");
619 0 : if (DEBUGLVL(DBGLVL_DEBUG)) {
620 0 : NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
621 : }
622 :
623 0 : if (global_blob.version != SMBXSRV_VERSION_0) {
624 0 : DBG_ERR("key '%s' uses unsupported version %u\n",
625 : tdb_data_dbg(key),
626 : global_blob.version);
627 0 : NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
628 0 : TALLOC_FREE(frame);
629 0 : return;
630 : }
631 :
632 0 : global = global_blob.info.info0;
633 :
634 0 : exists = serverid_exists(&global->server_id);
635 0 : if (!exists) {
636 0 : struct server_id_buf idbuf;
637 0 : DBG_NOTICE("key '%s' server_id %s does not exist.\n",
638 : tdb_data_dbg(key),
639 : server_id_str_buf(global->server_id, &idbuf));
640 0 : if (DEBUGLVL(DBGLVL_NOTICE)) {
641 0 : NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
642 : }
643 0 : TALLOC_FREE(frame);
644 0 : dbwrap_record_delete(db_rec);
645 0 : *is_free = true;
646 0 : return;
647 : }
648 :
649 0 : if (_g) {
650 0 : *_g = talloc_move(mem_ctx, &global);
651 : }
652 0 : TALLOC_FREE(frame);
653 : }
654 :
655 96614 : static NTSTATUS smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0 *global)
656 : {
657 1394 : struct smbXsrv_tcon_globalB global_blob;
658 96614 : DATA_BLOB blob = data_blob_null;
659 1394 : TDB_DATA key;
660 1394 : TDB_DATA val;
661 1394 : NTSTATUS status;
662 1394 : enum ndr_err_code ndr_err;
663 :
664 : /*
665 : * TODO: if we use other versions than '0'
666 : * we would add glue code here, that would be able to
667 : * store the information in the old format.
668 : */
669 :
670 96614 : if (global->db_rec == NULL) {
671 0 : return NT_STATUS_INTERNAL_ERROR;
672 : }
673 :
674 96614 : key = dbwrap_record_get_key(global->db_rec);
675 96614 : val = dbwrap_record_get_value(global->db_rec);
676 :
677 96614 : ZERO_STRUCT(global_blob);
678 96614 : global_blob.version = smbXsrv_version_global_current();
679 96614 : if (val.dsize >= 8) {
680 47801 : global_blob.seqnum = IVAL(val.dptr, 4);
681 : }
682 96614 : global_blob.seqnum += 1;
683 96614 : global_blob.info.info0 = global;
684 :
685 96614 : ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
686 : (ndr_push_flags_fn_t)ndr_push_smbXsrv_tcon_globalB);
687 96614 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
688 0 : status = ndr_map_error2ntstatus(ndr_err);
689 0 : DBG_WARNING("key '%s' ndr_push - %s\n",
690 : tdb_data_dbg(key),
691 : nt_errstr(status));
692 0 : TALLOC_FREE(global->db_rec);
693 0 : return status;
694 : }
695 :
696 96614 : val = make_tdb_data(blob.data, blob.length);
697 96614 : status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
698 96614 : if (!NT_STATUS_IS_OK(status)) {
699 0 : DBG_WARNING("key '%s' store - %s\n",
700 : tdb_data_dbg(key),
701 : nt_errstr(status));
702 0 : TALLOC_FREE(global->db_rec);
703 0 : return status;
704 : }
705 :
706 96614 : if (DEBUGLVL(DBGLVL_DEBUG)) {
707 0 : DBG_DEBUG("key '%s' stored\n", tdb_data_dbg(key));
708 0 : NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
709 : }
710 :
711 96614 : TALLOC_FREE(global->db_rec);
712 :
713 96614 : return NT_STATUS_OK;
714 : }
715 :
716 48799 : static int smbXsrv_tcon_destructor(struct smbXsrv_tcon *tcon)
717 : {
718 765 : NTSTATUS status;
719 :
720 48799 : status = smbXsrv_tcon_disconnect(tcon, 0);
721 48799 : if (!NT_STATUS_IS_OK(status)) {
722 0 : DBG_ERR("smbXsrv_tcon_disconnect() failed - %s\n",
723 : nt_errstr(status));
724 : }
725 :
726 48799 : TALLOC_FREE(tcon->global);
727 :
728 48799 : return 0;
729 : }
730 :
731 48813 : static NTSTATUS smbXsrv_tcon_create(struct smbXsrv_tcon_table *table,
732 : enum protocol_types protocol,
733 : struct server_id server_id,
734 : NTTIME now,
735 : uint32_t session_global_id,
736 : uint8_t encryption_flags,
737 : const char *share_name,
738 : struct smbXsrv_tcon **_tcon)
739 : {
740 48813 : struct db_record *local_rec = NULL;
741 48813 : struct smbXsrv_tcon *tcon = NULL;
742 48813 : void *ptr = NULL;
743 765 : TDB_DATA val;
744 48813 : struct smbXsrv_tcon_global0 *global = NULL;
745 765 : NTSTATUS status;
746 :
747 48813 : if (table->local.num_tcons >= table->local.max_tcons) {
748 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
749 : }
750 :
751 48813 : tcon = talloc_zero(table, struct smbXsrv_tcon);
752 48813 : if (tcon == NULL) {
753 0 : return NT_STATUS_NO_MEMORY;
754 : }
755 48813 : tcon->table = table;
756 48813 : tcon->status = NT_STATUS_INTERNAL_ERROR;
757 48813 : tcon->idle_time = now;
758 :
759 48813 : status = smbXsrv_tcon_global_allocate(table->global.db_ctx,
760 : tcon, &global);
761 48813 : if (!NT_STATUS_IS_OK(status)) {
762 0 : TALLOC_FREE(tcon);
763 0 : return status;
764 : }
765 48813 : tcon->global = global;
766 :
767 48813 : global->session_global_id = session_global_id;
768 48813 : global->encryption_flags = encryption_flags;
769 48813 : global->share_name = talloc_strdup(global, share_name);
770 48813 : if (global->share_name == NULL) {
771 0 : TALLOC_FREE(tcon);
772 0 : return NT_STATUS_NO_MEMORY;
773 : }
774 :
775 48813 : if (protocol >= PROTOCOL_SMB2_02) {
776 39510 : uint64_t id = global->tcon_global_id;
777 :
778 39510 : global->tcon_wire_id = id;
779 :
780 39510 : tcon->local_id = global->tcon_global_id;
781 :
782 39510 : local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
783 : tcon->local_id,
784 : tcon /* TALLOC_CTX */);
785 39510 : if (local_rec == NULL) {
786 0 : TALLOC_FREE(tcon);
787 0 : return NT_STATUS_NO_MEMORY;
788 : }
789 :
790 39510 : val = dbwrap_record_get_value(local_rec);
791 39510 : if (val.dsize != 0) {
792 0 : TALLOC_FREE(tcon);
793 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
794 : }
795 : } else {
796 :
797 9303 : status = smb1srv_tcon_local_allocate_id(table->local.db_ctx,
798 : table->local.lowest_id,
799 : table->local.highest_id,
800 : tcon,
801 : &local_rec,
802 : &tcon->local_id);
803 9303 : if (!NT_STATUS_IS_OK(status)) {
804 0 : TALLOC_FREE(tcon);
805 0 : return status;
806 : }
807 :
808 9303 : global->tcon_wire_id = tcon->local_id;
809 : }
810 :
811 48813 : global->creation_time = now;
812 :
813 48813 : global->server_id = server_id;
814 :
815 48813 : ptr = tcon;
816 48813 : val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
817 48813 : status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
818 48813 : TALLOC_FREE(local_rec);
819 48813 : if (!NT_STATUS_IS_OK(status)) {
820 0 : TALLOC_FREE(tcon);
821 0 : return status;
822 : }
823 48813 : table->local.num_tcons += 1;
824 :
825 48813 : talloc_set_destructor(tcon, smbXsrv_tcon_destructor);
826 :
827 48813 : status = smbXsrv_tcon_global_store(global);
828 48813 : if (!NT_STATUS_IS_OK(status)) {
829 0 : DBG_ERR("global_id (0x%08x) store failed - %s\n",
830 : tcon->global->tcon_global_id,
831 : nt_errstr(status));
832 0 : TALLOC_FREE(tcon);
833 0 : return status;
834 : }
835 :
836 48813 : if (DEBUGLVL(DBGLVL_DEBUG)) {
837 0 : struct smbXsrv_tconB tcon_blob = {
838 : .version = SMBXSRV_VERSION_0,
839 : .info.info0 = tcon,
840 : };
841 :
842 0 : DBG_DEBUG("global_id (0x%08x) stored\n",
843 : tcon->global->tcon_global_id);
844 0 : NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
845 : }
846 :
847 48813 : *_tcon = tcon;
848 48813 : return NT_STATUS_OK;
849 : }
850 :
851 47801 : NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon)
852 : {
853 47801 : struct smbXsrv_tcon_table *table = tcon->table;
854 629 : NTSTATUS status;
855 :
856 47801 : if (tcon->global->db_rec != NULL) {
857 0 : DBG_ERR("update(0x%08x): "
858 : "Called with db_rec != NULL'\n",
859 : tcon->global->tcon_global_id);
860 0 : return NT_STATUS_INTERNAL_ERROR;
861 : }
862 :
863 94973 : tcon->global->db_rec = smbXsrv_tcon_global_fetch_locked(
864 : table->global.db_ctx,
865 47172 : tcon->global->tcon_global_id,
866 47172 : tcon->global /* TALLOC_CTX */);
867 47801 : if (tcon->global->db_rec == NULL) {
868 0 : return NT_STATUS_INTERNAL_DB_ERROR;
869 : }
870 :
871 47801 : status = smbXsrv_tcon_global_store(tcon->global);
872 47801 : if (!NT_STATUS_IS_OK(status)) {
873 0 : DBG_ERR("global_id (0x%08x) store failed - %s\n",
874 : tcon->global->tcon_global_id,
875 : nt_errstr(status));
876 0 : return status;
877 : }
878 :
879 47801 : if (DEBUGLVL(DBGLVL_DEBUG)) {
880 0 : struct smbXsrv_tconB tcon_blob = {
881 : .version = SMBXSRV_VERSION_0,
882 : .info.info0 = tcon,
883 : };
884 :
885 0 : DBG_DEBUG("global_id (0x%08x) stored\n",
886 : tcon->global->tcon_global_id);
887 0 : NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
888 : }
889 :
890 47801 : return NT_STATUS_OK;
891 : }
892 :
893 97482 : NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid)
894 : {
895 1524 : struct smbXsrv_tcon_table *table;
896 97482 : struct db_record *local_rec = NULL;
897 97482 : struct db_record *global_rec = NULL;
898 1524 : NTSTATUS status;
899 97482 : NTSTATUS error = NT_STATUS_OK;
900 :
901 97482 : if (tcon->table == NULL) {
902 48683 : return NT_STATUS_OK;
903 : }
904 :
905 48799 : table = tcon->table;
906 48799 : tcon->table = NULL;
907 :
908 48799 : if (tcon->compat) {
909 759 : bool ok;
910 :
911 48683 : ok = chdir_current_service(tcon->compat);
912 48683 : if (!ok) {
913 52 : status = NT_STATUS_INTERNAL_ERROR;
914 52 : DBG_ERR("disconnect(0x%08x, '%s'): "
915 : "chdir_current_service() failed: %s\n",
916 : tcon->global->tcon_global_id,
917 : tcon->global->share_name,
918 : nt_errstr(status));
919 : /*
920 : * We must call close_cnum() on
921 : * error, as the caller is going
922 : * to free tcon and tcon->compat
923 : * so we must ensure tcon->compat is
924 : * removed from the linked list
925 : * conn->sconn->connections.
926 : */
927 52 : close_cnum(tcon->compat, vuid, ERROR_CLOSE);
928 52 : tcon->compat = NULL;
929 52 : return status;
930 : }
931 :
932 48631 : close_cnum(tcon->compat, vuid, SHUTDOWN_CLOSE);
933 48631 : tcon->compat = NULL;
934 : }
935 :
936 48747 : tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
937 :
938 48747 : global_rec = tcon->global->db_rec;
939 48747 : tcon->global->db_rec = NULL;
940 48747 : if (global_rec == NULL) {
941 48747 : global_rec = smbXsrv_tcon_global_fetch_locked(
942 : table->global.db_ctx,
943 47982 : tcon->global->tcon_global_id,
944 47982 : tcon->global /* TALLOC_CTX */);
945 48747 : if (global_rec == NULL) {
946 0 : error = NT_STATUS_INTERNAL_ERROR;
947 : }
948 : }
949 :
950 48747 : if (global_rec != NULL) {
951 48747 : status = dbwrap_record_delete(global_rec);
952 48747 : if (!NT_STATUS_IS_OK(status)) {
953 0 : TDB_DATA key = dbwrap_record_get_key(global_rec);
954 :
955 0 : DBG_ERR("disconnect(0x%08x, '%s'): "
956 : "failed to delete global key '%s': %s\n",
957 : tcon->global->tcon_global_id,
958 : tcon->global->share_name,
959 : tdb_data_dbg(key),
960 : nt_errstr(status));
961 0 : error = status;
962 : }
963 : }
964 48747 : TALLOC_FREE(global_rec);
965 :
966 48747 : local_rec = tcon->db_rec;
967 48747 : if (local_rec == NULL) {
968 33077 : local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
969 : tcon->local_id,
970 : tcon /* TALLOC_CTX */);
971 33077 : if (local_rec == NULL) {
972 0 : error = NT_STATUS_INTERNAL_ERROR;
973 : }
974 : }
975 :
976 48747 : if (local_rec != NULL) {
977 48747 : status = dbwrap_record_delete(local_rec);
978 48747 : if (!NT_STATUS_IS_OK(status)) {
979 0 : TDB_DATA key = dbwrap_record_get_key(local_rec);
980 :
981 0 : DBG_ERR("disconnect(0x%08x, '%s'): "
982 : "failed to delete local key '%s': %s\n",
983 : tcon->global->tcon_global_id,
984 : tcon->global->share_name,
985 : tdb_data_dbg(key),
986 : nt_errstr(status));
987 0 : error = status;
988 : }
989 48747 : table->local.num_tcons -= 1;
990 : }
991 48747 : if (tcon->db_rec == NULL) {
992 33077 : TALLOC_FREE(local_rec);
993 : }
994 48747 : tcon->db_rec = NULL;
995 :
996 48747 : return error;
997 : }
998 :
999 : struct smbXsrv_tcon_disconnect_all_state {
1000 : uint64_t vuid;
1001 : NTSTATUS first_status;
1002 : int errors;
1003 : };
1004 :
1005 : static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec,
1006 : void *private_data);
1007 :
1008 56758 : static NTSTATUS smbXsrv_tcon_disconnect_all(struct smbXsrv_tcon_table *table,
1009 : uint64_t vuid)
1010 : {
1011 56758 : struct smbXsrv_tcon_disconnect_all_state state = { .vuid = vuid };
1012 1469 : NTSTATUS status;
1013 56758 : int count = 0;
1014 :
1015 56758 : if (table == NULL) {
1016 25784 : return NT_STATUS_OK;
1017 : }
1018 :
1019 30974 : status = dbwrap_traverse(table->local.db_ctx,
1020 : smbXsrv_tcon_disconnect_all_callback,
1021 : &state, &count);
1022 30974 : if (!NT_STATUS_IS_OK(status)) {
1023 0 : DBG_ERR("dbwrap_traverse() failed: %s\n", nt_errstr(status));
1024 0 : return status;
1025 : }
1026 :
1027 30974 : if (!NT_STATUS_IS_OK(state.first_status)) {
1028 52 : DBG_ERR("count[%d] errors[%d] first[%s]\n",
1029 : count,
1030 : state.errors,
1031 : nt_errstr(state.first_status));
1032 52 : return state.first_status;
1033 : }
1034 :
1035 30922 : return NT_STATUS_OK;
1036 : }
1037 :
1038 15722 : static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec,
1039 : void *private_data)
1040 : {
1041 15722 : struct smbXsrv_tcon_disconnect_all_state *state =
1042 : (struct smbXsrv_tcon_disconnect_all_state *)private_data;
1043 743 : TDB_DATA val;
1044 15722 : void *ptr = NULL;
1045 15722 : struct smbXsrv_tcon *tcon = NULL;
1046 743 : uint64_t vuid;
1047 743 : NTSTATUS status;
1048 :
1049 15722 : val = dbwrap_record_get_value(local_rec);
1050 15722 : if (val.dsize != sizeof(ptr)) {
1051 0 : status = NT_STATUS_INTERNAL_ERROR;
1052 0 : if (NT_STATUS_IS_OK(state->first_status)) {
1053 0 : state->first_status = status;
1054 : }
1055 0 : state->errors++;
1056 0 : return 0;
1057 : }
1058 :
1059 15722 : memcpy(&ptr, val.dptr, val.dsize);
1060 15722 : tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
1061 :
1062 15722 : vuid = state->vuid;
1063 15722 : if (vuid == 0 && tcon->compat) {
1064 2113 : vuid = tcon->compat->vuid;
1065 : }
1066 :
1067 15722 : tcon->db_rec = local_rec;
1068 15722 : status = smbXsrv_tcon_disconnect(tcon, vuid);
1069 15722 : tcon->db_rec = NULL;
1070 15722 : if (!NT_STATUS_IS_OK(status)) {
1071 52 : if (NT_STATUS_IS_OK(state->first_status)) {
1072 52 : state->first_status = status;
1073 : }
1074 52 : state->errors++;
1075 52 : return 0;
1076 : }
1077 :
1078 14927 : return 0;
1079 : }
1080 :
1081 5777 : NTSTATUS smb1srv_tcon_table_init(struct smbXsrv_connection *conn)
1082 : {
1083 5777 : struct smbXsrv_client *client = conn->client;
1084 :
1085 : /*
1086 : * Allow a range from 1..65534 with 65534 values.
1087 : */
1088 5777 : client->tcon_table = talloc_zero(client, struct smbXsrv_tcon_table);
1089 5777 : if (client->tcon_table == NULL) {
1090 0 : return NT_STATUS_NO_MEMORY;
1091 : }
1092 :
1093 5777 : return smbXsrv_tcon_table_init(client, client->tcon_table,
1094 : 1, UINT16_MAX - 1,
1095 : UINT16_MAX - 1);
1096 : }
1097 :
1098 9303 : NTSTATUS smb1srv_tcon_create(struct smbXsrv_connection *conn,
1099 : uint32_t session_global_id,
1100 : const char *share_name,
1101 : NTTIME now,
1102 : struct smbXsrv_tcon **_tcon)
1103 : {
1104 9303 : struct server_id id = messaging_server_id(conn->client->msg_ctx);
1105 9303 : const uint8_t encryption_flags = 0;
1106 :
1107 9303 : return smbXsrv_tcon_create(conn->client->tcon_table,
1108 : conn->protocol,
1109 : id, now,
1110 : session_global_id,
1111 : encryption_flags,
1112 : share_name,
1113 : _tcon);
1114 : }
1115 :
1116 674563 : NTSTATUS smb1srv_tcon_lookup(struct smbXsrv_connection *conn,
1117 : uint16_t tree_id, NTTIME now,
1118 : struct smbXsrv_tcon **tcon)
1119 : {
1120 674563 : uint32_t local_id = tree_id;
1121 :
1122 674563 : return smbXsrv_tcon_local_lookup(conn->client->tcon_table,
1123 : local_id, now, tcon);
1124 : }
1125 :
1126 31549 : NTSTATUS smb1srv_tcon_disconnect_all(struct smbXsrv_client *client)
1127 : {
1128 :
1129 : /*
1130 : * We do not pass a vuid here,
1131 : * which means the vuid is taken from
1132 : * the tcon->compat->vuid.
1133 : *
1134 : * NOTE: that tcon->compat->vuid may point to
1135 : * a none existing vuid (or the wrong one)
1136 : * as the tcon can exist without a session
1137 : * in SMB1.
1138 : *
1139 : * This matches the old behavior of
1140 : * conn_close_all(), but we should think
1141 : * about how to fix this in future.
1142 : */
1143 31549 : return smbXsrv_tcon_disconnect_all(client->tcon_table, 0);
1144 : }
1145 :
1146 25211 : NTSTATUS smb2srv_tcon_table_init(struct smbXsrv_session *session)
1147 : {
1148 : /*
1149 : * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1150 : */
1151 25211 : session->tcon_table = talloc_zero(session, struct smbXsrv_tcon_table);
1152 25211 : if (session->tcon_table == NULL) {
1153 0 : return NT_STATUS_NO_MEMORY;
1154 : }
1155 :
1156 25211 : return smbXsrv_tcon_table_init(session, session->tcon_table,
1157 : 1, UINT32_MAX - 1,
1158 : UINT16_MAX - 1);
1159 : }
1160 :
1161 39510 : NTSTATUS smb2srv_tcon_create(struct smbXsrv_session *session,
1162 : uint32_t session_global_id,
1163 : uint8_t encryption_flags,
1164 : const char *share_name,
1165 : NTTIME now,
1166 : struct smbXsrv_tcon **_tcon)
1167 : {
1168 39510 : struct server_id id = messaging_server_id(session->client->msg_ctx);
1169 :
1170 39510 : return smbXsrv_tcon_create(session->tcon_table,
1171 : PROTOCOL_SMB2_02,
1172 : id, now,
1173 : session_global_id,
1174 : encryption_flags,
1175 : share_name,
1176 : _tcon);
1177 : }
1178 :
1179 1350169 : NTSTATUS smb2srv_tcon_lookup(struct smbXsrv_session *session,
1180 : uint32_t tree_id, NTTIME now,
1181 : struct smbXsrv_tcon **tcon)
1182 : {
1183 1350169 : uint32_t local_id = tree_id;
1184 :
1185 1350169 : return smbXsrv_tcon_local_lookup(session->tcon_table,
1186 : local_id, now, tcon);
1187 : }
1188 :
1189 25209 : NTSTATUS smb2srv_tcon_disconnect_all(struct smbXsrv_session *session)
1190 : {
1191 25209 : uint64_t vuid = session->global->session_wire_id;
1192 :
1193 25209 : return smbXsrv_tcon_disconnect_all(session->tcon_table, vuid);
1194 : }
1195 :
1196 : struct smbXsrv_tcon_global_traverse_state {
1197 : int (*fn)(struct smbXsrv_tcon_global0 *, void *);
1198 : void *private_data;
1199 : };
1200 :
1201 189 : static int smbXsrv_tcon_global_traverse_fn(struct db_record *rec, void *data)
1202 : {
1203 189 : int ret = -1;
1204 189 : struct smbXsrv_tcon_global_traverse_state *state =
1205 : (struct smbXsrv_tcon_global_traverse_state*)data;
1206 189 : TDB_DATA key = dbwrap_record_get_key(rec);
1207 189 : TDB_DATA val = dbwrap_record_get_value(rec);
1208 189 : DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
1209 0 : struct smbXsrv_tcon_globalB global_blob;
1210 0 : enum ndr_err_code ndr_err;
1211 189 : TALLOC_CTX *frame = talloc_stackframe();
1212 :
1213 189 : ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
1214 : (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB);
1215 189 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1216 0 : DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
1217 : "key '%s' ndr_pull_struct_blob - %s\n",
1218 : tdb_data_dbg(key),
1219 : ndr_errstr(ndr_err));
1220 0 : goto done;
1221 : }
1222 :
1223 189 : if (global_blob.version != SMBXSRV_VERSION_0) {
1224 0 : DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
1225 : "key '%s' unsupported version - %d\n",
1226 : tdb_data_dbg(key),
1227 : (int)global_blob.version);
1228 0 : goto done;
1229 : }
1230 :
1231 189 : if (global_blob.info.info0 == NULL) {
1232 0 : DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
1233 : "key '%s' info0 NULL pointer\n",
1234 : tdb_data_dbg(key));
1235 0 : goto done;
1236 : }
1237 :
1238 189 : global_blob.info.info0->db_rec = rec;
1239 189 : ret = state->fn(global_blob.info.info0, state->private_data);
1240 189 : done:
1241 189 : TALLOC_FREE(frame);
1242 189 : return ret;
1243 : }
1244 :
1245 69 : NTSTATUS smbXsrv_tcon_global_traverse(
1246 : int (*fn)(struct smbXsrv_tcon_global0 *, void *),
1247 : void *private_data)
1248 : {
1249 0 : NTSTATUS status;
1250 69 : int count = 0;
1251 69 : struct smbXsrv_tcon_global_traverse_state state = {
1252 : .fn = fn,
1253 : .private_data = private_data,
1254 : };
1255 :
1256 69 : become_root();
1257 69 : status = smbXsrv_tcon_global_init();
1258 69 : if (!NT_STATUS_IS_OK(status)) {
1259 0 : unbecome_root();
1260 0 : DBG_ERR("Failed to initialize tcon_global: %s\n",
1261 : nt_errstr(status));
1262 0 : return status;
1263 : }
1264 :
1265 69 : status = dbwrap_traverse_read(smbXsrv_tcon_global_db_ctx,
1266 : smbXsrv_tcon_global_traverse_fn,
1267 : &state,
1268 : &count);
1269 69 : unbecome_root();
1270 :
1271 69 : return status;
1272 : }
|