s3:smbd: make smbXsrv_open.c compile
[metze/samba/wip.git] / source3 / smbd / smbXsrv_open.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2012
5    Copyright (C) Michael Adam 2012
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_rbt.h"
26 #include "dbwrap/dbwrap_open.h"
27 #include "session.h"
28 #include "auth.h"
29 #include "../lib/tsocket/tsocket.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
35 static struct db_context *smbXsrv_open_global_db_ctx = NULL;
36
37 NTSTATUS smbXsrv_open_global_init(void)
38 {
39         const char *global_path = NULL;
40         struct db_context *db_ctx = NULL;
41
42         if (smbXsrv_open_global_db_ctx != NULL) {
43                 return NT_STATUS_OK;
44         }
45
46         global_path = lock_path("smbXsrv_open_global.tdb");
47
48         db_ctx = db_open(NULL, global_path,
49                          0, /* hash_size */
50                          TDB_DEFAULT |
51                          TDB_CLEAR_IF_FIRST |
52                          TDB_INCOMPATIBLE_HASH,
53                          O_RDWR | O_CREAT, 0600,
54                          DBWRAP_LOCK_ORDER_1 /* TODO - correct lock order */);
55         if (db_ctx == NULL) {
56                 NTSTATUS status;
57
58                 status = map_nt_error_from_unix_common(errno);
59
60                 return status;
61         }
62
63         smbXsrv_open_global_db_ctx = db_ctx;
64
65         return NT_STATUS_OK;
66 }
67
68 static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
69                                            uint32_t lowest_id,
70                                            uint32_t highest_id)
71 {
72         struct smbXsrv_open_table *table = &conn->open_table;
73         NTSTATUS status;
74
75         ZERO_STRUCTP(table);
76         table->local.db_ctx = db_open_rbt(conn);
77         if (table->local.db_ctx == NULL) {
78                 return NT_STATUS_NO_MEMORY;
79         }
80         table->local.lowest_id = lowest_id;
81         table->local.highest_id = highest_id;
82
83         status = smbXsrv_open_global_init();
84         if (!NT_STATUS_IS_OK(status)) {
85                 return status;
86         }
87
88         table->global.db_ctx = smbXsrv_open_global_db_ctx;
89
90         return NT_STATUS_OK;
91 }
92
93 struct smb1srv_open_local_allocate_state {
94         const uint32_t lowest_id;
95         const uint32_t highest_id;
96         uint32_t last_id;
97         uint32_t useable_id;
98         NTSTATUS status;
99 };
100
101 static int smb1srv_open_local_allocate_traverse(struct db_record *rec,
102                                                    void *private_data)
103 {
104         struct smb1srv_open_local_allocate_state *state =
105                 (struct smb1srv_open_local_allocate_state *)private_data;
106         TDB_DATA key = dbwrap_record_get_key(rec);
107         uint32_t id = 0;
108
109         if (key.dsize != sizeof(uint32_t)) {
110                 //TODO errno?
111                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
112                 return -1;
113         }
114
115         /*
116          * NOTE:
117          * We need big endian so that dbwrap_rbt's memcmp
118          * has the same result as integer comparison between the uint32_t
119          * values.
120          *
121          * TODO: implement string based key
122          */
123         id = RIVAL(key.dptr, 0);
124
125         if (id <= state->last_id) {
126                 //TODO errno?
127                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
128                 return -1;
129         }
130         state->last_id = id;
131
132         if (id > state->useable_id) {
133                 state->status = NT_STATUS_OK;
134                 return -1;
135         }
136
137         state->useable_id +=1;
138         return 0;
139 }
140
141 static NTSTATUS smb1srv_open_local_allocate_id(struct db_context *db,
142                                                   uint32_t lowest_id,
143                                                   uint32_t highest_id,
144                                                   TALLOC_CTX *mem_ctx,
145                                                   struct db_record **_rec,
146                                                   uint32_t *_id)
147 {
148         struct smb1srv_open_local_allocate_state state = {
149                 .lowest_id = lowest_id,
150                 .highest_id = highest_id,
151                 .last_id = 0,
152                 .useable_id = lowest_id,
153                 .status = NT_STATUS_INTERNAL_ERROR,
154         };
155         uint32_t i;
156         uint32_t range;
157         NTSTATUS status;
158         int count = 0;
159
160         *_rec = NULL;
161         *_id = 0;
162
163         if (lowest_id > highest_id) {
164                 return NT_STATUS_INSUFFICIENT_RESOURCES;
165         }
166
167         range = (highest_id - lowest_id) + 1;
168
169         for (i = 0; i < range; i++) {
170                 uint32_t id;
171                 uint8_t key_buf[sizeof(uint32_t)];
172                 TDB_DATA key;
173                 TDB_DATA val;
174                 struct db_record *rec = NULL;
175
176                 id = generate_random() % range;
177                 id += lowest_id;
178
179                 if (id < lowest_id) {
180                         id = lowest_id;
181                 }
182                 if (id > highest_id) {
183                         id = highest_id;
184                 }
185
186                 RSIVAL(key_buf, 0, id);
187                 key = make_tdb_data(key_buf, sizeof(key_buf));
188
189                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
190                 if (rec == NULL) {
191                         return NT_STATUS_INSUFFICIENT_RESOURCES;
192                 }
193
194                 val = dbwrap_record_get_value(rec);
195                 if (val.dsize != 0) {
196                         TALLOC_FREE(rec);
197                         continue;
198                 }
199
200                 *_rec = rec;
201                 *_id = id;
202                 return NT_STATUS_OK;
203         }
204
205         status = dbwrap_traverse_read(db, smb1srv_open_local_allocate_traverse,
206                                       &state, &count);
207         if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
208                 /*
209                  * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
210                  *
211                  * If we get anything else it is an error, because it
212                  * means we did not manage to find a free slot in
213                  * the db.
214                  */
215                 return NT_STATUS_INSUFFICIENT_RESOURCES;
216         }
217
218         if (NT_STATUS_IS_OK(state.status)) {
219                 uint32_t id;
220                 uint8_t key_buf[sizeof(uint32_t)];
221                 TDB_DATA key;
222                 TDB_DATA val;
223                 struct db_record *rec = NULL;
224
225                 id = state.useable_id;
226
227                 RSIVAL(key_buf, 0, id);
228                 key = make_tdb_data(key_buf, sizeof(key_buf));
229
230                 rec = dbwrap_fetch_locked(db, mem_ctx, key);
231                 if (rec == NULL) {
232                         return NT_STATUS_INSUFFICIENT_RESOURCES;
233                 }
234
235                 val = dbwrap_record_get_value(rec);
236                 if (val.dsize != 0) {
237                         TALLOC_FREE(rec);
238                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
239                 }
240
241                 *_rec = rec;
242                 *_id = id;
243                 return NT_STATUS_OK;
244         }
245
246         return state.status;
247 }
248
249 struct smbXsrv_open_local_fetch_state {
250         struct smbXsrv_open *open;
251         NTSTATUS status;
252 };
253
254 static void smbXsrv_open_local_fetch_parser(TDB_DATA key, TDB_DATA data,
255                                                void *private_data)
256 {
257         struct smbXsrv_open_local_fetch_state *state =
258                 (struct smbXsrv_open_local_fetch_state *)private_data;
259         void *ptr;
260
261         if (data.dsize != sizeof(ptr)) {
262                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
263                 return;
264         }
265
266         memcpy(&ptr, data.dptr, data.dsize);
267         state->open = talloc_get_type_abort(ptr, struct smbXsrv_open);
268         state->status = NT_STATUS_OK;
269 }
270
271 static NTSTATUS smbXsrv_open_local_lookup(struct smbXsrv_open_table *table,
272                                              uint32_t open_local_id,
273                                              NTTIME now,
274                                              struct smbXsrv_open **_open)
275 {
276         struct smbXsrv_open_local_fetch_state state = {
277                 .open = NULL,
278                 .status = NT_STATUS_INTERNAL_ERROR,
279         };
280         uint8_t key_buf[sizeof(uint32_t)];
281         TDB_DATA key;
282         NTSTATUS status;
283
284         *_open = NULL;
285
286         if (table->local.db_ctx == NULL) {
287                 return NT_STATUS_INTERNAL_ERROR;
288         }
289
290         RSIVAL(key_buf, 0, open_local_id);
291         key = make_tdb_data(key_buf, sizeof(key_buf));
292
293         status = dbwrap_parse_record(table->local.db_ctx, key,
294                                      smbXsrv_open_local_fetch_parser,
295                                      &state);
296         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
297                 return NT_STATUS_USER_SESSION_DELETED;
298         } else if (!NT_STATUS_IS_OK(status)) {
299                 return status;
300         }
301         if (!NT_STATUS_IS_OK(state.status)) {
302                 return state.status;
303         }
304
305         *_open = state.open;
306         return NT_STATUS_OK;
307 }
308
309 static int smbXsrv_open_global_destructor(struct smbXsrv_open_global0 *global)
310 {
311         return 0;
312 }
313
314 static NTSTATUS smbXsrv_open_global_allocate(struct db_context *db,
315                                         TALLOC_CTX *mem_ctx,
316                                         struct smbXsrv_open_global0 **_global)
317 {
318         uint32_t i;
319         struct smbXsrv_open_global0 *global = NULL;
320
321         *_global = NULL;
322
323         global = talloc_zero(mem_ctx, struct smbXsrv_open_global0);
324         if (global == NULL) {
325                 return NT_STATUS_NO_MEMORY;
326         }
327         talloc_set_destructor(global, smbXsrv_open_global_destructor);
328
329         for (i = 0; i < UINT32_MAX; i++) {
330                 uint32_t id;
331                 uint8_t key_buf[sizeof(uint32_t)];
332                 TDB_DATA key;
333                 TDB_DATA val;
334
335                 id = generate_random();
336                 if (id >= UINT16_MAX) {
337                         id = id & UINT16_MAX;
338                 }
339                 if (id == 0) {
340                         id++;
341                 }
342                 if (id == UINT32_MAX) {
343                         id--;
344                 }
345
346                 RSIVAL(key_buf, 0, id);
347                 key = make_tdb_data(key_buf, sizeof(key_buf));
348
349                 global->db_rec = dbwrap_fetch_locked(db, mem_ctx, key);
350                 if (global->db_rec == NULL) {
351                         talloc_free(global);
352                         return NT_STATUS_INSUFFICIENT_RESOURCES;
353                 }
354
355                 val = dbwrap_record_get_value(global->db_rec);
356                 if (val.dsize != 0) {
357                         TALLOC_FREE(global->db_rec);
358                         continue;
359                 }
360
361                 global->open_global_id = id;
362
363                 *_global = global;
364                 return NT_STATUS_OK;
365         }
366
367         /* should not be reached */
368         talloc_free(global);
369         return NT_STATUS_INTERNAL_ERROR;
370 }
371
372 static NTSTATUS smbXsrv_open_global_store(struct smbXsrv_connection *sconn,
373                                              struct smbXsrv_open_global0 *global)
374 {
375         struct smbXsrv_open_globalB global_blob;
376         DATA_BLOB blob = data_blob_null;
377         TDB_DATA val;
378         NTSTATUS status;
379         enum ndr_err_code ndr_err;
380
381         /*
382          * TODO: if we use other versions than '0'
383          * we would add glue code here, that would be able to
384          * store the information in the old format.
385          */
386
387         if (global->db_rec == NULL) {
388                 return NT_STATUS_INTERNAL_ERROR;
389         }
390
391         val = dbwrap_record_get_value(global->db_rec);
392
393         ZERO_STRUCT(global_blob);
394         global_blob.version = 0;
395         if (val.dsize >= 8) {
396                 global_blob.seqnum = IVAL(val.dptr, 4);
397         }
398         global_blob.seqnum += 1;
399         global_blob.info.info0 = global;
400
401         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
402                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_globalB);
403         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
404                 //status = ndr_err_code;
405                 TALLOC_FREE(global->db_rec);
406                 return status;
407         }
408
409         val = make_tdb_data(blob.data, blob.length);
410         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
411         TALLOC_FREE(global->db_rec);
412         if (!NT_STATUS_IS_OK(status)) {
413                 return status;
414         }
415
416         return NT_STATUS_OK;
417 }
418
419 struct smbXsrv_open_global_fetch_state {
420         TALLOC_CTX *mem_ctx;
421         struct smbXsrv_open_global *open;
422         NTSTATUS status;
423 };
424
425 static void smbXsrv_open_global_fetch_parser(TDB_DATA key, TDB_DATA data,
426                                                void *private_data)
427 {
428         struct smbXsrv_open_global_fetch_state *state =
429                 (struct smbXsrv_open_global_fetch_state *)private_data;
430
431         state->status = NT_STATUS_NOT_IMPLEMENTED;
432 }
433
434 static NTSTATUS smbXsrv_open_global_lookup(struct smbXsrv_open_table *table,
435                                               uint32_t open_global_id,
436                                               TALLOC_CTX *mem_ctx,
437                                               struct smbXsrv_open_global **_open)
438 {
439         struct smbXsrv_open_global_fetch_state state = {
440                 .mem_ctx = mem_ctx,
441                 .open = NULL,
442                 .status = NT_STATUS_INTERNAL_ERROR,
443         };
444         TDB_DATA key;
445         uint8_t key_buf[sizeof(uint32_t)];
446         NTSTATUS status;
447
448         *_open = NULL;
449
450         if (table->global.db_ctx == NULL) {
451                 return NT_STATUS_INTERNAL_ERROR;
452         }
453
454         /* TODO: key as string */
455         RSIVAL(key_buf, 0, open_global_id);
456         key = make_tdb_data(key_buf, sizeof(key_buf));
457
458         status = dbwrap_parse_record(table->global.db_ctx, key,
459                                      smbXsrv_open_global_fetch_parser, &state);
460         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
461                 return NT_STATUS_USER_SESSION_DELETED;
462         } else if (!NT_STATUS_IS_OK(status)) {
463                 return status;
464         }
465         if (!NT_STATUS_IS_OK(state.status)) {
466                 return state.status;
467         }
468
469         *_open = state.open;
470         return NT_STATUS_OK;
471 }
472
473 static int smbXsrv_open_destructor(struct smbXsrv_open *open)
474 {
475         struct smbXsrv_open_table *table;
476         struct db_record *local_rec = NULL;
477         struct db_record *global_rec = NULL;
478         NTSTATUS status;
479
480         if (open->connection == NULL) {
481                 return 0;
482         }
483
484         table = &open->connection->open_table;
485         open->connection = NULL;
486
487         local_rec = open->db_rec;
488         open->db_rec = NULL;
489         if (local_rec == NULL) {
490                 uint8_t key_buf[sizeof(uint32_t)];
491                 TDB_DATA key;
492
493                 RSIVAL(key_buf, 0, open->local_id);
494                 key = make_tdb_data(key_buf, sizeof(key_buf));
495
496                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
497                                                 open, key);
498         }
499
500         if (local_rec != NULL) {
501                 status = dbwrap_record_delete(local_rec);
502         }
503
504         global_rec = open->global->db_rec;
505         open->global->db_rec = NULL;
506         if (global_rec == NULL) {
507                 uint8_t key_buf[sizeof(uint32_t)];
508                 TDB_DATA key;
509
510                 RSIVAL(key_buf, 0, open->global->open_global_id);
511                 key = make_tdb_data(key_buf, sizeof(key_buf));
512
513                 global_rec = dbwrap_fetch_locked(table->global.db_ctx,
514                                                  open->global, key);
515         }
516
517         if (global_rec != NULL) {
518                 status = dbwrap_record_delete(global_rec);
519         }
520         TALLOC_FREE(open->global);
521
522         return 0;
523 }
524
525 NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn,
526                                 NTTIME now,
527                                 struct smbXsrv_open **_open)
528 {
529         struct smbXsrv_open_table *table = &conn->open_table;
530         uint32_t max_opens = table->local.highest_id - table->local.lowest_id;
531         struct db_record *local_rec = NULL;
532         struct smbXsrv_open *open = NULL;
533         void *ptr = NULL;
534         TDB_DATA val;
535         struct smbXsrv_open_global0 *global = NULL;
536         NTSTATUS status;
537
538         //system("sleep 999999");
539
540         if (table->local.num_opens >= max_opens) {
541                 return NT_STATUS_INSUFFICIENT_RESOURCES;
542                 // TODO smb1 return NT_STATUS_TOO_MANY_SESSIONS;
543         }
544
545         open = talloc_zero(conn, struct smbXsrv_open);
546         if (open == NULL) {
547                 return NT_STATUS_NO_MEMORY;
548         }
549         open->connection = conn;
550
551         status = smbXsrv_open_global_allocate(table->global.db_ctx,
552                                               open, &global);
553         if (!NT_STATUS_IS_OK(status)) {
554                 talloc_free(open);
555                 return status;
556         }
557         open->global = global;
558
559         talloc_set_destructor(open, smbXsrv_open_destructor);
560
561         if (conn->protocol >= PROTOCOL_SMB2_02) {
562                 uint64_t id = global->open_global_id;
563                 uint8_t key_buf[sizeof(uint32_t)];
564                 TDB_DATA key;
565
566                 global->open_persistent_id = id;
567                 //global->open_persistent_id |= (id << 32) & 0xFFFFFFFF00000000ULL;
568
569                 open->local_id = global->open_global_id;
570
571                 RSIVAL(key_buf, 0, open->local_id);
572                 key = make_tdb_data(key_buf, sizeof(key_buf));
573
574                 local_rec = dbwrap_fetch_locked(table->local.db_ctx,
575                                                 open, key);
576                 if (local_rec == NULL) {
577                         return NT_STATUS_NO_MEMORY;
578                 }
579
580                 val = dbwrap_record_get_value(local_rec);
581                 if (val.dsize != 0) {
582                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
583                 }
584         } else {
585
586                 status = smb1srv_open_local_allocate_id(table->local.db_ctx,
587                                                         table->local.lowest_id,
588                                                         table->local.highest_id,
589                                                         open,
590                                                         &local_rec,
591                                                         &open->local_id);
592                 if (!NT_STATUS_IS_OK(status)) {
593                         return status;
594                 }
595
596                 global->open_persistent_id = open->local_id;
597         }
598
599         ptr = open;
600         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
601         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
602         TALLOC_FREE(local_rec);
603         if (!NT_STATUS_IS_OK(status)) {
604                 talloc_free(open);
605                 return status;
606         }
607
608         global->creation_time = now;
609
610         status = smbXsrv_open_global_store(conn, global);
611         if (!NT_STATUS_IS_OK(status)) {
612                 talloc_free(open);
613                 return status;
614         }
615
616         {
617                 struct smbXsrv_openB open_blob;
618
619                 ZERO_STRUCT(open_blob);
620                 open_blob.version = 0;
621                 open_blob.info.info0 = open;
622
623                 NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
624         }
625
626         *_open = open;
627         return NT_STATUS_OK;
628 }
629
630 NTSTATUS smbXsrv_open_update(struct smbXsrv_open *open)
631 {
632         struct smbXsrv_open_table *table = &open->connection->open_table;
633         NTSTATUS status;
634         uint8_t key_buf[sizeof(uint32_t)];
635         TDB_DATA key;
636
637         if (open->global->db_rec != NULL) {
638                 return NT_STATUS_INTERNAL_ERROR;
639         }
640
641         RSIVAL(key_buf, 0, open->global->open_global_id);
642         key = make_tdb_data(key_buf, sizeof(key_buf));
643
644         open->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx,
645                                                       open->global, key);
646         if (open->global->db_rec == NULL) {
647                 // TODO proper return code?
648                 return NT_STATUS_NO_MEMORY;
649         }
650
651         status = smbXsrv_open_global_store(open->connection,
652                                               open->global);
653         if (!NT_STATUS_IS_OK(status)) {
654                 /* debug */
655                 return status;
656         }
657
658         return NT_STATUS_OK;
659 }
660
661 NTSTATUS smb1srv_open_table_init(struct smbXsrv_connection *conn)
662 {
663         /*
664          * Allow a range from 100..65534.
665          */
666         return smbXsrv_open_table_init(conn, 100, UINT16_MAX - 1);
667 }
668
669 NTSTATUS smb1srv_open_lookup(struct smbXsrv_open_table *table,
670                                 uint16_t vuid, NTTIME now,
671                                 struct smbXsrv_open **open)
672 {
673         uint32_t local_id = vuid;
674
675         return smbXsrv_open_local_lookup(table, local_id, now, open);
676 }
677
678 NTSTATUS smb2srv_open_table_init(struct smbXsrv_connection *conn)
679 {
680         /*
681          * For now use the same range as SMB1.
682          *
683          * Allow a range from 100..65534.
684          */
685         return smbXsrv_open_table_init(conn, 100, UINT16_MAX - 1);
686 }
687
688 NTSTATUS smb2srv_open_lookup(struct smbXsrv_open_table *table,
689                                 uint64_t open_id, NTTIME now,
690                                 struct smbXsrv_open **open)
691 {
692         uint32_t local_id = open_id & UINT32_MAX;
693
694         return smbXsrv_open_local_lookup(table, local_id, now, open);
695 }
696