2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2014
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #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 "dbwrap/dbwrap_watch.h"
32 #include "auth/gensec/gensec.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "../libcli/security/security.h"
36 #include "lib/util/util_tdb.h"
37 #include "librpc/gen_ndr/ndr_smbXsrv.h"
39 #include "lib/util/tevent_ntstatus.h"
40 #include "lib/util/iov_buf.h"
41 #include "lib/global_contexts.h"
43 struct smbXsrv_client_table
{
49 struct db_context
*db_ctx
;
53 static struct db_context
*smbXsrv_client_global_db_ctx
= NULL
;
55 NTSTATUS
smbXsrv_client_global_init(void)
57 const char *global_path
= NULL
;
58 struct db_context
*backend
= NULL
;
59 struct db_context
*db_ctx
= NULL
;
61 if (smbXsrv_client_global_db_ctx
!= NULL
) {
66 * This contains secret information like client keys!
68 global_path
= lock_path(talloc_tos(), "smbXsrv_client_global.tdb");
69 if (global_path
== NULL
) {
70 return NT_STATUS_NO_MEMORY
;
73 backend
= db_open(NULL
, global_path
,
77 TDB_INCOMPATIBLE_HASH
,
78 O_RDWR
| O_CREAT
, 0600,
81 if (backend
== NULL
) {
84 status
= map_nt_error_from_unix_common(errno
);
89 db_ctx
= db_open_watched(NULL
, &backend
, global_messaging_context());
92 return NT_STATUS_NO_MEMORY
;
95 smbXsrv_client_global_db_ctx
= db_ctx
;
102 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
103 * has the same result as integer comparison between the uint32_t
106 * TODO: implement string based key
109 #define SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE 16
111 static TDB_DATA
smbXsrv_client_global_id_to_key(const struct GUID
*client_guid
,
114 TDB_DATA key
= { .dsize
= 0, };
116 struct GUID_ndr_buf buf
= { .buf
= {0}, };
118 status
= GUID_to_ndr_buf(client_guid
, &buf
);
119 if (!NT_STATUS_IS_OK(status
)) {
122 memcpy(key_buf
, buf
.buf
, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE
);
124 key
= make_tdb_data(key_buf
, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE
);
129 static struct db_record
*smbXsrv_client_global_fetch_locked(
130 struct db_context
*db
,
131 const struct GUID
*client_guid
,
135 uint8_t key_buf
[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE
];
136 struct db_record
*rec
= NULL
;
138 key
= smbXsrv_client_global_id_to_key(client_guid
, key_buf
);
140 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
143 struct GUID_txt_buf buf
;
144 DBG_DEBUG("Failed to lock guid [%s], key '%s'\n",
145 GUID_buf_string(client_guid
, &buf
),
146 hex_encode_talloc(talloc_tos(), key
.dptr
, key
.dsize
));
152 static NTSTATUS
smbXsrv_client_table_create(TALLOC_CTX
*mem_ctx
,
153 struct messaging_context
*msg_ctx
,
154 uint32_t max_clients
,
155 struct smbXsrv_client_table
**_table
)
157 struct smbXsrv_client_table
*table
;
160 if (max_clients
> 1) {
161 return NT_STATUS_INTERNAL_ERROR
;
164 table
= talloc_zero(mem_ctx
, struct smbXsrv_client_table
);
166 return NT_STATUS_NO_MEMORY
;
169 table
->local
.max_clients
= max_clients
;
171 status
= smbXsrv_client_global_init();
172 if (!NT_STATUS_IS_OK(status
)) {
177 table
->global
.db_ctx
= smbXsrv_client_global_db_ctx
;
183 static int smbXsrv_client_global_destructor(struct smbXsrv_client_global0
*global
)
188 static void smbXsrv_client_global_verify_record(struct db_record
*db_rec
,
192 struct smbXsrv_client_global0
**_g
)
197 struct smbXsrv_client_globalB global_blob
;
198 enum ndr_err_code ndr_err
;
199 struct smbXsrv_client_global0
*global
= NULL
;
201 TALLOC_CTX
*frame
= talloc_stackframe();
212 key
= dbwrap_record_get_key(db_rec
);
214 val
= dbwrap_record_get_value(db_rec
);
215 if (val
.dsize
== 0) {
224 blob
= data_blob_const(val
.dptr
, val
.dsize
);
226 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
227 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_client_globalB
);
228 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
229 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
230 DBG_WARNING("smbXsrv_client_global_verify_record: "
231 "key '%s' ndr_pull_struct_blob - %s\n",
232 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
238 DBG_DEBUG("client_global:\n");
239 if (DEBUGLVL(DBGLVL_DEBUG
)) {
240 NDR_PRINT_DEBUG(smbXsrv_client_globalB
, &global_blob
);
243 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
244 DBG_ERR("key '%s' use unsupported version %u\n",
245 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
246 global_blob
.version
);
247 NDR_PRINT_DEBUG(smbXsrv_client_globalB
, &global_blob
);
252 global
= global_blob
.info
.info0
;
254 exists
= serverid_exists(&global
->server_id
);
256 struct server_id_buf tmp
;
258 DBG_NOTICE("key '%s' server_id %s does not exist.\n",
259 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
260 server_id_str_buf(global
->server_id
, &tmp
));
261 if (DEBUGLVL(DBGLVL_NOTICE
)) {
262 NDR_PRINT_DEBUG(smbXsrv_client_globalB
, &global_blob
);
265 dbwrap_record_delete(db_rec
);
271 *_g
= talloc_move(mem_ctx
, &global
);
276 static NTSTATUS
smb2srv_client_connection_pass(struct smbd_smb2_request
*smb2req
,
277 struct smbXsrv_client_global0
*global
)
280 enum ndr_err_code ndr_err
;
282 struct smbXsrv_connection_pass0 pass_info0
;
283 struct smbXsrv_connection_passB pass_blob
;
287 pass_info0
= (struct smbXsrv_connection_pass0
) {
288 .client_guid
= global
->client_guid
,
289 .src_server_id
= smb2req
->xconn
->client
->global
->server_id
,
290 .xconn_connect_time
= smb2req
->xconn
->client
->global
->initial_connect_time
,
291 .dst_server_id
= global
->server_id
,
292 .client_connect_time
= global
->initial_connect_time
,
295 reqlen
= iov_buflen(smb2req
->in
.vector
, smb2req
->in
.vector_count
);
297 return NT_STATUS_INVALID_BUFFER_SIZE
;
300 pass_info0
.negotiate_request
.length
= reqlen
;
301 pass_info0
.negotiate_request
.data
= talloc_array(talloc_tos(), uint8_t,
303 if (pass_info0
.negotiate_request
.data
== NULL
) {
304 return NT_STATUS_NO_MEMORY
;
306 iov_buf(smb2req
->in
.vector
, smb2req
->in
.vector_count
,
307 pass_info0
.negotiate_request
.data
,
308 pass_info0
.negotiate_request
.length
);
310 ZERO_STRUCT(pass_blob
);
311 pass_blob
.version
= smbXsrv_version_global_current();
312 pass_blob
.info
.info0
= &pass_info0
;
314 if (DEBUGLVL(DBGLVL_DEBUG
)) {
315 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
318 ndr_err
= ndr_push_struct_blob(&blob
, talloc_tos(), &pass_blob
,
319 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_connection_passB
);
320 data_blob_free(&pass_info0
.negotiate_request
);
321 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
322 status
= ndr_map_error2ntstatus(ndr_err
);
326 iov
.iov_base
= blob
.data
;
327 iov
.iov_len
= blob
.length
;
329 status
= messaging_send_iov(smb2req
->xconn
->client
->msg_ctx
,
331 MSG_SMBXSRV_CONNECTION_PASS
,
333 &smb2req
->xconn
->transport
.sock
, 1);
334 data_blob_free(&blob
);
335 if (!NT_STATUS_IS_OK(status
)) {
342 static NTSTATUS
smbXsrv_client_global_store(struct smbXsrv_client_global0
*global
)
344 struct smbXsrv_client_globalB global_blob
;
345 DATA_BLOB blob
= data_blob_null
;
349 enum ndr_err_code ndr_err
;
350 bool saved_stored
= global
->stored
;
353 * TODO: if we use other versions than '0'
354 * we would add glue code here, that would be able to
355 * store the information in the old format.
358 SMB_ASSERT(global
->local_address
!= NULL
);
359 SMB_ASSERT(global
->remote_address
!= NULL
);
360 SMB_ASSERT(global
->remote_name
!= NULL
);
362 if (global
->db_rec
== NULL
) {
363 return NT_STATUS_INTERNAL_ERROR
;
366 key
= dbwrap_record_get_key(global
->db_rec
);
367 val
= dbwrap_record_get_value(global
->db_rec
);
369 ZERO_STRUCT(global_blob
);
370 global_blob
.version
= smbXsrv_version_global_current();
371 if (val
.dsize
>= 8) {
372 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
374 global_blob
.seqnum
+= 1;
375 global_blob
.info
.info0
= global
;
377 global
->stored
= true;
378 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
379 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_client_globalB
);
380 global
->stored
= saved_stored
;
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
382 status
= ndr_map_error2ntstatus(ndr_err
);
383 DBG_WARNING("key '%s' ndr_push - %s\n",
384 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
386 TALLOC_FREE(global
->db_rec
);
390 val
= make_tdb_data(blob
.data
, blob
.length
);
391 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
392 if (!NT_STATUS_IS_OK(status
)) {
393 DBG_WARNING("key '%s' store - %s\n",
394 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
396 TALLOC_FREE(global
->db_rec
);
400 global
->stored
= true;
402 if (DEBUGLVL(DBGLVL_DEBUG
)) {
403 DBG_DEBUG("key '%s' stored\n",
404 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
));
405 NDR_PRINT_DEBUG(smbXsrv_client_globalB
, &global_blob
);
408 TALLOC_FREE(global
->db_rec
);
413 struct smb2srv_client_mc_negprot_state
{
414 struct tevent_context
*ev
;
415 struct smbd_smb2_request
*smb2req
;
416 struct db_record
*db_rec
;
419 static void smb2srv_client_mc_negprot_cleanup(struct tevent_req
*req
,
420 enum tevent_req_state req_state
)
422 struct smb2srv_client_mc_negprot_state
*state
=
424 struct smb2srv_client_mc_negprot_state
);
426 TALLOC_FREE(state
->db_rec
);
429 static void smb2srv_client_mc_negprot_next(struct tevent_req
*req
);
430 static bool smb2srv_client_mc_negprot_filter(struct messaging_rec
*rec
, void *private_data
);
431 static void smb2srv_client_mc_negprot_done(struct tevent_req
*subreq
);
432 static void smb2srv_client_mc_negprot_watched(struct tevent_req
*subreq
);
434 struct tevent_req
*smb2srv_client_mc_negprot_send(TALLOC_CTX
*mem_ctx
,
435 struct tevent_context
*ev
,
436 struct smbd_smb2_request
*smb2req
)
438 struct tevent_req
*req
= NULL
;
439 struct smb2srv_client_mc_negprot_state
*state
= NULL
;
441 req
= tevent_req_create(mem_ctx
, &state
,
442 struct smb2srv_client_mc_negprot_state
);
447 state
->smb2req
= smb2req
;
449 tevent_req_set_cleanup_fn(req
, smb2srv_client_mc_negprot_cleanup
);
451 smb2srv_client_mc_negprot_next(req
);
453 if (!tevent_req_is_in_progress(req
)) {
454 return tevent_req_post(req
, ev
);
460 static void smb2srv_client_mc_negprot_next(struct tevent_req
*req
)
462 struct smb2srv_client_mc_negprot_state
*state
=
464 struct smb2srv_client_mc_negprot_state
);
465 struct smbXsrv_connection
*xconn
= state
->smb2req
->xconn
;
466 struct smbXsrv_client
*client
= xconn
->client
;
467 struct smbXsrv_client_table
*table
= client
->table
;
468 struct GUID client_guid
= xconn
->smb2
.client
.guid
;
469 struct smbXsrv_client_global0
*global
= NULL
;
470 bool is_free
= false;
471 struct tevent_req
*subreq
= NULL
;
474 SMB_ASSERT(state
->db_rec
== NULL
);
475 state
->db_rec
= smbXsrv_client_global_fetch_locked(table
->global
.db_ctx
,
478 if (state
->db_rec
== NULL
) {
479 tevent_req_nterror(req
, NT_STATUS_INTERNAL_DB_ERROR
);
483 smbXsrv_client_global_verify_record(state
->db_rec
,
490 * This stores the new client information in
491 * smbXsrv_client_global.tdb
493 client
->global
->client_guid
= xconn
->smb2
.client
.guid
;
495 client
->global
->db_rec
= state
->db_rec
;
496 state
->db_rec
= NULL
;
497 status
= smbXsrv_client_global_store(client
->global
);
498 SMB_ASSERT(client
->global
->db_rec
== NULL
);
499 if (!NT_STATUS_IS_OK(status
)) {
500 struct GUID_txt_buf buf
;
501 DBG_ERR("client_guid[%s] store failed - %s\n",
502 GUID_buf_string(&client
->global
->client_guid
,
505 tevent_req_nterror(req
, status
);
509 if (DEBUGLVL(DBGLVL_DEBUG
)) {
510 struct smbXsrv_clientB client_blob
= {
511 .version
= SMBXSRV_VERSION_0
,
512 .info
.info0
= client
,
514 struct GUID_txt_buf buf
;
516 DBG_DEBUG("client_guid[%s] stored\n",
517 GUID_buf_string(&client
->global
->client_guid
,
519 NDR_PRINT_DEBUG(smbXsrv_clientB
, &client_blob
);
522 xconn
->smb2
.client
.guid_verified
= true;
523 tevent_req_done(req
);
527 if (global
== NULL
) {
529 * most likely ndr_pull_struct_blob() failed
531 tevent_req_nterror(req
, NT_STATUS_INTERNAL_DB_CORRUPTION
);
535 subreq
= messaging_filtered_read_send(state
,
538 smb2srv_client_mc_negprot_filter
,
540 if (tevent_req_nomem(subreq
, req
)) {
543 tevent_req_set_callback(subreq
, smb2srv_client_mc_negprot_done
, req
);
545 subreq
= dbwrap_watched_watch_send(state
,
549 if (tevent_req_nomem(subreq
, req
)) {
552 tevent_req_set_callback(subreq
, smb2srv_client_mc_negprot_watched
, req
);
554 status
= smb2srv_client_connection_pass(state
->smb2req
,
557 if (tevent_req_nterror(req
, status
)) {
561 TALLOC_FREE(state
->db_rec
);
565 static bool smb2srv_client_mc_negprot_filter(struct messaging_rec
*rec
, void *private_data
)
567 if (rec
->msg_type
!= MSG_SMBXSRV_CONNECTION_PASSED
) {
571 if (rec
->num_fds
!= 0) {
575 if (rec
->buf
.length
< SMB2_HDR_BODY
) {
582 static void smb2srv_client_mc_negprot_done(struct tevent_req
*subreq
)
584 struct tevent_req
*req
=
585 tevent_req_callback_data(subreq
,
587 struct smb2srv_client_mc_negprot_state
*state
=
589 struct smb2srv_client_mc_negprot_state
);
590 struct smbXsrv_connection
*xconn
= state
->smb2req
->xconn
;
591 struct smbXsrv_client
*client
= xconn
->client
;
592 struct messaging_rec
*rec
= NULL
;
593 struct smbXsrv_connection_passB passed_blob
;
594 enum ndr_err_code ndr_err
;
595 struct smbXsrv_connection_pass0
*passed_info0
= NULL
;
599 ret
= messaging_filtered_read_recv(subreq
, state
, &rec
);
602 status
= map_nt_error_from_unix_common(ret
);
603 DBG_ERR("messaging_filtered_read_recv() - %s\n",
605 tevent_req_nterror(req
, status
);
609 DBG_DEBUG("MSG_SMBXSRV_CONNECTION_PASSED: received...\n");
611 ndr_err
= ndr_pull_struct_blob(&rec
->buf
, rec
, &passed_blob
,
612 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_connection_passB
);
613 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
614 status
= ndr_map_error2ntstatus(ndr_err
);
615 DBG_ERR("ndr_pull_struct_blob - %s\n", nt_errstr(status
));
616 tevent_req_nterror(req
, status
);
620 if (DEBUGLVL(DBGLVL_DEBUG
)) {
621 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &passed_blob
);
624 if (passed_blob
.version
!= SMBXSRV_VERSION_0
) {
625 DBG_ERR("ignore invalid version %u\n", passed_blob
.version
);
626 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &passed_blob
);
627 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
631 passed_info0
= passed_blob
.info
.info0
;
632 if (passed_info0
== NULL
) {
633 DBG_ERR("ignore NULL info %u\n", passed_blob
.version
);
634 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &passed_blob
);
635 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
639 if (!GUID_equal(&xconn
->smb2
.client
.guid
, &passed_info0
->client_guid
)) {
640 struct GUID_txt_buf buf1
, buf2
;
642 DBG_ERR("client's client_guid [%s] != passed guid [%s]\n",
643 GUID_buf_string(&xconn
->smb2
.client
.guid
,
645 GUID_buf_string(&passed_info0
->client_guid
,
647 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &passed_blob
);
648 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
652 if (client
->global
->initial_connect_time
!=
653 passed_info0
->xconn_connect_time
)
655 DBG_ERR("client's initial connect time [%s] (%llu) != "
656 "passed xconn connect time [%s] (%llu)\n",
657 nt_time_string(talloc_tos(),
658 client
->global
->initial_connect_time
),
659 (unsigned long long)client
->global
->initial_connect_time
,
660 nt_time_string(talloc_tos(),
661 passed_info0
->xconn_connect_time
),
662 (unsigned long long)passed_info0
->xconn_connect_time
);
663 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &passed_blob
);
664 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
668 tevent_req_nterror(req
, NT_STATUS_MESSAGE_RETRIEVED
);
671 static void smb2srv_client_mc_negprot_watched(struct tevent_req
*subreq
)
673 struct tevent_req
*req
=
674 tevent_req_callback_data(subreq
,
678 status
= dbwrap_watched_watch_recv(subreq
, NULL
, NULL
);
680 if (tevent_req_nterror(req
, status
)) {
684 smb2srv_client_mc_negprot_next(req
);
687 NTSTATUS
smb2srv_client_mc_negprot_recv(struct tevent_req
*req
)
689 return tevent_req_simple_recv_ntstatus(req
);
692 static NTSTATUS
smbXsrv_client_global_remove(struct smbXsrv_client_global0
*global
)
698 * TODO: if we use other versions than '0'
699 * we would add glue code here, that would be able to
700 * store the information in the old format.
703 if (global
->db_rec
== NULL
) {
704 return NT_STATUS_INTERNAL_ERROR
;
707 key
= dbwrap_record_get_key(global
->db_rec
);
709 status
= dbwrap_record_delete(global
->db_rec
);
710 if (!NT_STATUS_IS_OK(status
)) {
711 DBG_WARNING("key '%s' delete - %s\n",
712 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
714 TALLOC_FREE(global
->db_rec
);
717 global
->stored
= false;
718 DBG_DEBUG("key '%s' delete\n",
719 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
));
721 TALLOC_FREE(global
->db_rec
);
726 static int smbXsrv_client_destructor(struct smbXsrv_client
*client
)
730 status
= smbXsrv_client_remove(client
);
731 if (!NT_STATUS_IS_OK(status
)) {
732 DBG_ERR("smbXsrv_client_remove() failed: %s\n",
736 TALLOC_FREE(client
->global
);
741 static bool smbXsrv_client_connection_pass_filter(struct messaging_rec
*rec
, void *private_data
);
742 static void smbXsrv_client_connection_pass_loop(struct tevent_req
*subreq
);
744 NTSTATUS
smbXsrv_client_create(TALLOC_CTX
*mem_ctx
,
745 struct tevent_context
*ev_ctx
,
746 struct messaging_context
*msg_ctx
,
748 struct smbXsrv_client
**_client
)
750 struct smbXsrv_client_table
*table
;
751 struct smbXsrv_client
*client
= NULL
;
752 struct smbXsrv_client_global0
*global
= NULL
;
754 struct tevent_req
*subreq
= NULL
;
756 status
= smbXsrv_client_table_create(mem_ctx
,
760 if (!NT_STATUS_IS_OK(status
)) {
764 if (table
->local
.num_clients
>= table
->local
.max_clients
) {
766 return NT_STATUS_INSUFFICIENT_RESOURCES
;
769 client
= talloc_zero(mem_ctx
, struct smbXsrv_client
);
770 if (client
== NULL
) {
772 return NT_STATUS_NO_MEMORY
;
774 client
->raw_ev_ctx
= ev_ctx
;
775 client
->msg_ctx
= msg_ctx
;
777 client
->server_multi_channel_enabled
=
778 smbXsrv_server_multi_channel_enabled();
779 if (client
->server_multi_channel_enabled
) {
780 client
->next_channel_id
= 1;
782 client
->table
= talloc_move(client
, &table
);
783 table
= client
->table
;
785 global
= talloc_zero(client
, struct smbXsrv_client_global0
);
786 if (global
== NULL
) {
788 return NT_STATUS_NO_MEMORY
;
790 talloc_set_destructor(global
, smbXsrv_client_global_destructor
);
791 client
->global
= global
;
793 global
->initial_connect_time
= now
;
795 global
->server_id
= messaging_server_id(client
->msg_ctx
);
797 table
->local
.num_clients
+= 1;
799 talloc_set_destructor(client
, smbXsrv_client_destructor
);
801 if (DEBUGLVL(DBGLVL_DEBUG
)) {
802 struct smbXsrv_clientB client_blob
= {
803 .version
= SMBXSRV_VERSION_0
,
804 .info
.info0
= client
,
806 struct GUID_txt_buf buf
;
808 DBG_DEBUG("client_guid[%s] created\n",
809 GUID_buf_string(&global
->client_guid
, &buf
));
810 NDR_PRINT_DEBUG(smbXsrv_clientB
, &client_blob
);
813 subreq
= messaging_filtered_read_send(client
,
816 smbXsrv_client_connection_pass_filter
,
818 if (subreq
== NULL
) {
820 return NT_STATUS_NO_MEMORY
;
822 tevent_req_set_callback(subreq
, smbXsrv_client_connection_pass_loop
, client
);
823 client
->connection_pass_subreq
= subreq
;
829 static NTSTATUS
smb2srv_client_connection_passed(struct smbXsrv_client
*client
,
830 const struct smbXsrv_connection_pass0
*recv_info0
)
833 enum ndr_err_code ndr_err
;
835 struct smbXsrv_connection_pass0 passed_info0
;
836 struct smbXsrv_connection_passB passed_blob
;
840 * We echo back the message with a cleared negotiate_request
842 passed_info0
= *recv_info0
;
843 passed_info0
.negotiate_request
= data_blob_null
;
845 ZERO_STRUCT(passed_blob
);
846 passed_blob
.version
= smbXsrv_version_global_current();
847 passed_blob
.info
.info0
= &passed_info0
;
849 if (DEBUGLVL(DBGLVL_DEBUG
)) {
850 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &passed_blob
);
853 ndr_err
= ndr_push_struct_blob(&blob
, talloc_tos(), &passed_blob
,
854 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_connection_passB
);
855 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
856 status
= ndr_map_error2ntstatus(ndr_err
);
860 iov
.iov_base
= blob
.data
;
861 iov
.iov_len
= blob
.length
;
863 status
= messaging_send_iov(client
->msg_ctx
,
864 recv_info0
->src_server_id
,
865 MSG_SMBXSRV_CONNECTION_PASSED
,
868 data_blob_free(&blob
);
869 if (!NT_STATUS_IS_OK(status
)) {
876 static bool smbXsrv_client_connection_pass_filter(struct messaging_rec
*rec
, void *private_data
)
878 if (rec
->msg_type
!= MSG_SMBXSRV_CONNECTION_PASS
) {
882 if (rec
->num_fds
!= 1) {
886 if (rec
->buf
.length
< SMB2_HDR_BODY
) {
890 /* TODO: verify client_guid...? */
895 static void smbXsrv_client_connection_pass_loop(struct tevent_req
*subreq
)
897 struct smbXsrv_client
*client
=
898 tevent_req_callback_data(subreq
,
899 struct smbXsrv_client
);
900 struct smbXsrv_connection
*xconn
= NULL
;
902 struct messaging_rec
*rec
= NULL
;
903 struct smbXsrv_connection_passB pass_blob
;
904 enum ndr_err_code ndr_err
;
905 struct smbXsrv_connection_pass0
*pass_info0
= NULL
;
910 client
->connection_pass_subreq
= NULL
;
912 ret
= messaging_filtered_read_recv(subreq
, talloc_tos(), &rec
);
918 if (rec
->num_fds
!= 1) {
919 DBG_ERR("MSG_SMBXSRV_CONNECTION_PASS: num_fds[%u]\n",
924 sock_fd
= rec
->fds
[0];
925 DBG_DEBUG("MSG_SMBXSRV_CONNECTION_PASS: got sock_fd[%d]\n", sock_fd
);
927 ndr_err
= ndr_pull_struct_blob(&rec
->buf
, rec
, &pass_blob
,
928 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_connection_passB
);
929 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
930 status
= ndr_map_error2ntstatus(ndr_err
);
931 DBG_WARNING("ndr_pull_struct_blob - %s\n", nt_errstr(status
));
935 if (DEBUGLVL(DBGLVL_DEBUG
)) {
936 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
939 if (pass_blob
.version
!= SMBXSRV_VERSION_0
) {
940 DBG_ERR("ignore invalid version %u\n", pass_blob
.version
);
941 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
945 pass_info0
= pass_blob
.info
.info0
;
946 if (pass_info0
== NULL
) {
947 DBG_ERR("ignore NULL info %u\n", pass_blob
.version
);
948 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
952 if (!GUID_equal(&client
->global
->client_guid
, &pass_info0
->client_guid
))
954 struct GUID_txt_buf buf1
, buf2
;
956 DBG_WARNING("client's client_guid [%s] != passed guid [%s]\n",
957 GUID_buf_string(&client
->global
->client_guid
,
959 GUID_buf_string(&pass_info0
->client_guid
,
961 if (DEBUGLVL(DBGLVL_WARNING
)) {
962 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
967 if (client
->global
->initial_connect_time
!=
968 pass_info0
->client_connect_time
)
970 DBG_WARNING("client's initial connect time [%s] (%llu) != "
971 "passed initial connect time [%s] (%llu)\n",
972 nt_time_string(talloc_tos(),
973 client
->global
->initial_connect_time
),
974 (unsigned long long)client
->global
->initial_connect_time
,
975 nt_time_string(talloc_tos(),
976 pass_info0
->client_connect_time
),
977 (unsigned long long)pass_info0
->client_connect_time
);
978 if (DEBUGLVL(DBGLVL_WARNING
)) {
979 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
984 status
= smb2srv_client_connection_passed(client
, pass_info0
);
985 if (!NT_STATUS_IS_OK(status
)) {
986 const char *r
= "smb2srv_client_connection_passed() failed";
987 DBG_ERR("%s => %s\n", r
, nt_errstr(status
));
988 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
989 exit_server_cleanly(r
);
993 status
= smbd_add_connection(client
,
995 pass_info0
->xconn_connect_time
,
997 if (NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
)) {
999 smbd_server_connection_terminate(xconn
, nt_errstr(status
));
1001 if (!NT_STATUS_IS_OK(status
)) {
1002 DBG_ERR("smbd_add_connection => %s\n", nt_errstr(status
));
1003 NDR_PRINT_DEBUG(smbXsrv_connection_passB
, &pass_blob
);
1009 * Set seq_low to mid received in negprot
1011 seq_low
= BVAL(pass_info0
->negotiate_request
.data
,
1012 SMB2_HDR_MESSAGE_ID
);
1014 xconn
->smb2
.client
.guid_verified
= true;
1015 smbd_smb2_process_negprot(xconn
, seq_low
,
1016 pass_info0
->negotiate_request
.data
,
1017 pass_info0
->negotiate_request
.length
);
1023 for (fd_idx
= 0; fd_idx
< rec
->num_fds
; fd_idx
++) {
1024 sock_fd
= rec
->fds
[fd_idx
];
1032 subreq
= messaging_filtered_read_send(client
,
1035 smbXsrv_client_connection_pass_filter
,
1037 if (subreq
== NULL
) {
1039 r
= "messaging_read_send(MSG_SMBXSRV_CONNECTION_PASS failed";
1040 exit_server_cleanly(r
);
1043 tevent_req_set_callback(subreq
, smbXsrv_client_connection_pass_loop
, client
);
1044 client
->connection_pass_subreq
= subreq
;
1047 NTSTATUS
smbXsrv_client_remove(struct smbXsrv_client
*client
)
1049 struct smbXsrv_client_table
*table
= client
->table
;
1052 if (client
->global
->db_rec
!= NULL
) {
1053 struct GUID_txt_buf buf
;
1054 DBG_ERR("client_guid[%s]: Called with db_rec != NULL'\n",
1055 GUID_buf_string(&client
->global
->client_guid
,
1057 return NT_STATUS_INTERNAL_ERROR
;
1060 if (!client
->global
->stored
) {
1061 return NT_STATUS_OK
;
1064 TALLOC_FREE(client
->connection_pass_subreq
);
1066 client
->global
->db_rec
= smbXsrv_client_global_fetch_locked(
1067 table
->global
.db_ctx
,
1068 &client
->global
->client_guid
,
1069 client
->global
/* TALLOC_CTX */);
1070 if (client
->global
->db_rec
== NULL
) {
1071 return NT_STATUS_INTERNAL_DB_ERROR
;
1074 status
= smbXsrv_client_global_remove(client
->global
);
1075 if (!NT_STATUS_IS_OK(status
)) {
1076 struct GUID_txt_buf buf
;
1077 DBG_ERR("client_guid[%s] store failed - %s\n",
1078 GUID_buf_string(&client
->global
->client_guid
, &buf
),
1083 if (DEBUGLVL(DBGLVL_DEBUG
)) {
1084 struct smbXsrv_clientB client_blob
= {
1085 .version
= SMBXSRV_VERSION_0
,
1086 .info
.info0
= client
,
1088 struct GUID_txt_buf buf
;
1090 DBG_DEBUG("client_guid[%s] stored\n",
1091 GUID_buf_string(&client
->global
->client_guid
, &buf
));
1092 NDR_PRINT_DEBUG(smbXsrv_clientB
, &client_blob
);
1095 return NT_STATUS_OK
;