static void test_scan_call(struct torture_context *tctx, const struct ndr_interface_table *iface, int opnum) { DATA_BLOB stub_in, stub_out; int i; NTSTATUS status; struct dcerpc_pipe *p = NULL; struct policy_handle handle; reopen(tctx, &p, iface); get_policy_handle(p, tctx, &handle); /* work out the minimum amount of input data */ for (i=0;i<2000;i++) { stub_in = data_blob(NULL, i); data_blob_clear(&stub_in); status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); if (NT_STATUS_IS_OK(status)) { printf("opnum %d min_input %d - output %d\n", opnum, (int)stub_in.length, (int)stub_out.length); dump_data(0, stub_out.data, stub_out.length); talloc_free(p); test_ptr_scan(tctx, iface, opnum, &stub_in, 0, stub_in.length, 0); return; } fill_blob_handle(&stub_in, tctx, &handle); status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); if (NT_STATUS_IS_OK(status)) { printf("opnum %d min_input %d - output %d (with handle)\n", opnum, (int)stub_in.length, (int)stub_out.length); dump_data(0, stub_out.data, stub_out.length); talloc_free(p); test_ptr_scan(tctx, iface, opnum, &stub_in, 0, stub_in.length, 0); return; } if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { printf("opnum %d size %d fault %s\n", opnum, i, dcerpc_errstr(tctx, p->last_fault_code)); if (p->last_fault_code == 5) { reopen(tctx, &p, iface); } continue; } printf("opnum %d size %d error %s\n", opnum, i, nt_errstr(status)); } printf("opnum %d minimum not found!?\n", opnum); talloc_free(p); }
static void try_expand(struct torture_context *tctx, const struct ndr_interface_table *iface, int opnum, DATA_BLOB *base_in, int insert_ofs, int depth) { DATA_BLOB stub_in, stub_out; int n; NTSTATUS status; struct dcerpc_pipe *p = NULL; reopen(tctx, &p, iface); /* work out how much to expand to get a non fault */ for (n=0;n<2000;n++) { stub_in = data_blob(NULL, base_in->length + n); data_blob_clear(&stub_in); memcpy(stub_in.data, base_in->data, insert_ofs); memcpy(stub_in.data+insert_ofs+n, base_in->data+insert_ofs, base_in->length-insert_ofs); status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { print_depth(depth); printf("expand by %d gives %s\n", n, nt_errstr(status)); if (n >= 4) { test_ptr_scan(tctx, iface, opnum, &stub_in, insert_ofs, insert_ofs+n, depth+1); } return; } else { #if 0 print_depth(depth); printf("expand by %d gives fault %s\n", n, dcerpc_errstr(tctx, p->last_fault_code)); #endif } if (p->last_fault_code == 5) { reopen(tctx, &p, iface); } } talloc_free(p); }
static void test_ptr_scan(struct torture_context *tctx, const struct ndr_interface_table *iface, int opnum, DATA_BLOB *base_in, int min_ofs, int max_ofs, int depth) { DATA_BLOB stub_in, stub_out; int ofs; NTSTATUS status; struct dcerpc_pipe *p = NULL; reopen(tctx, &p, iface); stub_in = data_blob(NULL, base_in->length); memcpy(stub_in.data, base_in->data, base_in->length); /* work out which elements are pointers */ for (ofs=min_ofs;ofs<=max_ofs-4;ofs+=4) { SIVAL(stub_in.data, ofs, 1); status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { print_depth(depth); printf("possible ptr at ofs %d - fault %s\n", ofs-min_ofs, dcerpc_errstr(tctx, p->last_fault_code)); if (p->last_fault_code == 5) { reopen(tctx, &p, iface); } if (depth == 0) { try_expand(tctx, iface, opnum, &stub_in, ofs+4, depth+1); } else { try_expand(tctx, iface, opnum, &stub_in, max_ofs, depth+1); } SIVAL(stub_in.data, ofs, 0); continue; } SIVAL(stub_in.data, ofs, 0); } talloc_free(p); }
/* work out how many calls there are for an interface */ static BOOL test_num_calls(const struct dcerpc_interface_table *iface, TALLOC_CTX *mem_ctx, struct dcerpc_syntax_id *id) { struct dcerpc_pipe *p; NTSTATUS status; int i; DATA_BLOB stub_in, stub_out; int idl_calls; struct dcerpc_interface_table tbl; /* FIXME: This should be fixed when torture_rpc_connection * takes a dcerpc_syntax_id */ tbl.name = iface->name; tbl.syntax_id = *id; status = torture_rpc_connection(mem_ctx, &p, iface); if (!NT_STATUS_IS_OK(status)) { char *uuid_str = GUID_string(mem_ctx, &id->uuid); printf("Failed to connect to '%s' on '%s' - %s\n", uuid_str, iface->name, nt_errstr(status)); talloc_free(uuid_str); return False; } /* make null calls */ stub_in = data_blob(NULL, 1000); memset(stub_in.data, 0xFF, stub_in.length); for (i=0;i<200;i++) { status = dcerpc_request(p, NULL, False, i, mem_ctx, &stub_in, &stub_out); if (!NT_STATUS_IS_OK(status) && p->last_fault_code == DCERPC_FAULT_OP_RNG_ERROR) { break; } if (!NT_STATUS_IS_OK(status) && p->last_fault_code == 5) { printf("\tpipe disconnected at %d\n", i); goto done; } if (!NT_STATUS_IS_OK(status) && p->last_fault_code == 0x80010111) { printf("\terr 0x80010111 at %d\n", i); goto done; } } printf("\t%d calls available\n", i); idl_calls = idl_num_calls(&id->uuid, id->if_version); if (idl_calls == -1) { printf("\tinterface not known in local IDL\n"); } else if (i != idl_calls) { printf("\tWARNING: local IDL defines %u calls\n", idl_calls); } else { printf("\tOK: matches num_calls in local IDL\n"); } done: talloc_free(p); return True; }