diff options
author | Stefan Metzmacher <metze@samba.org> | 2016-01-26 01:10:25 +0100 |
---|---|---|
committer | Michael Adam <obnox@samba.org> | 2016-01-26 15:58:11 +0100 |
commit | d77238f85f63a0743e6464f360121e0dfd85cb28 (patch) | |
tree | 31f4440da2dde4fc49db9048f669e6f4b9aaabf8 | |
parent | 8ab462926014c836ae05728e1765459d82cba326 (diff) | |
download | samba-d77238f85f63a0743e6464f360121e0dfd85cb28.tar.gz |
smbd: add smbXsrv_client.c
Pair-Programmed-With: Michael Adam <obnox@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Michael Adam <obnox@samba.org>
-rw-r--r-- | source3/smbd/globals.h | 16 | ||||
-rw-r--r-- | source3/smbd/smbXsrv_client.c | 770 | ||||
-rwxr-xr-x | source3/wscript_build | 1 |
3 files changed, 787 insertions, 0 deletions
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 7af09753e74..1ca1389cdd6 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -528,6 +528,22 @@ const char *smbXsrv_connection_dbg(const struct smbXsrv_connection *xconn); NTSTATUS smbXsrv_version_global_init(const struct server_id *server_id); uint32_t smbXsrv_version_global_current(void); +struct smbXsrv_client_table; +NTSTATUS smbXsrv_client_global_init(void); +NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx, + NTTIME now, + struct smbXsrv_client **_client); +NTSTATUS smbXsrv_client_update(struct smbXsrv_client *client); +NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client); +NTSTATUS smb2srv_client_lookup_global(struct smbXsrv_client *client, + struct GUID client_guid, + TALLOC_CTX *mem_ctx, + struct smbXsrv_client_global0 **_pass); +NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req, + struct smbXsrv_client_global0 *global); + NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn, enum protocol_types protocol); diff --git a/source3/smbd/smbXsrv_client.c b/source3/smbd/smbXsrv_client.c new file mode 100644 index 00000000000..87cc307abef --- /dev/null +++ b/source3/smbd/smbXsrv_client.c @@ -0,0 +1,770 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Stefan Metzmacher 2014 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include <tevent.h> +#include "smbd/smbd.h" +#include "smbd/globals.h" +#include "dbwrap/dbwrap.h" +#include "dbwrap/dbwrap_rbt.h" +#include "dbwrap/dbwrap_open.h" +#include "dbwrap/dbwrap_watch.h" +#include "session.h" +#include "auth.h" +#include "auth/gensec/gensec.h" +#include "../lib/tsocket/tsocket.h" +#include "../libcli/security/security.h" +#include "messages.h" +#include "lib/util/util_tdb.h" +#include "librpc/gen_ndr/ndr_smbXsrv.h" +#include "serverid.h" +#include "lib/util/tevent_ntstatus.h" +#include "lib/util/iov_buf.h" + +struct smbXsrv_client_table { + struct { + uint32_t max_clients; + uint32_t num_clients; + } local; + struct { + struct db_context *db_ctx; + } global; +}; + +static struct db_context *smbXsrv_client_global_db_ctx = NULL; + +NTSTATUS smbXsrv_client_global_init(void) +{ + const char *global_path = NULL; + struct db_context *db_ctx = NULL; + + if (smbXsrv_client_global_db_ctx != NULL) { + return NT_STATUS_OK; + } + + /* + * This contains secret information like client keys! + */ + global_path = lock_path("smbXsrv_client_global.tdb"); + + db_ctx = db_open(NULL, global_path, + 0, /* hash_size */ + TDB_DEFAULT | + TDB_CLEAR_IF_FIRST | + TDB_INCOMPATIBLE_HASH, + O_RDWR | O_CREAT, 0600, + DBWRAP_LOCK_ORDER_1, + DBWRAP_FLAG_NONE); + if (db_ctx == NULL) { + NTSTATUS status; + + status = map_nt_error_from_unix_common(errno); + + return status; + } + + smbXsrv_client_global_db_ctx = db_ctx; + + return NT_STATUS_OK; +} + +/* + * NOTE: + * We need to store the keys in big endian so that dbwrap_rbt's memcmp + * has the same result as integer comparison between the uint32_t + * values. + * + * TODO: implement string based key + */ + +#define SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE 16 + +static TDB_DATA smbXsrv_client_global_id_to_key(const struct GUID *client_guid, + uint8_t *key_buf) +{ + TDB_DATA key = { .dsize = 0, }; + NTSTATUS status; + DATA_BLOB b; + + status = GUID_to_ndr_blob(client_guid, talloc_tos(), &b); + if (!NT_STATUS_IS_OK(status)) { + return key; + } + memcpy(key_buf, b.data, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE); + data_blob_free(&b); + + key = make_tdb_data(key_buf, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE); + + return key; +} + +static NTSTATUS smbXsrv_client_table_create(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + uint32_t max_clients, + struct smbXsrv_client_table **_table) +{ + struct smbXsrv_client_table *table; + NTSTATUS status; + + if (max_clients > 1) { + return NT_STATUS_INTERNAL_ERROR; + } + + table = talloc_zero(mem_ctx, struct smbXsrv_client_table); + if (table == NULL) { + return NT_STATUS_NO_MEMORY; + } + + table->local.max_clients = max_clients; + + status = smbXsrv_client_global_init(); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(table); + return status; + } + + table->global.db_ctx = smbXsrv_client_global_db_ctx; + + dbwrap_watch_db(table->global.db_ctx, msg_ctx); + + *_table = table; + return NT_STATUS_OK; +} + +static int smbXsrv_client_global_destructor(struct smbXsrv_client_global0 *global) +{ + return 0; +} + +static void smbXsrv_client_global_verify_record(struct db_record *db_rec, + bool *is_free, + bool *was_free, + TALLOC_CTX *mem_ctx, + struct smbXsrv_client_global0 **_g) +{ + TDB_DATA key; + TDB_DATA val; + DATA_BLOB blob; + struct smbXsrv_client_globalB global_blob; + enum ndr_err_code ndr_err; + struct smbXsrv_client_global0 *global = NULL; + bool exists; + TALLOC_CTX *frame = talloc_stackframe(); + + *is_free = false; + + if (was_free) { + *was_free = false; + } + if (_g) { + *_g = NULL; + } + + key = dbwrap_record_get_key(db_rec); + + val = dbwrap_record_get_value(db_rec); + if (val.dsize == 0) { + TALLOC_FREE(frame); + *is_free = true; + if (was_free) { + *was_free = true; + } + return; + } + + blob = data_blob_const(val.dptr, val.dsize); + + ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob, + (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_client_globalB); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + NTSTATUS status = ndr_map_error2ntstatus(ndr_err); + DBG_WARNING("smbXsrv_client_global_verify_record: " + "key '%s' ndr_pull_struct_blob - %s\n", + hex_encode_talloc(frame, key.dptr, key.dsize), + nt_errstr(status)); + TALLOC_FREE(frame); + return; + } + + DBG_DEBUG("client_global:\n"); + if (DEBUGLVL(DBGLVL_DEBUG)) { + NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob); + } + + if (global_blob.version != SMBXSRV_VERSION_0) { + DBG_ERR("key '%s' use unsupported version %u\n", + hex_encode_talloc(frame, key.dptr, key.dsize), + global_blob.version); + NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob); + TALLOC_FREE(frame); + return; + } + + global = global_blob.info.info0; + + exists = serverid_exists(&global->server_id); + if (!exists) { + struct server_id_buf tmp; + + DBG_NOTICE("key '%s' server_id %s does not exist.\n", + hex_encode_talloc(frame, key.dptr, key.dsize), + server_id_str_buf(global->server_id, &tmp)); + if (DEBUGLVL(DBGLVL_NOTICE)) { + NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob); + } + TALLOC_FREE(frame); + dbwrap_record_delete(db_rec); + *is_free = true; + return; + } + + if (_g) { + *_g = talloc_move(mem_ctx, &global); + } + TALLOC_FREE(frame); +} + +NTSTATUS smb2srv_client_lookup_global(struct smbXsrv_client *client, + struct GUID client_guid, + TALLOC_CTX *mem_ctx, + struct smbXsrv_client_global0 **_global) +{ + struct smbXsrv_client_table *table = client->table; + struct smbXsrv_client_global0 *global = NULL; + bool is_free = false; + uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE]; + TDB_DATA key; + struct db_record *db_rec; + + key = smbXsrv_client_global_id_to_key(&client_guid, key_buf); + + db_rec = dbwrap_fetch_locked(table->global.db_ctx, + talloc_tos(), key); + if (db_rec == NULL) { + DBG_ERR("guid [%s]: Failed to lock key '%s'\n", + GUID_string(talloc_tos(), &client_guid), + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + return NT_STATUS_INTERNAL_DB_ERROR; + } + + smbXsrv_client_global_verify_record(db_rec, + &is_free, + NULL, + mem_ctx, + &global); + TALLOC_FREE(db_rec); + + if (is_free) { + return NT_STATUS_OBJECTID_NOT_FOUND; + } + + *_global = global; + return NT_STATUS_OK; +} + +NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req, + struct smbXsrv_client_global0 *global) +{ + DATA_BLOB blob; + enum ndr_err_code ndr_err; + NTSTATUS status; + struct smbXsrv_connection_pass0 pass_info0; + struct smbXsrv_connection_passB pass_blob; + struct iovec iov; + + pass_info0.initial_connect_time = global->initial_connect_time; + pass_info0.client_guid = global->client_guid; + pass_info0.negotiate_request.length = iov_buflen(smb2req->in.vector, + smb2req->in.vector_count); + pass_info0.negotiate_request.data = talloc_array(talloc_tos(), uint8_t, + pass_info0.negotiate_request.length); + if (pass_info0.negotiate_request.data == NULL) { + return NT_STATUS_NO_MEMORY; + } + iov_buf(smb2req->in.vector, smb2req->in.vector_count, + pass_info0.negotiate_request.data, + pass_info0.negotiate_request.length); + + ZERO_STRUCT(pass_blob); + pass_blob.version = smbXsrv_version_global_current(); + pass_blob.info.info0 = &pass_info0; + + if (DEBUGLVL(DBGLVL_DEBUG)) { + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + } + + ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &pass_blob, + (ndr_push_flags_fn_t)ndr_push_smbXsrv_connection_passB); + data_blob_free(&pass_info0.negotiate_request); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + return status; + } + + iov.iov_base = blob.data; + iov.iov_len = blob.length; + + status = messaging_send_iov(smb2req->xconn->msg_ctx, + global->server_id, + MSG_SMBXSRV_CONNECTION_PASS, + &iov, 1, + &smb2req->xconn->transport.sock, 1); + data_blob_free(&blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS smbXsrv_client_global_store(struct smbXsrv_client_global0 *global) +{ + struct smbXsrv_client_globalB global_blob; + DATA_BLOB blob = data_blob_null; + TDB_DATA key; + TDB_DATA val; + NTSTATUS status; + enum ndr_err_code ndr_err; + bool saved_stored = global->stored; + + /* + * TODO: if we use other versions than '0' + * we would add glue code here, that would be able to + * store the information in the old format. + */ + + if (global->db_rec == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + key = dbwrap_record_get_key(global->db_rec); + val = dbwrap_record_get_value(global->db_rec); + + ZERO_STRUCT(global_blob); + global_blob.version = smbXsrv_version_global_current(); + if (val.dsize >= 8) { + global_blob.seqnum = IVAL(val.dptr, 4); + } + global_blob.seqnum += 1; + global_blob.info.info0 = global; + + global->stored = true; + ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob, + (ndr_push_flags_fn_t)ndr_push_smbXsrv_client_globalB); + global->stored = saved_stored; + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + DBG_WARNING("key '%s' ndr_push - %s\n", + hex_encode_talloc(global->db_rec, key.dptr, key.dsize), + nt_errstr(status)); + TALLOC_FREE(global->db_rec); + return status; + } + + val = make_tdb_data(blob.data, blob.length); + status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("key '%s' store - %s\n", + hex_encode_talloc(global->db_rec, key.dptr, key.dsize), + nt_errstr(status)); + TALLOC_FREE(global->db_rec); + return status; + } + + global->stored = true; + + if (DEBUGLVL(DBGLVL_DEBUG)) { + DBG_DEBUG("key '%s' stored\n", + hex_encode_talloc(global->db_rec, key.dptr, key.dsize)); + NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob); + } + + TALLOC_FREE(global->db_rec); + + return NT_STATUS_OK; +} + +static NTSTATUS smbXsrv_client_global_remove(struct smbXsrv_client_global0 *global) +{ + struct smbXsrv_client_globalB global_blob; + TDB_DATA key; + NTSTATUS status; + + /* + * TODO: if we use other versions than '0' + * we would add glue code here, that would be able to + * store the information in the old format. + */ + + if (global->db_rec == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + key = dbwrap_record_get_key(global->db_rec); + + status = dbwrap_record_delete(global->db_rec); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("key '%s' delete - %s\n", + hex_encode_talloc(global->db_rec, key.dptr, key.dsize), + nt_errstr(status)); + TALLOC_FREE(global->db_rec); + return status; + } + global->stored = false; + if (DEBUGLVL(DBGLVL_DEBUG)) { + DBG_DEBUG("key '%s' delete\n", + hex_encode_talloc(global->db_rec, key.dptr, key.dsize)); + NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob); + } + + TALLOC_FREE(global->db_rec); + + return NT_STATUS_OK; +} + +static int smbXsrv_client_destructor(struct smbXsrv_client *client) +{ + NTSTATUS status; + + status = smbXsrv_client_remove(client); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("smbXsrv_client_remove() failed: %s\n", + nt_errstr(status)); + } + + TALLOC_FREE(client->global); + + return 0; +} + +static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data); +static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq); + +NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx, + NTTIME now, + struct smbXsrv_client **_client) +{ + struct smbXsrv_client_table *table; + struct smbXsrv_client *client = NULL; + struct smbXsrv_client_global0 *global = NULL; + NTSTATUS status; + struct tevent_req *subreq = NULL; + + status = smbXsrv_client_table_create(mem_ctx, + msg_ctx, + 1, /* max_clients */ + &table); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (table->local.num_clients >= table->local.max_clients) { + TALLOC_FREE(table); + return NT_STATUS_INSUFFICIENT_RESOURCES; + } + + client = talloc_zero(mem_ctx, struct smbXsrv_client); + if (client == NULL) { + TALLOC_FREE(table); + return NT_STATUS_NO_MEMORY; + } + client->ev_ctx = ev_ctx; + client->msg_ctx = msg_ctx; + + client->table = talloc_move(client, &table); + table = client->table; + + global = talloc_zero(client, struct smbXsrv_client_global0); + if (global == NULL) { + TALLOC_FREE(client); + return NT_STATUS_NO_MEMORY; + } + talloc_set_destructor(global, smbXsrv_client_global_destructor); + client->global = global; + + global->initial_connect_time = now; + + global->server_id = messaging_server_id(client->msg_ctx); + + table->local.num_clients += 1; + + talloc_set_destructor(client, smbXsrv_client_destructor); + + if (DEBUGLVL(DBGLVL_DEBUG)) { + struct smbXsrv_clientB client_blob; + + ZERO_STRUCT(client_blob); + client_blob.version = SMBXSRV_VERSION_0; + client_blob.info.info0 = client; + + DBG_DEBUG("client_guid[%s] stored\n", + GUID_string(talloc_tos(), &global->client_guid)); + NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob); + } + + subreq = messaging_filtered_read_send(client, client->ev_ctx, client->msg_ctx, + smbXsrv_client_connection_pass_filter, + client); + if (subreq == NULL) { + TALLOC_FREE(client); + return NT_STATUS_NO_MEMORY; + } + tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client); + + *_client = client; + return NT_STATUS_OK; +} + +static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data) +{ + if (rec->msg_type != MSG_SMBXSRV_CONNECTION_PASS) { + return false; + } + + if (rec->num_fds != 1) { + return false; + } + + if (rec->buf.length < SMB2_HDR_BODY) { + return false; + } + + /* TODO: verify client_guid...? */ + + return true; +} + +static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq) +{ + struct smbXsrv_client *client = + tevent_req_callback_data(subreq, + struct smbXsrv_client); + struct smbXsrv_connection *xconn = NULL; + int ret; + struct messaging_rec *rec = NULL; + struct smbXsrv_connection_passB pass_blob; + enum ndr_err_code ndr_err; + struct smbXsrv_connection_pass0 *pass_info0 = NULL; + NTSTATUS status; + int sock_fd = -1; + uint64_t seq_low; + + ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec); + TALLOC_FREE(subreq); + if (ret != 0) { + goto next; + } + + ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &pass_blob, + (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_connection_passB); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + DBG_WARNING("ndr_pull_struct_blob - %s\n", nt_errstr(status)); + goto next; + } + + DBG_DEBUG("MSG_SMBXSRV_CLIENT_CLOSE\n"); + if (DEBUGLVL(DBGLVL_DEBUG)) { + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + } + + if (pass_blob.version != SMBXSRV_VERSION_0) { + DBG_ERR("ignore invalid version %u\n", pass_blob.version); + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + goto next; + } + + pass_info0 = pass_blob.info.info0; + if (pass_info0 == NULL) { + DBG_ERR("ignore NULL info %u\n", pass_blob.version); + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + goto next; + } + + if (!GUID_equal(&client->global->client_guid, &pass_info0->client_guid)) + { + DBG_WARNING("client's client_guid [%s] != passed guid [%s]\n", + GUID_string(talloc_tos(), &client->global->client_guid), + GUID_string(talloc_tos(), &pass_info0->client_guid)); + if (DEBUGLVL(DBGLVL_WARNING)) { + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + } + goto next; + } + + if (client->global->initial_connect_time != + pass_info0->initial_connect_time) + { + DBG_WARNING("client's initial connect time [%s] (%llu) != " + "passed initial connect time [%s] (%llu)\n", + nt_time_string(talloc_tos(), + client->global->initial_connect_time), + (unsigned long long)client->global->initial_connect_time, + nt_time_string(talloc_tos(), + pass_info0->initial_connect_time), + (unsigned long long)pass_info0->initial_connect_time); + if (DEBUGLVL(DBGLVL_WARNING)) { + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + } + goto next; + } + + SMB_ASSERT(rec->num_fds == 1); + sock_fd = rec->fds[0]; + + DBG_ERR("got connection sockfd[%d]\n", sock_fd); + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + status = smbd_add_connection(client, sock_fd, &xconn); + if (!NT_STATUS_IS_OK(status)) { + close(sock_fd); + sock_fd = -1; + DBG_ERR("smbd_add_connection => %s\n", nt_errstr(status)); + NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob); + goto next; + } + + /* + * Set seq_low to mid received in negprot + */ + seq_low = BVAL(pass_info0->negotiate_request.data, + SMB2_HDR_MESSAGE_ID); + + xconn->smb2.client.guid_verified = true; + smbd_smb2_process_negprot(xconn, seq_low, + pass_info0->negotiate_request.data, + pass_info0->negotiate_request.length); + +next: + TALLOC_FREE(rec); + + subreq = messaging_filtered_read_send(client, client->ev_ctx, client->msg_ctx, + smbXsrv_client_connection_pass_filter, + client); + if (subreq == NULL) { + const char *r; + r = "messaging_read_send(MSG_SMBXSRV_CONNECTION_PASS failed"; + exit_server_cleanly(r); + return; + } + tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client); +} + +NTSTATUS smbXsrv_client_update(struct smbXsrv_client *client) +{ + struct smbXsrv_client_table *table = client->table; + NTSTATUS status; + uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE]; + TDB_DATA key; + + if (client->global->db_rec != NULL) { + DBG_ERR("guid [%s]: Called with db_rec != NULL'\n", + GUID_string(talloc_tos(), + &client->global->client_guid)); + return NT_STATUS_INTERNAL_ERROR; + } + + key = smbXsrv_client_global_id_to_key(&client->global->client_guid, + key_buf); + + client->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx, + client->global, key); + if (client->global->db_rec == NULL) { + DBG_ERR("guid [%s]: Failed to lock key '%s'\n", + GUID_string(talloc_tos(), &client->global->client_guid), + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + return NT_STATUS_INTERNAL_DB_ERROR; + } + + status = smbXsrv_client_global_store(client->global); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("client_guid[%s] store failed - %s\n", + GUID_string(talloc_tos(), &client->global->client_guid), + nt_errstr(status)); + return status; + } + + if (DEBUGLVL(DBGLVL_DEBUG)) { + struct smbXsrv_clientB client_blob; + + ZERO_STRUCT(client_blob); + client_blob.version = SMBXSRV_VERSION_0; + client_blob.info.info0 = client; + + DBG_DEBUG("client_guid[%s] stored\n", + GUID_string(talloc_tos(), &client->global->client_guid)); + NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob); + } + + return NT_STATUS_OK; +} + +NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client) +{ + struct smbXsrv_client_table *table = client->table; + NTSTATUS status; + uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE]; + TDB_DATA key; + + if (client->global->db_rec != NULL) { + DBG_ERR("client_guid[%s]: Called with db_rec != NULL'\n", + GUID_string(talloc_tos(), &client->global->client_guid)); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!client->global->stored) { + return NT_STATUS_OK; + } + + key = smbXsrv_client_global_id_to_key(&client->global->client_guid, + key_buf); + + client->global->db_rec = dbwrap_fetch_locked(table->global.db_ctx, + client->global, key); + if (client->global->db_rec == NULL) { + DBG_ERR("client_guid[%s]: Failed to lock key '%s'\n", + GUID_string(talloc_tos(), &client->global->client_guid), + hex_encode_talloc(talloc_tos(), key.dptr, key.dsize)); + return NT_STATUS_INTERNAL_DB_ERROR; + } + + status = smbXsrv_client_global_remove(client->global); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("client_guid[%s] store failed - %s\n", + GUID_string(talloc_tos(), &client->global->client_guid), + nt_errstr(status)); + return status; + } + + if (DEBUGLVL(DBGLVL_DEBUG)) { + struct smbXsrv_clientB client_blob; + + ZERO_STRUCT(client_blob); + client_blob.version = SMBXSRV_VERSION_0; + client_blob.info.info0 = client; + + DBG_DEBUG("client_guid[%s] stored\n", + GUID_string(talloc_tos(), &client->global->client_guid)); + NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob); + } + + return NT_STATUS_OK; +} diff --git a/source3/wscript_build b/source3/wscript_build index 06b24bfb43b..27e1b5ec719 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -592,6 +592,7 @@ bld.SAMBA3_LIBRARY('smbd_base', smbd/smb2_setinfo.c smbd/smb2_break.c smbd/smbXsrv_version.c + smbd/smbXsrv_client.c smbd/smbXsrv_session.c smbd/smbXsrv_tcon.c smbd/smbXsrv_open.c |