auth/credentials: don't ignore "client use kerberos" and --use-kerberos for machine...
[samba.git] / source3 / smbd / smbXsrv_tcon.c
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 NTSTATUS smbXsrv_tcon_global_init(void)
51 {
52         char *global_path = NULL;
53         struct db_context *db_ctx = NULL;
54
55         if (smbXsrv_tcon_global_db_ctx != NULL) {
56                 return NT_STATUS_OK;
57         }
58
59         global_path = lock_path(talloc_tos(), "smbXsrv_tcon_global.tdb");
60         if (global_path == NULL) {
61                 return NT_STATUS_NO_MEMORY;
62         }
63
64         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         TALLOC_FREE(global_path);
71         if (db_ctx == NULL) {
72                 NTSTATUS status;
73
74                 status = map_nt_error_from_unix_common(errno);
75
76                 return status;
77         }
78
79         smbXsrv_tcon_global_db_ctx = db_ctx;
80
81         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 static TDB_DATA smbXsrv_tcon_global_id_to_key(uint32_t id,
96                                               uint8_t *key_buf)
97 {
98         TDB_DATA key;
99
100         RSIVAL(key_buf, 0, id);
101
102         key = make_tdb_data(key_buf, SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE);
103
104         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 static TDB_DATA smbXsrv_tcon_local_id_to_key(uint32_t id,
127                                              uint8_t *key_buf)
128 {
129         TDB_DATA key;
130
131         RSIVAL(key_buf, 0, id);
132
133         key = make_tdb_data(key_buf, SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE);
134
135         return key;
136 }
137
138 static NTSTATUS smbXsrv_tcon_local_key_to_id(TDB_DATA key, uint32_t *id)
139 {
140         if (id == NULL) {
141                 return NT_STATUS_INVALID_PARAMETER;
142         }
143
144         if (key.dsize != SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE) {
145                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
146         }
147
148         *id = RIVAL(key.dptr, 0);
149
150         return NT_STATUS_OK;
151 }
152
153 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         TDB_DATA key;
159         uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE];
160         struct db_record *rec = NULL;
161
162         key = smbXsrv_tcon_global_id_to_key(id, key_buf);
163
164         rec = dbwrap_fetch_locked(db, mem_ctx, key);
165
166         if (rec == NULL) {
167                 DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
168                           tdb_data_dbg(key));
169         }
170
171         return rec;
172 }
173
174 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         TDB_DATA key;
180         uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
181         struct db_record *rec = NULL;
182
183         key = smbXsrv_tcon_local_id_to_key(id, key_buf);
184
185         rec = dbwrap_fetch_locked(db, mem_ctx, key);
186
187         if (rec == NULL) {
188                 DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
189                           tdb_data_dbg(key));
190         }
191
192         return rec;
193 }
194
195 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         NTSTATUS status;
202         uint64_t max_range;
203
204         if (lowest_id > highest_id) {
205                 return NT_STATUS_INTERNAL_ERROR;
206         }
207
208         max_range = highest_id;
209         max_range -= lowest_id;
210         max_range += 1;
211
212         if (max_tcons > max_range) {
213                 return NT_STATUS_INTERNAL_ERROR;
214         }
215
216         ZERO_STRUCTP(table);
217         table->local.db_ctx = db_open_rbt(table);
218         if (table->local.db_ctx == NULL) {
219                 return NT_STATUS_NO_MEMORY;
220         }
221         table->local.lowest_id = lowest_id;
222         table->local.highest_id = highest_id;
223         table->local.max_tcons = max_tcons;
224
225         status = smbXsrv_tcon_global_init();
226         if (!NT_STATUS_IS_OK(status)) {
227                 return status;
228         }
229
230         table->global.db_ctx = smbXsrv_tcon_global_db_ctx;
231
232         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 static int smb1srv_tcon_local_allocate_traverse(struct db_record *rec,
244                                                    void *private_data)
245 {
246         struct smb1srv_tcon_local_allocate_state *state =
247                 (struct smb1srv_tcon_local_allocate_state *)private_data;
248         TDB_DATA key = dbwrap_record_get_key(rec);
249         uint32_t id = 0;
250         NTSTATUS status;
251
252         status = smbXsrv_tcon_local_key_to_id(key, &id);
253         if (!NT_STATUS_IS_OK(status)) {
254                 state->status = status;
255                 return -1;
256         }
257
258         if (id <= state->last_id) {
259                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
260                 return -1;
261         }
262         state->last_id = id;
263
264         if (id > state->useable_id) {
265                 state->status = NT_STATUS_OK;
266                 return -1;
267         }
268
269         if (state->useable_id == state->highest_id) {
270                 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
271                 return -1;
272         }
273
274         state->useable_id +=1;
275         return 0;
276 }
277
278 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         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         uint32_t i;
293         uint32_t range;
294         NTSTATUS status;
295         int count = 0;
296
297         *_rec = NULL;
298         *_id = 0;
299
300         if (lowest_id > highest_id) {
301                 return NT_STATUS_INSUFFICIENT_RESOURCES;
302         }
303
304         /*
305          * first we try randomly
306          */
307         range = (highest_id - lowest_id) + 1;
308
309         for (i = 0; i < (range / 2); i++) {
310                 uint32_t id;
311                 TDB_DATA val;
312                 struct db_record *rec = NULL;
313
314                 id = generate_random() % range;
315                 id += lowest_id;
316
317                 if (id < lowest_id) {
318                         id = lowest_id;
319                 }
320                 if (id > highest_id) {
321                         id = highest_id;
322                 }
323
324                 rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
325                 if (rec == NULL) {
326                         return NT_STATUS_INSUFFICIENT_RESOURCES;
327                 }
328
329                 val = dbwrap_record_get_value(rec);
330                 if (val.dsize != 0) {
331                         TALLOC_FREE(rec);
332                         continue;
333                 }
334
335                 *_rec = rec;
336                 *_id = id;
337                 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         status = dbwrap_traverse_read(db, smb1srv_tcon_local_allocate_traverse,
346                                       &state, &count);
347         if (NT_STATUS_IS_OK(status)) {
348                 if (NT_STATUS_IS_OK(state.status)) {
349                         return NT_STATUS_INTERNAL_ERROR;
350                 }
351
352                 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
353                         return state.status;
354                 }
355
356                 if (state.useable_id <= state.highest_id) {
357                         state.status = NT_STATUS_OK;
358                 } else {
359                         return NT_STATUS_INSUFFICIENT_RESOURCES;
360                 }
361         } 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                 return NT_STATUS_INSUFFICIENT_RESOURCES;
370         }
371
372         if (NT_STATUS_IS_OK(state.status)) {
373                 uint32_t id;
374                 TDB_DATA val;
375                 struct db_record *rec = NULL;
376
377                 id = state.useable_id;
378
379                 rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
380                 if (rec == NULL) {
381                         return NT_STATUS_INSUFFICIENT_RESOURCES;
382                 }
383
384                 val = dbwrap_record_get_value(rec);
385                 if (val.dsize != 0) {
386                         TALLOC_FREE(rec);
387                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
388                 }
389
390                 *_rec = rec;
391                 *_id = id;
392                 return NT_STATUS_OK;
393         }
394
395         return state.status;
396 }
397
398 struct smbXsrv_tcon_local_fetch_state {
399         struct smbXsrv_tcon *tcon;
400         NTSTATUS status;
401 };
402
403 static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key, TDB_DATA data,
404                                             void *private_data)
405 {
406         struct smbXsrv_tcon_local_fetch_state *state =
407                 (struct smbXsrv_tcon_local_fetch_state *)private_data;
408         void *ptr;
409
410         if (data.dsize != sizeof(ptr)) {
411                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
412                 return;
413         }
414
415         memcpy(&ptr, data.dptr, data.dsize);
416         state->tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
417         state->status = NT_STATUS_OK;
418 }
419
420 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         struct smbXsrv_tcon_local_fetch_state state = {
426                 .tcon = NULL,
427                 .status = NT_STATUS_INTERNAL_ERROR,
428         };
429         uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
430         TDB_DATA key;
431         NTSTATUS status;
432
433         *_tcon = NULL;
434
435         if (tcon_local_id == 0) {
436                 return NT_STATUS_NETWORK_NAME_DELETED;
437         }
438
439         if (table == NULL) {
440                 /* this might happen before the end of negprot */
441                 return NT_STATUS_NETWORK_NAME_DELETED;
442         }
443
444         if (table->local.db_ctx == NULL) {
445                 return NT_STATUS_INTERNAL_ERROR;
446         }
447
448         key = smbXsrv_tcon_local_id_to_key(tcon_local_id, key_buf);
449
450         status = dbwrap_parse_record(table->local.db_ctx, key,
451                                      smbXsrv_tcon_local_fetch_parser,
452                                      &state);
453         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
454                 return NT_STATUS_NETWORK_NAME_DELETED;
455         } else if (!NT_STATUS_IS_OK(status)) {
456                 return status;
457         }
458         if (!NT_STATUS_IS_OK(state.status)) {
459                 return state.status;
460         }
461
462         if (NT_STATUS_EQUAL(state.tcon->status, NT_STATUS_NETWORK_NAME_DELETED)) {
463                 return NT_STATUS_NETWORK_NAME_DELETED;
464         }
465
466         state.tcon->idle_time = now;
467
468         *_tcon = state.tcon;
469         return state.tcon->status;
470 }
471
472 static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0 *global)
473 {
474         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 static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db,
484                                         TALLOC_CTX *mem_ctx,
485                                         struct smbXsrv_tcon_global0 **_global)
486 {
487         uint32_t i;
488         struct smbXsrv_tcon_global0 *global = NULL;
489         uint32_t last_free = 0;
490         const uint32_t min_tries = 3;
491
492         *_global = NULL;
493
494         global = talloc_zero(mem_ctx, struct smbXsrv_tcon_global0);
495         if (global == NULL) {
496                 return NT_STATUS_NO_MEMORY;
497         }
498         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         for (i = 0; i < UINT32_MAX; i++) {
507                 bool is_free = false;
508                 bool was_free = false;
509                 uint32_t id;
510
511                 if (i >= min_tries && last_free != 0) {
512                         id = last_free;
513                 } else {
514                         id = generate_random();
515                 }
516                 if (id == 0) {
517                         id++;
518                 }
519                 if (id == UINT32_MAX) {
520                         id--;
521                 }
522
523                 global->db_rec = smbXsrv_tcon_global_fetch_locked(db, id,
524                                                                   mem_ctx);
525                 if (global->db_rec == NULL) {
526                         talloc_free(global);
527                         return NT_STATUS_INSUFFICIENT_RESOURCES;
528                 }
529
530                 smbXsrv_tcon_global_verify_record(global->db_rec,
531                                                   &is_free,
532                                                   &was_free,
533                                                   NULL, NULL);
534
535                 if (!is_free) {
536                         TALLOC_FREE(global->db_rec);
537                         continue;
538                 }
539
540                 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                         if (last_free == 0) {
552                                 last_free = id;
553                         }
554                         TALLOC_FREE(global->db_rec);
555                         continue;
556                 }
557
558                 global->tcon_global_id = id;
559
560                 *_global = global;
561                 return NT_STATUS_OK;
562         }
563
564         /* should not be reached */
565         talloc_free(global);
566         return NT_STATUS_INTERNAL_ERROR;
567 }
568
569 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         TDB_DATA key;
576         TDB_DATA val;
577         DATA_BLOB blob;
578         struct smbXsrv_tcon_globalB global_blob;
579         enum ndr_err_code ndr_err;
580         struct smbXsrv_tcon_global0 *global = NULL;
581         bool exists;
582         TALLOC_CTX *frame = talloc_stackframe();
583
584         *is_free = false;
585
586         if (was_free) {
587                 *was_free = false;
588         }
589         if (_g) {
590                 *_g = NULL;
591         }
592
593         key = dbwrap_record_get_key(db_rec);
594
595         val = dbwrap_record_get_value(db_rec);
596         if (val.dsize == 0) {
597                 TALLOC_FREE(frame);
598                 *is_free = true;
599                 if (was_free) {
600                         *was_free = true;
601                 }
602                 return;
603         }
604
605         blob = data_blob_const(val.dptr, val.dsize);
606
607         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
608                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB);
609         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
610                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
611                 DBG_WARNING("key '%s' ndr_pull_struct_blob - %s\n",
612                             tdb_data_dbg(key),
613                             nt_errstr(status));
614                 TALLOC_FREE(frame);
615                 return;
616         }
617
618         DBG_DEBUG("smbXsrv_tcon_global_verify_record\n");
619         if (DEBUGLVL(DBGLVL_DEBUG)) {
620                 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
621         }
622
623         if (global_blob.version != SMBXSRV_VERSION_0) {
624                 DBG_ERR("key '%s' uses unsupported version %u\n",
625                         tdb_data_dbg(key),
626                         global_blob.version);
627                 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
628                 TALLOC_FREE(frame);
629                 return;
630         }
631
632         global = global_blob.info.info0;
633
634         exists = serverid_exists(&global->server_id);
635         if (!exists) {
636                 struct server_id_buf idbuf;
637                 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                 if (DEBUGLVL(DBGLVL_NOTICE)) {
641                         NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
642                 }
643                 TALLOC_FREE(frame);
644                 dbwrap_record_delete(db_rec);
645                 *is_free = true;
646                 return;
647         }
648
649         if (_g) {
650                 *_g = talloc_move(mem_ctx, &global);
651         }
652         TALLOC_FREE(frame);
653 }
654
655 static NTSTATUS smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0 *global)
656 {
657         struct smbXsrv_tcon_globalB global_blob;
658         DATA_BLOB blob = data_blob_null;
659         TDB_DATA key;
660         TDB_DATA val;
661         NTSTATUS status;
662         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         if (global->db_rec == NULL) {
671                 return NT_STATUS_INTERNAL_ERROR;
672         }
673
674         key = dbwrap_record_get_key(global->db_rec);
675         val = dbwrap_record_get_value(global->db_rec);
676
677         ZERO_STRUCT(global_blob);
678         global_blob.version = smbXsrv_version_global_current();
679         if (val.dsize >= 8) {
680                 global_blob.seqnum = IVAL(val.dptr, 4);
681         }
682         global_blob.seqnum += 1;
683         global_blob.info.info0 = global;
684
685         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
686                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_tcon_globalB);
687         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
688                 status = ndr_map_error2ntstatus(ndr_err);
689                 DBG_WARNING("key '%s' ndr_push - %s\n",
690                             tdb_data_dbg(key),
691                             nt_errstr(status));
692                 TALLOC_FREE(global->db_rec);
693                 return status;
694         }
695
696         val = make_tdb_data(blob.data, blob.length);
697         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
698         if (!NT_STATUS_IS_OK(status)) {
699                 DBG_WARNING("key '%s' store - %s\n",
700                             tdb_data_dbg(key),
701                             nt_errstr(status));
702                 TALLOC_FREE(global->db_rec);
703                 return status;
704         }
705
706         if (DEBUGLVL(DBGLVL_DEBUG)) {
707                 DBG_DEBUG("key '%s' stored\n", tdb_data_dbg(key));
708                 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
709         }
710
711         TALLOC_FREE(global->db_rec);
712
713         return NT_STATUS_OK;
714 }
715
716 static int smbXsrv_tcon_destructor(struct smbXsrv_tcon *tcon)
717 {
718         NTSTATUS status;
719
720         status = smbXsrv_tcon_disconnect(tcon, 0);
721         if (!NT_STATUS_IS_OK(status)) {
722                 DBG_ERR("smbXsrv_tcon_disconnect() failed - %s\n",
723                         nt_errstr(status));
724         }
725
726         TALLOC_FREE(tcon->global);
727
728         return 0;
729 }
730
731 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         struct db_record *local_rec = NULL;
741         struct smbXsrv_tcon *tcon = NULL;
742         void *ptr = NULL;
743         TDB_DATA val;
744         struct smbXsrv_tcon_global0 *global = NULL;
745         NTSTATUS status;
746
747         if (table->local.num_tcons >= table->local.max_tcons) {
748                 return NT_STATUS_INSUFFICIENT_RESOURCES;
749         }
750
751         tcon = talloc_zero(table, struct smbXsrv_tcon);
752         if (tcon == NULL) {
753                 return NT_STATUS_NO_MEMORY;
754         }
755         tcon->table = table;
756         tcon->status = NT_STATUS_INTERNAL_ERROR;
757         tcon->idle_time = now;
758
759         status = smbXsrv_tcon_global_allocate(table->global.db_ctx,
760                                               tcon, &global);
761         if (!NT_STATUS_IS_OK(status)) {
762                 TALLOC_FREE(tcon);
763                 return status;
764         }
765         tcon->global = global;
766
767         global->session_global_id = session_global_id;
768         global->encryption_flags = encryption_flags;
769         global->share_name = talloc_strdup(global, share_name);
770         if (global->share_name == NULL) {
771                 TALLOC_FREE(tcon);
772                 return NT_STATUS_NO_MEMORY;
773         }
774
775         if (protocol >= PROTOCOL_SMB2_02) {
776                 uint64_t id = global->tcon_global_id;
777
778                 global->tcon_wire_id = id;
779
780                 tcon->local_id = global->tcon_global_id;
781
782                 local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
783                                                         tcon->local_id,
784                                                         tcon /* TALLOC_CTX */);
785                 if (local_rec == NULL) {
786                         TALLOC_FREE(tcon);
787                         return NT_STATUS_NO_MEMORY;
788                 }
789
790                 val = dbwrap_record_get_value(local_rec);
791                 if (val.dsize != 0) {
792                         TALLOC_FREE(tcon);
793                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
794                 }
795         } else {
796
797                 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                 if (!NT_STATUS_IS_OK(status)) {
804                         TALLOC_FREE(tcon);
805                         return status;
806                 }
807
808                 global->tcon_wire_id = tcon->local_id;
809         }
810
811         global->creation_time = now;
812
813         global->server_id = server_id;
814
815         ptr = tcon;
816         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
817         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
818         TALLOC_FREE(local_rec);
819         if (!NT_STATUS_IS_OK(status)) {
820                 TALLOC_FREE(tcon);
821                 return status;
822         }
823         table->local.num_tcons += 1;
824
825         talloc_set_destructor(tcon, smbXsrv_tcon_destructor);
826
827         status = smbXsrv_tcon_global_store(global);
828         if (!NT_STATUS_IS_OK(status)) {
829                 DBG_ERR("global_id (0x%08x) store failed - %s\n",
830                         tcon->global->tcon_global_id,
831                         nt_errstr(status));
832                 TALLOC_FREE(tcon);
833                 return status;
834         }
835
836         if (DEBUGLVL(DBGLVL_DEBUG)) {
837                 struct smbXsrv_tconB tcon_blob = {
838                         .version = SMBXSRV_VERSION_0,
839                         .info.info0 = tcon,
840                 };
841
842                 DBG_DEBUG("global_id (0x%08x) stored\n",
843                           tcon->global->tcon_global_id);
844                 NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
845         }
846
847         *_tcon = tcon;
848         return NT_STATUS_OK;
849 }
850
851 NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon)
852 {
853         struct smbXsrv_tcon_table *table = tcon->table;
854         NTSTATUS status;
855
856         if (tcon->global->db_rec != NULL) {
857                 DBG_ERR("update(0x%08x): "
858                         "Called with db_rec != NULL'\n",
859                         tcon->global->tcon_global_id);
860                 return NT_STATUS_INTERNAL_ERROR;
861         }
862
863         tcon->global->db_rec = smbXsrv_tcon_global_fetch_locked(
864                                                 table->global.db_ctx,
865                                                 tcon->global->tcon_global_id,
866                                                 tcon->global /* TALLOC_CTX */);
867         if (tcon->global->db_rec == NULL) {
868                 return NT_STATUS_INTERNAL_DB_ERROR;
869         }
870
871         status = smbXsrv_tcon_global_store(tcon->global);
872         if (!NT_STATUS_IS_OK(status)) {
873                 DBG_ERR("global_id (0x%08x) store failed - %s\n",
874                         tcon->global->tcon_global_id,
875                         nt_errstr(status));
876                 return status;
877         }
878
879         if (DEBUGLVL(DBGLVL_DEBUG)) {
880                 struct smbXsrv_tconB tcon_blob = {
881                         .version = SMBXSRV_VERSION_0,
882                         .info.info0 = tcon,
883                 };
884
885                 DBG_DEBUG("global_id (0x%08x) stored\n",
886                           tcon->global->tcon_global_id);
887                 NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
888         }
889
890         return NT_STATUS_OK;
891 }
892
893 NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid)
894 {
895         struct smbXsrv_tcon_table *table;
896         struct db_record *local_rec = NULL;
897         struct db_record *global_rec = NULL;
898         NTSTATUS status;
899         NTSTATUS error = NT_STATUS_OK;
900
901         if (tcon->table == NULL) {
902                 return NT_STATUS_OK;
903         }
904
905         table = tcon->table;
906         tcon->table = NULL;
907
908         if (tcon->compat) {
909                 bool ok;
910
911                 ok = chdir_current_service(tcon->compat);
912                 if (!ok) {
913                         status = NT_STATUS_INTERNAL_ERROR;
914                         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                         close_cnum(tcon->compat, vuid, ERROR_CLOSE);
928                         tcon->compat = NULL;
929                         return status;
930                 }
931
932                 close_cnum(tcon->compat, vuid, SHUTDOWN_CLOSE);
933                 tcon->compat = NULL;
934         }
935
936         tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
937
938         global_rec = tcon->global->db_rec;
939         tcon->global->db_rec = NULL;
940         if (global_rec == NULL) {
941                 global_rec = smbXsrv_tcon_global_fetch_locked(
942                                                 table->global.db_ctx,
943                                                 tcon->global->tcon_global_id,
944                                                 tcon->global /* TALLOC_CTX */);
945                 if (global_rec == NULL) {
946                         error = NT_STATUS_INTERNAL_ERROR;
947                 }
948         }
949
950         if (global_rec != NULL) {
951                 status = dbwrap_record_delete(global_rec);
952                 if (!NT_STATUS_IS_OK(status)) {
953                         TDB_DATA key = dbwrap_record_get_key(global_rec);
954
955                         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                         error = status;
962                 }
963         }
964         TALLOC_FREE(global_rec);
965
966         local_rec = tcon->db_rec;
967         if (local_rec == NULL) {
968                 local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
969                                                         tcon->local_id,
970                                                         tcon /* TALLOC_CTX */);
971                 if (local_rec == NULL) {
972                         error = NT_STATUS_INTERNAL_ERROR;
973                 }
974         }
975
976         if (local_rec != NULL) {
977                 status = dbwrap_record_delete(local_rec);
978                 if (!NT_STATUS_IS_OK(status)) {
979                         TDB_DATA key = dbwrap_record_get_key(local_rec);
980
981                         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                         error = status;
988                 }
989                 table->local.num_tcons -= 1;
990         }
991         if (tcon->db_rec == NULL) {
992                 TALLOC_FREE(local_rec);
993         }
994         tcon->db_rec = NULL;
995
996         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 static NTSTATUS smbXsrv_tcon_disconnect_all(struct smbXsrv_tcon_table *table,
1009                                             uint64_t vuid)
1010 {
1011         struct smbXsrv_tcon_disconnect_all_state state = { .vuid = vuid };
1012         NTSTATUS status;
1013         int count = 0;
1014
1015         if (table == NULL) {
1016                 return NT_STATUS_OK;
1017         }
1018
1019         status = dbwrap_traverse(table->local.db_ctx,
1020                                  smbXsrv_tcon_disconnect_all_callback,
1021                                  &state, &count);
1022         if (!NT_STATUS_IS_OK(status)) {
1023                 DBG_ERR("dbwrap_traverse() failed: %s\n", nt_errstr(status));
1024                 return status;
1025         }
1026
1027         if (!NT_STATUS_IS_OK(state.first_status)) {
1028                 DBG_ERR("count[%d] errors[%d] first[%s]\n",
1029                         count,
1030                         state.errors,
1031                         nt_errstr(state.first_status));
1032                 return state.first_status;
1033         }
1034
1035         return NT_STATUS_OK;
1036 }
1037
1038 static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec,
1039                                                 void *private_data)
1040 {
1041         struct smbXsrv_tcon_disconnect_all_state *state =
1042                 (struct smbXsrv_tcon_disconnect_all_state *)private_data;
1043         TDB_DATA val;
1044         void *ptr = NULL;
1045         struct smbXsrv_tcon *tcon = NULL;
1046         uint64_t vuid;
1047         NTSTATUS status;
1048
1049         val = dbwrap_record_get_value(local_rec);
1050         if (val.dsize != sizeof(ptr)) {
1051                 status = NT_STATUS_INTERNAL_ERROR;
1052                 if (NT_STATUS_IS_OK(state->first_status)) {
1053                         state->first_status = status;
1054                 }
1055                 state->errors++;
1056                 return 0;
1057         }
1058
1059         memcpy(&ptr, val.dptr, val.dsize);
1060         tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
1061
1062         vuid = state->vuid;
1063         if (vuid == 0 && tcon->compat) {
1064                 vuid = tcon->compat->vuid;
1065         }
1066
1067         tcon->db_rec = local_rec;
1068         status = smbXsrv_tcon_disconnect(tcon, vuid);
1069         tcon->db_rec = NULL;
1070         if (!NT_STATUS_IS_OK(status)) {
1071                 if (NT_STATUS_IS_OK(state->first_status)) {
1072                         state->first_status = status;
1073                 }
1074                 state->errors++;
1075                 return 0;
1076         }
1077
1078         return 0;
1079 }
1080
1081 NTSTATUS smb1srv_tcon_table_init(struct smbXsrv_connection *conn)
1082 {
1083         struct smbXsrv_client *client = conn->client;
1084
1085         /*
1086          * Allow a range from 1..65534 with 65534 values.
1087          */
1088         client->tcon_table = talloc_zero(client, struct smbXsrv_tcon_table);
1089         if (client->tcon_table == NULL) {
1090                 return NT_STATUS_NO_MEMORY;
1091         }
1092
1093         return smbXsrv_tcon_table_init(client, client->tcon_table,
1094                                        1, UINT16_MAX - 1,
1095                                        UINT16_MAX - 1);
1096 }
1097
1098 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         struct server_id id = messaging_server_id(conn->client->msg_ctx);
1105         const uint8_t encryption_flags = 0;
1106
1107         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 NTSTATUS smb1srv_tcon_lookup(struct smbXsrv_connection *conn,
1117                              uint16_t tree_id, NTTIME now,
1118                              struct smbXsrv_tcon **tcon)
1119 {
1120         uint32_t local_id = tree_id;
1121
1122         return smbXsrv_tcon_local_lookup(conn->client->tcon_table,
1123                                          local_id, now, tcon);
1124 }
1125
1126 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         return smbXsrv_tcon_disconnect_all(client->tcon_table, 0);
1144 }
1145
1146 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         session->tcon_table = talloc_zero(session, struct smbXsrv_tcon_table);
1152         if (session->tcon_table == NULL) {
1153                 return NT_STATUS_NO_MEMORY;
1154         }
1155
1156         return smbXsrv_tcon_table_init(session, session->tcon_table,
1157                                        1, UINT32_MAX - 1,
1158                                        UINT16_MAX - 1);
1159 }
1160
1161 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         struct server_id id = messaging_server_id(session->client->msg_ctx);
1169
1170         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 NTSTATUS smb2srv_tcon_lookup(struct smbXsrv_session *session,
1180                              uint32_t tree_id, NTTIME now,
1181                              struct smbXsrv_tcon **tcon)
1182 {
1183         uint32_t local_id = tree_id;
1184
1185         return smbXsrv_tcon_local_lookup(session->tcon_table,
1186                                          local_id, now, tcon);
1187 }
1188
1189 NTSTATUS smb2srv_tcon_disconnect_all(struct smbXsrv_session *session)
1190 {
1191         uint64_t vuid = session->global->session_wire_id;
1192
1193         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 static int smbXsrv_tcon_global_traverse_fn(struct db_record *rec, void *data)
1202 {
1203         int ret = -1;
1204         struct smbXsrv_tcon_global_traverse_state *state =
1205                 (struct smbXsrv_tcon_global_traverse_state*)data;
1206         TDB_DATA key = dbwrap_record_get_key(rec);
1207         TDB_DATA val = dbwrap_record_get_value(rec);
1208         DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
1209         struct smbXsrv_tcon_globalB global_blob;
1210         enum ndr_err_code ndr_err;
1211         TALLOC_CTX *frame = talloc_stackframe();
1212
1213         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
1214                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB);
1215         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1216                 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                 goto done;
1221         }
1222
1223         if (global_blob.version != SMBXSRV_VERSION_0) {
1224                 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                 goto done;
1229         }
1230
1231         if (global_blob.info.info0 == NULL) {
1232                 DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
1233                          "key '%s' info0 NULL pointer\n",
1234                          tdb_data_dbg(key));
1235                 goto done;
1236         }
1237
1238         global_blob.info.info0->db_rec = rec;
1239         ret = state->fn(global_blob.info.info0, state->private_data);
1240 done:
1241         TALLOC_FREE(frame);
1242         return ret;
1243 }
1244
1245 NTSTATUS smbXsrv_tcon_global_traverse(
1246                         int (*fn)(struct smbXsrv_tcon_global0 *, void *),
1247                         void *private_data)
1248 {
1249         NTSTATUS status;
1250         int count = 0;
1251         struct smbXsrv_tcon_global_traverse_state state = {
1252                 .fn = fn,
1253                 .private_data = private_data,
1254         };
1255
1256         become_root();
1257         status = smbXsrv_tcon_global_init();
1258         if (!NT_STATUS_IS_OK(status)) {
1259                 unbecome_root();
1260                 DBG_ERR("Failed to initialize tcon_global: %s\n",
1261                           nt_errstr(status));
1262                 return status;
1263         }
1264
1265         status = dbwrap_traverse_read(smbXsrv_tcon_global_db_ctx,
1266                                       smbXsrv_tcon_global_traverse_fn,
1267                                       &state,
1268                                       &count);
1269         unbecome_root();
1270
1271         return status;
1272 }