📄 gentest.c
字号:
/* Unix SMB/CIFS implementation. generic testing tool - version with both SMB and SMB2 support Copyright (C) Andrew Tridgell 2003-2008 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 "lib/cmdline/popt_common.h"#include "lib/events/events.h"#include "system/time.h"#include "system/filesys.h"#include "libcli/raw/request.h"#include "libcli/libcli.h"#include "libcli/raw/libcliraw.h"#include "libcli/smb2/smb2.h"#include "libcli/smb2/smb2_calls.h"#include "librpc/gen_ndr/security.h"#include "librpc/gen_ndr/ndr_security.h"#include "auth/credentials/credentials.h"#include "libcli/resolve/resolve.h"#include "auth/gensec/gensec.h"#include "param/param.h"#include "dynconfig/dynconfig.h"#include "libcli/security/security.h"#include "libcli/raw/raw_proto.h"#define NSERVERS 2#define NINSTANCES 2/* global options */static struct gentest_options { int showall; int analyze; int analyze_always; int analyze_continuous; uint_t max_open_handles; uint_t seed; uint_t numops; int use_oplocks; char **ignore_patterns; const char *seeds_file; int use_preset_seeds; int fast_reconnect; int mask_indexing; int no_eas; int no_acls; int skip_cleanup; int valid; int smb2;} options;/* mapping between open handles on the server and local handles */static struct { bool active; uint_t instance; struct smb2_handle smb2_handle[NSERVERS]; /* SMB2 */ uint16_t smb_handle[NSERVERS]; /* SMB */ const char *name;} *open_handles;static uint_t num_open_handles;/* state information for the servers. We open NINSTANCES connections to each server */static struct { struct smb2_tree *smb2_tree[NINSTANCES]; struct smbcli_tree *smb_tree[NINSTANCES]; char *server_name; char *share_name; struct cli_credentials *credentials;} servers[NSERVERS];/* the seeds and flags for each operation */static struct { uint_t seed; bool disabled;} *op_parms;/* oplock break info */static struct { bool got_break; struct smb2_handle smb2_handle; uint16_t smb_handle; uint16_t handle; uint8_t level; bool do_close;} oplocks[NSERVERS][NINSTANCES];/* change notify reply info */static struct { int notify_count; NTSTATUS status; union smb_notify notify;} notifies[NSERVERS][NINSTANCES];/* info relevant to the current operation */static struct { const char *name; uint_t seed; NTSTATUS status; uint_t opnum; TALLOC_CTX *mem_ctx; const char *mismatch;} current_op;static struct smb2_handle bad_smb2_handle;#define BAD_HANDLE 0xFFFEstatic bool oplock_handler_smb2(struct smb2_transport *transport, const struct smb2_handle *handle, uint8_t level, void *private_data);static void idle_func_smb2(struct smb2_transport *transport, void *private);static bool oplock_handler_smb(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private);static void idle_func_smb(struct smbcli_transport *transport, void *private);/* check if a string should be ignored. This is used as the basis for all error ignore settings*/static bool ignore_pattern(const char *str){ int i; if (!options.ignore_patterns) return false; for (i=0;options.ignore_patterns[i];i++) { if (strcmp(options.ignore_patterns[i], str) == 0 || gen_fnmatch(options.ignore_patterns[i], str) == 0) { DEBUG(2,("Ignoring '%s'\n", str)); return true; } } return false;}/***************************************************** connect to the servers*******************************************************/static bool connect_servers_fast(void){ int h, i; /* close all open files */ for (h=0;h<options.max_open_handles;h++) { if (!open_handles[h].active) continue; for (i=0;i<NSERVERS;i++) { NTSTATUS status; if (options.smb2) { status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance], open_handles[h].smb2_handle[i]); } else { status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], open_handles[h].smb_handle[i]); } if (NT_STATUS_IS_ERR(status)) { return false; } open_handles[h].active = false; } } return true;}/***************************************************** connect to the servers*******************************************************/static bool connect_servers(struct event_context *ev, struct loadparm_context *lp_ctx){ int i, j; if (options.fast_reconnect && servers[0].smb2_tree[0]) { if (connect_servers_fast()) { return true; } } /* close any existing connections */ for (i=0;i<NSERVERS;i++) { for (j=0;j<NINSTANCES;j++) { if (servers[i].smb2_tree[j]) { smb2_tdis(servers[i].smb2_tree[j]); talloc_free(servers[i].smb2_tree[j]); servers[i].smb2_tree[j] = NULL; } if (servers[i].smb_tree[j]) { smb_tree_disconnect(servers[i].smb_tree[j]); talloc_free(servers[i].smb_tree[j]); servers[i].smb_tree[j] = NULL; } } } for (i=0;i<NSERVERS;i++) { for (j=0;j<NINSTANCES;j++) { NTSTATUS status; struct smbcli_options smb_options; lp_smbcli_options(lp_ctx, &smb_options); printf("Connecting to \\\\%s\\%s as %s - instance %d\n", servers[i].server_name, servers[i].share_name, servers[i].credentials->username, j); cli_credentials_set_workstation(servers[i].credentials, "gentest", CRED_SPECIFIED); if (options.smb2) { status = smb2_connect(NULL, servers[i].server_name, servers[i].share_name, lp_resolve_context(lp_ctx), servers[i].credentials, &servers[i].smb2_tree[j], ev, &smb_options); } else { status = smbcli_tree_full_connection(NULL, &servers[i].smb_tree[j], servers[i].server_name, lp_smb_ports(lp_ctx), servers[i].share_name, "A:", servers[i].credentials, lp_resolve_context(lp_ctx), ev, &smb_options); } if (!NT_STATUS_IS_OK(status)) { printf("Failed to connect to \\\\%s\\%s - %s\n", servers[i].server_name, servers[i].share_name, nt_errstr(status)); return false; } if (options.smb2) { servers[i].smb2_tree[j]->session->transport->oplock.handler = oplock_handler_smb2; servers[i].smb2_tree[j]->session->transport->oplock.private_data = (void *)(uintptr_t)((i<<8)|j); smb2_transport_idle_handler(servers[i].smb2_tree[j]->session->transport, idle_func_smb2, 50000, NULL); } else { smbcli_oplock_handler(servers[i].smb_tree[j]->session->transport, oplock_handler_smb, (void *)(uintptr_t)((i<<8)|j)); smbcli_transport_idle_handler(servers[i].smb_tree[j]->session->transport, idle_func_smb, 50000, (void *)(uintptr_t)((i<<8)|j)); } } } return true;}/* work out the time skew between the servers - be conservative*/static uint_t time_skew(void){ uint_t ret; if (options.smb2) { ret = labs(servers[0].smb2_tree[0]->session->transport->negotiate.system_time - servers[1].smb2_tree[0]->session->transport->negotiate.system_time); } else { ret = labs(servers[0].smb_tree[0]->session->transport->negotiate.server_time - servers[1].smb_tree[0]->session->transport->negotiate.server_time); } return ret + 300;}static bool smb2_handle_equal(const struct smb2_handle *h1, const struct smb2_handle *h2){ return memcmp(h1, h2, sizeof(struct smb2_handle)) == 0;}/* turn a server handle into a local handle*/static uint_t fnum_to_handle_smb2(int server, int instance, struct smb2_handle server_handle){ uint_t i; for (i=0;i<options.max_open_handles;i++) { if (!open_handles[i].active || instance != open_handles[i].instance) continue; if (smb2_handle_equal(&open_handles[i].smb2_handle[server], &server_handle)) { return i; } } printf("Invalid server handle in fnum_to_handle on server %d instance %d\n", server, instance); return BAD_HANDLE;}/* turn a server handle into a local handle*/static uint_t fnum_to_handle_smb(int server, int instance, uint16_t server_handle){ uint_t i; for (i=0;i<options.max_open_handles;i++) { if (!open_handles[i].active || instance != open_handles[i].instance) continue; if (open_handles[i].smb_handle[server] == server_handle) { return i; } } printf("Invalid server handle in fnum_to_handle on server %d instance %d\n", server, instance); return BAD_HANDLE;}/* add some newly opened handles*/static void gen_add_handle_smb2(int instance, const char *name, struct smb2_handle handles[NSERVERS]){ int i, h; for (h=0;h<options.max_open_handles;h++) { if (!open_handles[h].active) break; } if (h == options.max_open_handles) { /* we have to force close a random handle */ h = random() % options.max_open_handles; for (i=0;i<NSERVERS;i++) { NTSTATUS status; status = smb2_util_close(servers[i].smb2_tree[open_handles[h].instance], open_handles[h].smb2_handle[i]); if (NT_STATUS_IS_ERR(status)) { printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n", nt_errstr(status)); } } printf("Recovered handle %d\n", h); num_open_handles--; } for (i=0;i<NSERVERS;i++) { open_handles[h].smb2_handle[i] = handles[i]; open_handles[h].instance = instance; open_handles[h].active = true; open_handles[h].name = name; } num_open_handles++; printf("OPEN num_open_handles=%d h=%d (%s)\n", num_open_handles, h, name);}/* add some newly opened handles*/static void gen_add_handle_smb(int instance, const char *name, uint16_t handles[NSERVERS]){ int i, h; for (h=0;h<options.max_open_handles;h++) { if (!open_handles[h].active) break; } if (h == options.max_open_handles) { /* we have to force close a random handle */ h = random() % options.max_open_handles; for (i=0;i<NSERVERS;i++) { NTSTATUS status; status = smbcli_close(servers[i].smb_tree[open_handles[h].instance], open_handles[h].smb_handle[i]); if (NT_STATUS_IS_ERR(status)) { printf("INTERNAL ERROR: Close failed when recovering handle! - %s\n", nt_errstr(status)); } } printf("Recovered handle %d\n", h); num_open_handles--; } for (i=0;i<NSERVERS;i++) { open_handles[h].smb_handle[i] = handles[i]; open_handles[h].instance = instance; open_handles[h].active = true; open_handles[h].name = name; } num_open_handles++; printf("OPEN num_open_handles=%d h=%d (%s)\n", num_open_handles, h, name);}/* remove a closed handle*/static void gen_remove_handle_smb2(int instance, struct smb2_handle handles[NSERVERS]){ int h; for (h=0;h<options.max_open_handles;h++) { if (instance == open_handles[h].instance && smb2_handle_equal(&open_handles[h].smb2_handle[0], &handles[0])) { open_handles[h].active = false; num_open_handles--; printf("CLOSE num_open_handles=%d h=%d (%s)\n", num_open_handles, h, open_handles[h].name); return; } } printf("Removing invalid handle!?\n"); exit(1);}/* remove a closed handle*/static void gen_remove_handle_smb(int instance, uint16_t handles[NSERVERS]){ int h; for (h=0;h<options.max_open_handles;h++) { if (instance == open_handles[h].instance && open_handles[h].smb_handle[0] == handles[0]) { open_handles[h].active = false; num_open_handles--; printf("CLOSE num_open_handles=%d h=%d (%s)\n", num_open_handles, h, open_handles[h].name); return; } } printf("Removing invalid handle!?\n"); exit(1);}/* return true with 'chance' probability as a percentage*/static bool gen_chance(uint_t chance){ return ((random() % 100) <= chance);}/* map an internal handle number to a server handle*/static struct smb2_handle gen_lookup_handle_smb2(int server, uint16_t handle){ if (handle == BAD_HANDLE) return bad_smb2_handle; return open_handles[handle].smb2_handle[server];}/* map an internal handle number to a server handle*/static uint16_t gen_lookup_handle_smb(int server, uint16_t handle){ if (handle == BAD_HANDLE) return BAD_HANDLE; return open_handles[handle].smb_handle[server];}/* return a file handle*/static uint16_t gen_fnum(int instance){ uint16_t h; int count = 0; if (gen_chance(20)) return BAD_HANDLE; while (num_open_handles > 0 && count++ < 10*options.max_open_handles) { h = random() % options.max_open_handles; if (open_handles[h].active && open_handles[h].instance == instance) { return h; } } return BAD_HANDLE;}/* return a file handle, but skewed so we don't close the last couple of handles too readily*/static uint16_t gen_fnum_close(int instance){ if (num_open_handles < 5) { if (gen_chance(90)) return BAD_HANDLE; } return gen_fnum(instance);}/* generate an integer in a specified range*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -