/** * check whether a serverid is the special placeholder for * a disconnected client */ bool server_id_is_disconnected(const struct server_id *id) { struct server_id dis; SMB_ASSERT(id != NULL); server_id_set_disconnected(&dis); return server_id_equal(id, &dis); }
struct server_id server_id_from_string(uint32_t local_vnn, const char *pid_string) { struct server_id result; unsigned long long pid; unsigned int vnn, task_id = 0; ZERO_STRUCT(result); /* * We accept various forms with 1, 2 or 3 component forms * because the server_id_str() can print different forms, and * we want backwards compatibility for scripts that may call * smbclient. */ if (sscanf(pid_string, "%u:%llu.%u", &vnn, &pid, &task_id) == 3) { result.vnn = vnn; result.pid = pid; result.task_id = task_id; } else if (sscanf(pid_string, "%u:%llu", &vnn, &pid) == 2) { result.vnn = vnn; result.pid = pid; } else if (sscanf(pid_string, "%llu.%u", &pid, &task_id) == 2) { result.vnn = local_vnn; result.pid = pid; result.task_id = task_id; } else if (sscanf(pid_string, "%llu", &pid) == 1) { result.vnn = local_vnn; result.pid = pid; } else if (strcmp(pid_string, "disconnected") ==0) { server_id_set_disconnected(&result); } else { result.vnn = NONCLUSTER_VNN; result.pid = UINT64_MAX; } return result; }
bool mark_share_mode_disconnected(struct share_mode_lock *lck, struct files_struct *fsp) { struct share_mode_entry entry, *e; if (lck->data->num_share_modes != 1) { return false; } if (fsp->op == NULL) { return false; } if (!fsp->op->global->durable) { return false; } /* Don't care about the pid owner being correct here - just a search. */ fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK); e = find_share_mode_entry(lck->data, &entry); if (e == NULL) { return false; } DEBUG(10, ("Marking share mode entry disconnected for durable handle\n")); server_id_set_disconnected(&e->pid); /* * On reopen the caller needs to check that * the client comes with the correct handle. */ e->share_file_id = fsp->op->global->open_persistent_id; lck->data->modified = true; return true; }
uint32_t smbXsrv_open_hash(struct smbXsrv_open *_open) { uint8_t buf[8+8+8]; uint32_t ret; TDB_DATA key; SBVAL(buf, 0, _open->global->open_persistent_id); SBVAL(buf, 8, _open->global->open_volatile_id); SBVAL(buf, 16, _open->global->open_time); key = (TDB_DATA) { .dptr = buf, .dsize = sizeof(buf) }; ret = tdb_jenkins_hash(&key); if (ret == 0) { ret = 1; } return ret; } static NTSTATUS smbXsrv_open_set_replay_cache(struct smbXsrv_open *op) { struct GUID *create_guid; struct GUID_txt_buf buf; char *guid_string; struct db_context *db = op->table->local.replay_cache_db_ctx; NTSTATUS status; if (!(op->flags & SMBXSRV_OPEN_NEED_REPLAY_CACHE)) { return NT_STATUS_OK; } if (op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE) { return NT_STATUS_OK; } create_guid = &op->global->create_guid; if (GUID_all_zero(create_guid)) { return NT_STATUS_OK; } guid_string = GUID_buf_string(create_guid, &buf); if (guid_string == NULL) { return NT_STATUS_INVALID_PARAMETER; } status = dbwrap_store_uint32_bystring(db, guid_string, op->local_id); if (NT_STATUS_IS_OK(status)) { op->flags |= SMBXSRV_OPEN_HAVE_REPLAY_CACHE; op->flags &= ~SMBXSRV_OPEN_NEED_REPLAY_CACHE; } return status; } static NTSTATUS smbXsrv_open_clear_replay_cache(struct smbXsrv_open *op) { struct GUID *create_guid; struct GUID_txt_buf buf; char *guid_string; struct db_context *db; NTSTATUS status; if (op->table == NULL) { return NT_STATUS_OK; } db = op->table->local.replay_cache_db_ctx; if (!(op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE)) { return NT_STATUS_OK; } create_guid = &op->global->create_guid; if (GUID_all_zero(create_guid)) { return NT_STATUS_OK; } guid_string = GUID_buf_string(create_guid, &buf); if (guid_string == NULL) { return NT_STATUS_INVALID_PARAMETER; } status = dbwrap_purge_bystring(db, guid_string); if (NT_STATUS_IS_OK(status)) { op->flags &= ~SMBXSRV_OPEN_HAVE_REPLAY_CACHE; } return status; } NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op) { struct smbXsrv_open_table *table = op->table; NTSTATUS status; if (op->global->db_rec != NULL) { DEBUG(0, ("smbXsrv_open_update(0x%08x): " "Called with db_rec != NULL'\n", op->global->open_global_id)); return NT_STATUS_INTERNAL_ERROR; } op->global->db_rec = smbXsrv_open_global_fetch_locked( table->global.db_ctx, op->global->open_global_id, op->global /* TALLOC_CTX */); if (op->global->db_rec == NULL) { return NT_STATUS_INTERNAL_DB_ERROR; } status = smbXsrv_open_global_store(op->global); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smbXsrv_open_update: " "global_id (0x%08x) store failed - %s\n", op->global->open_global_id, nt_errstr(status))); return status; } status = smbXsrv_open_set_replay_cache(op); if (!NT_STATUS_IS_OK(status)) { DBG_ERR("smbXsrv_open_set_replay_cache failed: %s\n", nt_errstr(status)); return status; } if (CHECK_DEBUGLVL(10)) { struct smbXsrv_openB open_blob; ZERO_STRUCT(open_blob); open_blob.version = SMBXSRV_VERSION_0; open_blob.info.info0 = op; DEBUG(10,("smbXsrv_open_update: global_id (0x%08x) stored\n", op->global->open_global_id)); NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob); } return NT_STATUS_OK; } NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now) { struct smbXsrv_open_table *table; struct db_record *local_rec = NULL; struct db_record *global_rec = NULL; NTSTATUS status; NTSTATUS error = NT_STATUS_OK; error = smbXsrv_open_clear_replay_cache(op); if (!NT_STATUS_IS_OK(error)) { DBG_ERR("smbXsrv_open_clear_replay_cache failed: %s\n", nt_errstr(error)); } if (op->table == NULL) { return error; } table = op->table; op->table = NULL; op->status = NT_STATUS_FILE_CLOSED; op->global->disconnect_time = now; server_id_set_disconnected(&op->global->server_id); global_rec = op->global->db_rec; op->global->db_rec = NULL; if (global_rec == NULL) { global_rec = smbXsrv_open_global_fetch_locked( table->global.db_ctx, op->global->open_global_id, op->global /* TALLOC_CTX */); if (global_rec == NULL) { error = NT_STATUS_INTERNAL_ERROR; } } if (global_rec != NULL && op->global->durable) { /* * If it is a durable open we need to update the global part * instead of deleting it */ op->global->db_rec = global_rec; status = smbXsrv_open_global_store(op->global); if (NT_STATUS_IS_OK(status)) { /* * smbXsrv_open_global_store does the free * of op->global->db_rec */ global_rec = NULL; } if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smbXsrv_open_close(0x%08x)" "smbXsrv_open_global_store() failed - %s\n", op->global->open_global_id, nt_errstr(status))); error = status; } if (NT_STATUS_IS_OK(status) && CHECK_DEBUGLVL(10)) { struct smbXsrv_openB open_blob; ZERO_STRUCT(open_blob); open_blob.version = SMBXSRV_VERSION_0; open_blob.info.info0 = op; DEBUG(10,("smbXsrv_open_close(0x%08x): " "stored disconnect\n", op->global->open_global_id)); NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob); } } if (global_rec != NULL) { status = dbwrap_record_delete(global_rec); if (!NT_STATUS_IS_OK(status)) { TDB_DATA key = dbwrap_record_get_key(global_rec); DEBUG(0, ("smbXsrv_open_close(0x%08x): " "failed to delete global key '%s': %s\n", op->global->open_global_id, hex_encode_talloc(global_rec, key.dptr, key.dsize), nt_errstr(status))); error = status; } } TALLOC_FREE(global_rec); local_rec = op->db_rec; if (local_rec == NULL) { local_rec = smbXsrv_open_local_fetch_locked(table->local.db_ctx, op->local_id, op /* TALLOC_CTX*/); if (local_rec == NULL) { error = NT_STATUS_INTERNAL_ERROR; } } if (local_rec != NULL) { status = dbwrap_record_delete(local_rec); if (!NT_STATUS_IS_OK(status)) { TDB_DATA key = dbwrap_record_get_key(local_rec); DEBUG(0, ("smbXsrv_open_close(0x%08x): " "failed to delete local key '%s': %s\n", op->global->open_global_id, hex_encode_talloc(local_rec, key.dptr, key.dsize), nt_errstr(status))); error = status; } table->local.num_opens -= 1; } if (op->db_rec == NULL) { TALLOC_FREE(local_rec); } op->db_rec = NULL; if (op->compat) { op->compat->op = NULL; file_free(NULL, op->compat); op->compat = NULL; } return error; } NTSTATUS smb1srv_open_table_init(struct smbXsrv_connection *conn) { uint32_t max_opens; /* * Allow a range from 1..65534. * * With real_max_open_files possible ids, * truncated to the SMB1 limit of 16-bit. * * 0 and 0xFFFF are no valid ids. */ max_opens = conn->client->sconn->real_max_open_files; max_opens = MIN(max_opens, UINT16_MAX - 1); return smbXsrv_open_table_init(conn, 1, UINT16_MAX - 1, max_opens); }
struct server_id server_id_from_string(uint32_t local_vnn, const char *pid_string) { struct server_id templ = { .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX }; struct server_id result; int ret; /* * We accept various forms with 1, 2 or 3 component forms * because the server_id_str_buf() can print different forms, and * we want backwards compatibility for scripts that may call * smbclient. */ result = templ; ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64, &result.vnn, &result.pid, &result.task_id, &result.unique_id); if (ret == 4) { return result; } result = templ; ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32, &result.vnn, &result.pid, &result.task_id); if (ret == 3) { return result; } result = templ; ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64, &result.vnn, &result.pid, &result.unique_id); if (ret == 3) { return result; } result = templ; ret = sscanf(pid_string, "%"SCNu32":%"SCNu64, &result.vnn, &result.pid); if (ret == 2) { return result; } result = templ; ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64, &result.pid, &result.task_id, &result.unique_id); if (ret == 3) { result.vnn = local_vnn; return result; } result = templ; ret = sscanf(pid_string, "%"SCNu64".%"SCNu32, &result.pid, &result.task_id); if (ret == 2) { result.vnn = local_vnn; return result; } result = templ; ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64, &result.pid, &result.unique_id); if (ret == 2) { result.vnn = local_vnn; return result; } result = templ; ret = sscanf(pid_string, "%"SCNu64, &result.pid); if (ret == 1) { result.vnn = local_vnn; return result; } if (strcmp(pid_string, "disconnected") == 0) { server_id_set_disconnected(&result); return result; } return templ; }
NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now) { struct smbXsrv_open_table *table; struct db_record *local_rec = NULL; struct db_record *global_rec = NULL; NTSTATUS status; NTSTATUS error = NT_STATUS_OK; if (op->table == NULL) { return NT_STATUS_OK; } table = op->table; op->table = NULL; op->status = NT_STATUS_FILE_CLOSED; op->global->disconnect_time = now; server_id_set_disconnected(&op->global->server_id); global_rec = op->global->db_rec; op->global->db_rec = NULL; if (global_rec == NULL) { uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE]; TDB_DATA key; key = smbXsrv_open_global_id_to_key( op->global->open_global_id, key_buf); global_rec = dbwrap_fetch_locked(table->global.db_ctx, op->global, key); if (global_rec == NULL) { DEBUG(0, ("smbXsrv_open_close(0x%08x): " "Failed to lock global key '%s'\n", op->global->open_global_id, hex_encode_talloc(global_rec, key.dptr, key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } if (global_rec != NULL && op->global->durable) { /* * If it is a durable open we need to update the global part * instead of deleting it */ op->global->db_rec = global_rec; status = smbXsrv_open_global_store(op->global); if (NT_STATUS_IS_OK(status)) { /* * smbXsrv_open_global_store does the free * of op->global->db_rec */ global_rec = NULL; } if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("smbXsrv_open_close(0x%08x)" "smbXsrv_open_global_store() failed - %s\n", op->global->open_global_id, nt_errstr(status))); error = status; } if (NT_STATUS_IS_OK(status) && CHECK_DEBUGLVL(10)) { struct smbXsrv_openB open_blob; ZERO_STRUCT(open_blob); open_blob.version = SMBXSRV_VERSION_0; open_blob.info.info0 = op; DEBUG(10,("smbXsrv_open_close(0x%08x): " "stored disconnect\n", op->global->open_global_id)); NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob); } } if (global_rec != NULL) { status = dbwrap_record_delete(global_rec); if (!NT_STATUS_IS_OK(status)) { TDB_DATA key = dbwrap_record_get_key(global_rec); DEBUG(0, ("smbXsrv_open_close(0x%08x): " "failed to delete global key '%s': %s\n", op->global->open_global_id, hex_encode_talloc(global_rec, key.dptr, key.dsize), nt_errstr(status))); error = status; } } TALLOC_FREE(global_rec); local_rec = op->db_rec; if (local_rec == NULL) { uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE]; TDB_DATA key; key = smbXsrv_open_local_id_to_key(op->local_id, key_buf); local_rec = dbwrap_fetch_locked(table->local.db_ctx, op, key); if (local_rec == NULL) { DEBUG(0, ("smbXsrv_open_close(0x%08x): " "Failed to lock local key '%s'\n", op->global->open_global_id, hex_encode_talloc(local_rec, key.dptr, key.dsize))); error = NT_STATUS_INTERNAL_ERROR; } } if (local_rec != NULL) { status = dbwrap_record_delete(local_rec); if (!NT_STATUS_IS_OK(status)) { TDB_DATA key = dbwrap_record_get_key(local_rec); DEBUG(0, ("smbXsrv_open_close(0x%08x): " "failed to delete local key '%s': %s\n", op->global->open_global_id, hex_encode_talloc(local_rec, key.dptr, key.dsize), nt_errstr(status))); error = status; } table->local.num_opens -= 1; } if (op->db_rec == NULL) { TALLOC_FREE(local_rec); } op->db_rec = NULL; if (op->compat) { op->compat->op = NULL; file_free(NULL, op->compat); op->compat = NULL; } return error; }