1/* 2 Unix SMB/CIFS implementation. 3 4 helper functions for SMB2 test suite 5 6 Copyright (C) Andrew Tridgell 2005 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 "libcli/smb2/smb2.h" 24#include "libcli/smb2/smb2_calls.h" 25#include "libcli/smb_composite/smb_composite.h" 26#include "lib/cmdline/popt_common.h" 27#include "lib/events/events.h" 28#include "system/time.h" 29#include "librpc/gen_ndr/ndr_security.h" 30#include "param/param.h" 31#include "libcli/resolve/resolve.h" 32 33#include "torture/torture.h" 34#include "torture/smb2/proto.h" 35 36 37/* 38 write to a file on SMB2 39*/ 40NTSTATUS smb2_util_write(struct smb2_tree *tree, 41 struct smb2_handle handle, 42 const void *buf, off_t offset, size_t size) 43{ 44 struct smb2_write w; 45 46 ZERO_STRUCT(w); 47 w.in.file.handle = handle; 48 w.in.offset = offset; 49 w.in.data = data_blob_const(buf, size); 50 51 return smb2_write(tree, &w); 52} 53 54/* 55 create a complex file/dir using the SMB2 protocol 56*/ 57static NTSTATUS smb2_create_complex(struct smb2_tree *tree, const char *fname, 58 struct smb2_handle *handle, bool dir) 59{ 60 TALLOC_CTX *tmp_ctx = talloc_new(tree); 61 char buf[7] = "abc"; 62 struct smb2_create io; 63 union smb_setfileinfo setfile; 64 union smb_fileinfo fileinfo; 65 time_t t = (time(NULL) & ~1); 66 NTSTATUS status; 67 68 smb2_util_unlink(tree, fname); 69 ZERO_STRUCT(io); 70 io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; 71 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; 72 io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; 73 io.in.share_access = 74 NTCREATEX_SHARE_ACCESS_DELETE| 75 NTCREATEX_SHARE_ACCESS_READ| 76 NTCREATEX_SHARE_ACCESS_WRITE; 77 io.in.create_options = 0; 78 io.in.fname = fname; 79 if (dir) { 80 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; 81 io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE; 82 io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; 83 io.in.create_disposition = NTCREATEX_DISP_CREATE; 84 } 85 86 /* it seems vista is now fussier about alignment? */ 87 if (strchr(fname, ':') == NULL) { 88 /* setup some EAs */ 89 io.in.eas.num_eas = 2; 90 io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2); 91 io.in.eas.eas[0].flags = 0; 92 io.in.eas.eas[0].name.s = "EAONE"; 93 io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6); 94 io.in.eas.eas[1].flags = 0; 95 io.in.eas.eas[1].name.s = "SECONDEA"; 96 io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8); 97 } 98 99 status = smb2_create(tree, tmp_ctx, &io); 100 talloc_free(tmp_ctx); 101 NT_STATUS_NOT_OK_RETURN(status); 102 103 *handle = io.out.file.handle; 104 105 if (!dir) { 106 status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf)); 107 NT_STATUS_NOT_OK_RETURN(status); 108 } 109 110 /* make sure all the timestamps aren't the same, and are also 111 in different DST zones*/ 112 setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; 113 setfile.generic.in.file.handle = *handle; 114 115 unix_to_nt_time(&setfile.basic_info.in.create_time, t + 9*30*24*60*60); 116 unix_to_nt_time(&setfile.basic_info.in.access_time, t + 6*30*24*60*60); 117 unix_to_nt_time(&setfile.basic_info.in.write_time, t + 3*30*24*60*60); 118 unix_to_nt_time(&setfile.basic_info.in.change_time, t + 1*30*24*60*60); 119 setfile.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; 120 121 status = smb2_setinfo_file(tree, &setfile); 122 if (!NT_STATUS_IS_OK(status)) { 123 printf("Failed to setup file times - %s\n", nt_errstr(status)); 124 return status; 125 } 126 127 /* make sure all the timestamps aren't the same */ 128 fileinfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION; 129 fileinfo.generic.in.file.handle = *handle; 130 131 status = smb2_getinfo_file(tree, tree, &fileinfo); 132 if (!NT_STATUS_IS_OK(status)) { 133 printf("Failed to query file times - %s\n", nt_errstr(status)); 134 return status; 135 136 } 137 138#define CHECK_TIME(field) do {\ 139 if (setfile.basic_info.in.field != fileinfo.all_info2.out.field) { \ 140 printf("(%s) " #field " not setup correctly: %s(%llu) => %s(%llu)\n", \ 141 __location__, \ 142 nt_time_string(tree, setfile.basic_info.in.field), \ 143 (unsigned long long)setfile.basic_info.in.field, \ 144 nt_time_string(tree, fileinfo.basic_info.out.field), \ 145 (unsigned long long)fileinfo.basic_info.out.field); \ 146 status = NT_STATUS_INVALID_PARAMETER; \ 147 } \ 148} while (0) 149 150 CHECK_TIME(create_time); 151 CHECK_TIME(access_time); 152 CHECK_TIME(write_time); 153 CHECK_TIME(change_time); 154 155 return status; 156} 157 158/* 159 create a complex file using the SMB2 protocol 160*/ 161NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, 162 struct smb2_handle *handle) 163{ 164 return smb2_create_complex(tree, fname, handle, false); 165} 166 167/* 168 create a complex dir using the SMB2 protocol 169*/ 170NTSTATUS smb2_create_complex_dir(struct smb2_tree *tree, const char *fname, 171 struct smb2_handle *handle) 172{ 173 return smb2_create_complex(tree, fname, handle, true); 174} 175 176/* 177 show lots of information about a file 178*/ 179void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle) 180{ 181 NTSTATUS status; 182 TALLOC_CTX *tmp_ctx = talloc_new(tree); 183 union smb_fileinfo io; 184 185 io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION; 186 io.generic.in.file.handle = handle; 187 188 status = smb2_getinfo_file(tree, tmp_ctx, &io); 189 if (!NT_STATUS_IS_OK(status)) { 190 DEBUG(0,("getinfo failed - %s\n", nt_errstr(status))); 191 talloc_free(tmp_ctx); 192 return; 193 } 194 195 d_printf("all_info for '%s'\n", io.all_info2.out.fname.s); 196 d_printf("\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time)); 197 d_printf("\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time)); 198 d_printf("\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time)); 199 d_printf("\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time)); 200 d_printf("\tattrib: 0x%x\n", io.all_info2.out.attrib); 201 d_printf("\tunknown1: 0x%x\n", io.all_info2.out.unknown1); 202 d_printf("\talloc_size: %llu\n", (long long)io.all_info2.out.alloc_size); 203 d_printf("\tsize: %llu\n", (long long)io.all_info2.out.size); 204 d_printf("\tnlink: %u\n", io.all_info2.out.nlink); 205 d_printf("\tdelete_pending: %u\n", io.all_info2.out.delete_pending); 206 d_printf("\tdirectory: %u\n", io.all_info2.out.directory); 207 d_printf("\tfile_id: %llu\n", (long long)io.all_info2.out.file_id); 208 d_printf("\tea_size: %u\n", io.all_info2.out.ea_size); 209 d_printf("\taccess_mask: 0x%08x\n", io.all_info2.out.access_mask); 210 d_printf("\tposition: 0x%llx\n", (long long)io.all_info2.out.position); 211 d_printf("\tmode: 0x%llx\n", (long long)io.all_info2.out.mode); 212 213 /* short name, if any */ 214 io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION; 215 status = smb2_getinfo_file(tree, tmp_ctx, &io); 216 if (NT_STATUS_IS_OK(status)) { 217 d_printf("\tshort name: '%s'\n", io.alt_name_info.out.fname.s); 218 } 219 220 /* the EAs, if any */ 221 io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS; 222 status = smb2_getinfo_file(tree, tmp_ctx, &io); 223 if (NT_STATUS_IS_OK(status)) { 224 int i; 225 for (i=0;i<io.all_eas.out.num_eas;i++) { 226 d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i, 227 io.all_eas.out.eas[i].flags, 228 (int)io.all_eas.out.eas[i].value.length, 229 io.all_eas.out.eas[i].name.s); 230 } 231 } 232 233 /* streams, if available */ 234 io.generic.level = RAW_FILEINFO_STREAM_INFORMATION; 235 status = smb2_getinfo_file(tree, tmp_ctx, &io); 236 if (NT_STATUS_IS_OK(status)) { 237 int i; 238 for (i=0;i<io.stream_info.out.num_streams;i++) { 239 d_printf("\tstream %d:\n", i); 240 d_printf("\t\tsize %ld\n", 241 (long)io.stream_info.out.streams[i].size); 242 d_printf("\t\talloc size %ld\n", 243 (long)io.stream_info.out.streams[i].alloc_size); 244 d_printf("\t\tname %s\n", io.stream_info.out.streams[i].stream_name.s); 245 } 246 } 247 248 if (DEBUGLVL(1)) { 249 /* the security descriptor */ 250 io.query_secdesc.level = RAW_FILEINFO_SEC_DESC; 251 io.query_secdesc.in.secinfo_flags = 252 SECINFO_OWNER|SECINFO_GROUP| 253 SECINFO_DACL; 254 status = smb2_getinfo_file(tree, tmp_ctx, &io); 255 if (NT_STATUS_IS_OK(status)) { 256 NDR_PRINT_DEBUG(security_descriptor, io.query_secdesc.out.sd); 257 } 258 } 259 260 talloc_free(tmp_ctx); 261} 262 263 264/* 265 open a smb2 connection 266*/ 267bool torture_smb2_connection(struct torture_context *tctx, struct smb2_tree **tree) 268{ 269 NTSTATUS status; 270 const char *host = torture_setting_string(tctx, "host", NULL); 271 const char *share = torture_setting_string(tctx, "share", NULL); 272 struct cli_credentials *credentials = cmdline_credentials; 273 struct smbcli_options options; 274 275 lp_smbcli_options(tctx->lp_ctx, &options); 276 277 status = smb2_connect(tctx, host, 278 lp_smb_ports(tctx->lp_ctx), 279 share, 280 lp_resolve_context(tctx->lp_ctx), 281 credentials, tree, 282 tctx->ev, &options, 283 lp_socket_options(tctx->lp_ctx), 284 lp_gensec_settings(tctx, tctx->lp_ctx) 285 ); 286 if (!NT_STATUS_IS_OK(status)) { 287 printf("Failed to connect to SMB2 share \\\\%s\\%s - %s\n", 288 host, share, nt_errstr(status)); 289 return false; 290 } 291 return true; 292} 293 294 295/* 296 create and return a handle to a test file 297*/ 298NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname, 299 struct smb2_handle *handle) 300{ 301 struct smb2_create io; 302 struct smb2_read r; 303 NTSTATUS status; 304 305 ZERO_STRUCT(io); 306 io.in.oplock_level = 0; 307 io.in.desired_access = SEC_RIGHTS_FILE_ALL; 308 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; 309 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; 310 io.in.share_access = 311 NTCREATEX_SHARE_ACCESS_DELETE| 312 NTCREATEX_SHARE_ACCESS_READ| 313 NTCREATEX_SHARE_ACCESS_WRITE; 314 io.in.create_options = 0; 315 io.in.fname = fname; 316 317 status = smb2_create(tree, tree, &io); 318 NT_STATUS_NOT_OK_RETURN(status); 319 320 *handle = io.out.file.handle; 321 322 ZERO_STRUCT(r); 323 r.in.file.handle = *handle; 324 r.in.length = 5; 325 r.in.offset = 0; 326 327 smb2_read(tree, tree, &r); 328 329 return NT_STATUS_OK; 330} 331 332/* 333 create and return a handle to a test directory 334*/ 335NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname, 336 struct smb2_handle *handle) 337{ 338 struct smb2_create io; 339 NTSTATUS status; 340 341 ZERO_STRUCT(io); 342 io.in.oplock_level = 0; 343 io.in.desired_access = SEC_RIGHTS_DIR_ALL; 344 io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; 345 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; 346 io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE; 347 io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; 348 io.in.fname = fname; 349 350 status = smb2_create(tree, tree, &io); 351 NT_STATUS_NOT_OK_RETURN(status); 352 353 *handle = io.out.file.handle; 354 355 return NT_STATUS_OK; 356} 357 358 359/* 360 create a complex file using the old SMB protocol, to make it easier to 361 find fields in SMB2 getinfo levels 362*/ 363NTSTATUS torture_setup_complex_file(struct smb2_tree *tree, const char *fname) 364{ 365 struct smb2_handle handle; 366 NTSTATUS status = smb2_create_complex_file(tree, fname, &handle); 367 NT_STATUS_NOT_OK_RETURN(status); 368 return smb2_util_close(tree, handle); 369} 370 371 372/* 373 create a complex dir using the old SMB protocol, to make it easier to 374 find fields in SMB2 getinfo levels 375*/ 376NTSTATUS torture_setup_complex_dir(struct smb2_tree *tree, const char *fname) 377{ 378 struct smb2_handle handle; 379 NTSTATUS status = smb2_create_complex_dir(tree, fname, &handle); 380 NT_STATUS_NOT_OK_RETURN(status); 381 return smb2_util_close(tree, handle); 382} 383 384 385/* 386 return a handle to the root of the share 387*/ 388NTSTATUS smb2_util_roothandle(struct smb2_tree *tree, struct smb2_handle *handle) 389{ 390 struct smb2_create io; 391 NTSTATUS status; 392 393 ZERO_STRUCT(io); 394 io.in.oplock_level = 0; 395 io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST; 396 io.in.file_attributes = 0; 397 io.in.create_disposition = NTCREATEX_DISP_OPEN; 398 io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_DELETE; 399 io.in.create_options = NTCREATEX_OPTIONS_ASYNC_ALERT; 400 io.in.fname = NULL; 401 402 status = smb2_create(tree, tree, &io); 403 NT_STATUS_NOT_OK_RETURN(status); 404 405 *handle = io.out.file.handle; 406 407 return NT_STATUS_OK; 408} 409