1/* 2 Unix SMB/CIFS implementation. 3 4 auto-idl scanner 5 6 Copyright (C) Andrew Tridgell 2003 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "torture/torture.h" 24#include "librpc/gen_ndr/ndr_drsuapi_c.h" 25#include "librpc/gen_ndr/ndr_misc.h" 26#include "librpc/ndr/ndr_table.h" 27#include "torture/rpc/rpc.h" 28#include "librpc/rpc/dcerpc_proto.h" 29 30 31#if 1 32/* 33 get a DRSUAPI policy handle 34*/ 35static bool get_policy_handle(struct dcerpc_pipe *p, 36 TALLOC_CTX *mem_ctx, 37 struct policy_handle *handle) 38{ 39 NTSTATUS status; 40 struct drsuapi_DsBind r; 41 42 ZERO_STRUCT(r); 43 r.out.bind_handle = handle; 44 45 status = dcerpc_drsuapi_DsBind(p, mem_ctx, &r); 46 if (!NT_STATUS_IS_OK(status)) { 47 printf("drsuapi_DsBind failed - %s\n", nt_errstr(status)); 48 return false; 49 } 50 51 return true; 52} 53#else 54/* 55 get a SAMR handle 56*/ 57static bool get_policy_handle(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 58 struct policy_handle *handle) 59{ 60 NTSTATUS status; 61 struct samr_Connect r; 62 63 r.in.system_name = 0; 64 r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; 65 r.out.connect_handle = handle; 66 67 status = dcerpc_samr_Connect(p, mem_ctx, &r); 68 if (!NT_STATUS_IS_OK(status)) { 69 printf("samr_Connect failed - %s\n", nt_errstr(status)); 70 return false; 71 } 72 73 return true; 74} 75#endif 76 77static void fill_blob_handle(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 78 struct policy_handle *handle) 79{ 80 DATA_BLOB b2; 81 82 if (blob->length < 20) { 83 return; 84 } 85 86 ndr_push_struct_blob(&b2, mem_ctx, NULL, handle, (ndr_push_flags_fn_t)ndr_push_policy_handle); 87 88 memcpy(blob->data, b2.data, 20); 89} 90 91static void reopen(struct torture_context *tctx, 92 struct dcerpc_pipe **p, 93 const struct ndr_interface_table *iface) 94{ 95 NTSTATUS status; 96 97 talloc_free(*p); 98 99 status = torture_rpc_connection(tctx, p, iface); 100 if (!NT_STATUS_IS_OK(status)) { 101 printf("Failed to reopen '%s' - %s\n", iface->name, nt_errstr(status)); 102 exit(1); 103 } 104} 105 106static void print_depth(int depth) 107{ 108 int i; 109 for (i=0;i<depth;i++) { 110 printf(" "); 111 } 112} 113 114static void test_ptr_scan(struct torture_context *tctx, const struct ndr_interface_table *iface, 115 int opnum, DATA_BLOB *base_in, int min_ofs, int max_ofs, int depth); 116 117static void try_expand(struct torture_context *tctx, const struct ndr_interface_table *iface, 118 int opnum, DATA_BLOB *base_in, int insert_ofs, int depth) 119{ 120 DATA_BLOB stub_in, stub_out; 121 int n; 122 NTSTATUS status; 123 struct dcerpc_pipe *p = NULL; 124 125 reopen(tctx, &p, iface); 126 127 /* work out how much to expand to get a non fault */ 128 for (n=0;n<2000;n++) { 129 stub_in = data_blob(NULL, base_in->length + n); 130 data_blob_clear(&stub_in); 131 memcpy(stub_in.data, base_in->data, insert_ofs); 132 memcpy(stub_in.data+insert_ofs+n, base_in->data+insert_ofs, base_in->length-insert_ofs); 133 134 status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); 135 136 if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { 137 print_depth(depth); 138 printf("expand by %d gives %s\n", n, nt_errstr(status)); 139 if (n >= 4) { 140 test_ptr_scan(tctx, iface, opnum, &stub_in, 141 insert_ofs, insert_ofs+n, depth+1); 142 } 143 return; 144 } else { 145#if 0 146 print_depth(depth); 147 printf("expand by %d gives fault %s\n", n, dcerpc_errstr(tctx, p->last_fault_code)); 148#endif 149 } 150 if (p->last_fault_code == 5) { 151 reopen(tctx, &p, iface); 152 } 153 } 154 155 talloc_free(p); 156} 157 158 159static void test_ptr_scan(struct torture_context *tctx, const struct ndr_interface_table *iface, 160 int opnum, DATA_BLOB *base_in, int min_ofs, int max_ofs, int depth) 161{ 162 DATA_BLOB stub_in, stub_out; 163 int ofs; 164 NTSTATUS status; 165 struct dcerpc_pipe *p = NULL; 166 167 reopen(tctx, &p, iface); 168 169 stub_in = data_blob(NULL, base_in->length); 170 memcpy(stub_in.data, base_in->data, base_in->length); 171 172 /* work out which elements are pointers */ 173 for (ofs=min_ofs;ofs<=max_ofs-4;ofs+=4) { 174 SIVAL(stub_in.data, ofs, 1); 175 status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); 176 177 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { 178 print_depth(depth); 179 printf("possible ptr at ofs %d - fault %s\n", 180 ofs-min_ofs, dcerpc_errstr(tctx, p->last_fault_code)); 181 if (p->last_fault_code == 5) { 182 reopen(tctx, &p, iface); 183 } 184 if (depth == 0) { 185 try_expand(tctx, iface, opnum, &stub_in, ofs+4, depth+1); 186 } else { 187 try_expand(tctx, iface, opnum, &stub_in, max_ofs, depth+1); 188 } 189 SIVAL(stub_in.data, ofs, 0); 190 continue; 191 } 192 SIVAL(stub_in.data, ofs, 0); 193 } 194 195 talloc_free(p); 196} 197 198 199static void test_scan_call(struct torture_context *tctx, const struct ndr_interface_table *iface, int opnum) 200{ 201 DATA_BLOB stub_in, stub_out; 202 int i; 203 NTSTATUS status; 204 struct dcerpc_pipe *p = NULL; 205 struct policy_handle handle; 206 207 reopen(tctx, &p, iface); 208 209 get_policy_handle(p, tctx, &handle); 210 211 /* work out the minimum amount of input data */ 212 for (i=0;i<2000;i++) { 213 stub_in = data_blob(NULL, i); 214 data_blob_clear(&stub_in); 215 216 217 status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); 218 219 if (NT_STATUS_IS_OK(status)) { 220 printf("opnum %d min_input %d - output %d\n", 221 opnum, (int)stub_in.length, (int)stub_out.length); 222 dump_data(0, stub_out.data, stub_out.length); 223 talloc_free(p); 224 test_ptr_scan(tctx, iface, opnum, &stub_in, 0, stub_in.length, 0); 225 return; 226 } 227 228 fill_blob_handle(&stub_in, tctx, &handle); 229 230 status = dcerpc_request(p, NULL, opnum, tctx, &stub_in, &stub_out); 231 232 if (NT_STATUS_IS_OK(status)) { 233 printf("opnum %d min_input %d - output %d (with handle)\n", 234 opnum, (int)stub_in.length, (int)stub_out.length); 235 dump_data(0, stub_out.data, stub_out.length); 236 talloc_free(p); 237 test_ptr_scan(tctx, iface, opnum, &stub_in, 0, stub_in.length, 0); 238 return; 239 } 240 241 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { 242 printf("opnum %d size %d fault %s\n", opnum, i, dcerpc_errstr(tctx, p->last_fault_code)); 243 if (p->last_fault_code == 5) { 244 reopen(tctx, &p, iface); 245 } 246 continue; 247 } 248 249 printf("opnum %d size %d error %s\n", opnum, i, nt_errstr(status)); 250 } 251 252 printf("opnum %d minimum not found!?\n", opnum); 253 talloc_free(p); 254} 255 256 257static void test_auto_scan(struct torture_context *tctx, const struct ndr_interface_table *iface) 258{ 259 test_scan_call(tctx, iface, 2); 260} 261 262bool torture_rpc_autoidl(struct torture_context *torture) 263{ 264 const struct ndr_interface_table *iface; 265 266 iface = ndr_table_by_name("drsuapi"); 267 if (!iface) { 268 printf("Unknown interface!\n"); 269 return false; 270 } 271 272 printf("\nProbing pipe '%s'\n", iface->name); 273 274 test_auto_scan(torture, iface); 275 276 return true; 277} 278