diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/include/smb_interfaces.h | 57 | ||||
-rw-r--r-- | source4/include/trans2.h | 1 | ||||
-rw-r--r-- | source4/libcli/raw/rawfileinfo.c | 64 | ||||
-rw-r--r-- | source4/libcli/smb2/getinfo.c | 257 | ||||
-rw-r--r-- | source4/libcli/smb2/smb2_calls.h | 144 | ||||
-rw-r--r-- | source4/torture/smb2/getinfo.c | 157 | ||||
-rw-r--r-- | source4/torture/smb2/util.c | 73 |
7 files changed, 324 insertions, 429 deletions
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h index f078134194..c6635251a2 100644 --- a/source4/include/smb_interfaces.h +++ b/source4/include/smb_interfaces.h @@ -315,7 +315,6 @@ enum smb_fileinfo_level { RAW_FILEINFO_ACCESS_INFORMATION = SMB_QFILEINFO_ACCESS_INFORMATION, RAW_FILEINFO_NAME_INFORMATION = SMB_QFILEINFO_NAME_INFORMATION, RAW_FILEINFO_POSITION_INFORMATION = SMB_QFILEINFO_POSITION_INFORMATION, - RAW_FILEINFO_FULL_EA_INFORMATION = SMB_QFILEINFO_FULL_EA_INFORMATION, RAW_FILEINFO_MODE_INFORMATION = SMB_QFILEINFO_MODE_INFORMATION, RAW_FILEINFO_ALIGNMENT_INFORMATION = SMB_QFILEINFO_ALIGNMENT_INFORMATION, RAW_FILEINFO_ALL_INFORMATION = SMB_QFILEINFO_ALL_INFORMATION, @@ -323,7 +322,17 @@ enum smb_fileinfo_level { RAW_FILEINFO_STREAM_INFORMATION = SMB_QFILEINFO_STREAM_INFORMATION, RAW_FILEINFO_COMPRESSION_INFORMATION = SMB_QFILEINFO_COMPRESSION_INFORMATION, RAW_FILEINFO_NETWORK_OPEN_INFORMATION = SMB_QFILEINFO_NETWORK_OPEN_INFORMATION, - RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION = SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION + RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION = SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION, + /* SMB2 specific levels */ + RAW_FILEINFO_SMB2_ALL_EAS = 0x0f01, + RAW_FILEINFO_SMB2_ALL_INFORMATION = 0x1201 +}; + +/* + file handles in SMB2 are 16 bytes +*/ +struct smb2_handle { + uint64_t data[2]; }; @@ -335,11 +344,14 @@ union smb_fileinfo { enum smb_fileinfo_level level; /* each level can be called on either a pathname or a - * filename, in either case the return format is - * identical */ + filename, in either case the return format is + identical + On SMB2 a 16 byte handle is used + */ union smb_fileinfo_in { const char *fname; uint16_t fnum; + struct smb2_handle handle; } in; struct { @@ -445,7 +457,7 @@ union smb_fileinfo { } out; } ea_list; - /* trans2 RAW_FILEINFO_ALL_EAS interface */ + /* trans2 RAW_FILEINFO_ALL_EAS and RAW_FILEINFO_FULL_EA_INFORMATION interfaces */ struct { enum smb_fileinfo_level level; union smb_fileinfo_in in; @@ -530,6 +542,33 @@ union smb_fileinfo { } out; } all_info; + /* RAW_FILEINFO_SMB2_ALL_INFORMATION interface */ + struct { + enum smb_fileinfo_level level; + union smb_fileinfo_in in; + + struct { + NTTIME create_time; + NTTIME access_time; + NTTIME write_time; + NTTIME change_time; + uint32_t attrib; + uint32_t unknown1; + uint64_t alloc_size; + uint64_t size; + uint32_t nlink; + uint8_t delete_pending; + uint8_t directory; + /* uint16_t _pad; */ + uint64_t file_id; + uint32_t ea_size; + uint32_t access_mask; + uint64_t unknown2; + uint64_t unknown3; + WIRE_STRING fname; + } out; + } all_info2; + /* RAW_FILEINFO_ALT_NAME_INFO and RAW_FILEINFO_ALT_NAME_INFORMATION interfaces */ struct { enum smb_fileinfo_level level; @@ -917,6 +956,7 @@ union smb_fsinfo { /* generic interface */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { uint32_t block_size; @@ -976,6 +1016,7 @@ union smb_fsinfo { /* TRANS2 RAW_QFS_VOLUME_INFO and RAW_QFS_VOLUME_INFORMATION interfaces */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { NTTIME create_time; @@ -987,6 +1028,7 @@ union smb_fsinfo { /* trans2 RAW_QFS_SIZE_INFO and RAW_QFS_SIZE_INFORMATION interfaces */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { uint64_t total_alloc_units; @@ -999,6 +1041,7 @@ union smb_fsinfo { /* TRANS2 RAW_QFS_DEVICE_INFO and RAW_QFS_DEVICE_INFORMATION interfaces */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { uint32_t device_type; @@ -1010,6 +1053,7 @@ union smb_fsinfo { /* TRANS2 RAW_QFS_ATTRIBUTE_INFO and RAW_QFS_ATTRIBUTE_INFORMATION interfaces */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { uint32_t fs_attr; @@ -1033,6 +1077,7 @@ union smb_fsinfo { /* trans2 RAW_QFS_QUOTA_INFORMATION interface */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { uint64_t unknown[3]; @@ -1045,6 +1090,7 @@ union smb_fsinfo { /* trans2 RAW_QFS_FULL_SIZE_INFORMATION interface */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { uint64_t total_alloc_units; @@ -1058,6 +1104,7 @@ union smb_fsinfo { /* trans2 RAW_QFS_OBJECTID_INFORMATION interface */ struct { enum smb_fsinfo_level level; + struct smb2_handle handle; /* only for smb2 */ struct { struct GUID guid; diff --git a/source4/include/trans2.h b/source4/include/trans2.h index 6768476e1d..a3f6e28a2a 100644 --- a/source4/include/trans2.h +++ b/source4/include/trans2.h @@ -147,7 +147,6 @@ Found 8 aliased levels #define SMB_QFILEINFO_ACCESS_INFORMATION 1008 #define SMB_QFILEINFO_NAME_INFORMATION 1009 #define SMB_QFILEINFO_POSITION_INFORMATION 1014 -#define SMB_QFILEINFO_FULL_EA_INFORMATION 1015 /* only on SMB2 */ #define SMB_QFILEINFO_MODE_INFORMATION 1016 #define SMB_QFILEINFO_ALIGNMENT_INFORMATION 1017 #define SMB_QFILEINFO_ALL_INFORMATION 1018 diff --git a/source4/libcli/raw/rawfileinfo.c b/source4/libcli/raw/rawfileinfo.c index 2edb6d5b42..7119eed5e7 100644 --- a/source4/libcli/raw/rawfileinfo.c +++ b/source4/libcli/raw/rawfileinfo.c @@ -176,12 +176,6 @@ NTSTATUS smb_raw_fileinfo_passthru_parse(const DATA_BLOB *blob, TALLOC_CTX *mem_ parms->position_information.out.position = BVAL(blob->data, 0); return NT_STATUS_OK; - case RAW_FILEINFO_FULL_EA_INFORMATION: - FINFO_CHECK_MIN_SIZE(4); - return ea_pull_list_chained(blob, mem_ctx, - &parms->all_eas.out.num_eas, - &parms->all_eas.out.eas); - case RAW_FILEINFO_MODE_INFORMATION: FINFO_CHECK_SIZE(4); parms->mode_information.out.mode = IVAL(blob->data, 0); @@ -220,6 +214,51 @@ NTSTATUS smb_raw_fileinfo_passthru_parse(const DATA_BLOB *blob, TALLOC_CTX *mem_ parms->attribute_tag_information.out.reparse_tag = IVAL(blob->data, 4); return NT_STATUS_OK; + case RAW_FILEINFO_SMB2_ALL_EAS: + FINFO_CHECK_MIN_SIZE(4); + return ea_pull_list_chained(blob, mem_ctx, + &parms->all_eas.out.num_eas, + &parms->all_eas.out.eas); + + case RAW_FILEINFO_SMB2_ALL_INFORMATION: + FINFO_CHECK_MIN_SIZE(0x64); + parms->all_info2.out.create_time = smbcli_pull_nttime(blob->data, 0x00); + parms->all_info2.out.access_time = smbcli_pull_nttime(blob->data, 0x08); + parms->all_info2.out.write_time = smbcli_pull_nttime(blob->data, 0x10); + parms->all_info2.out.change_time = smbcli_pull_nttime(blob->data, 0x18); + parms->all_info2.out.attrib = IVAL(blob->data, 0x20); + parms->all_info2.out.unknown1 = IVAL(blob->data, 0x24); + parms->all_info2.out.alloc_size = BVAL(blob->data, 0x28); + parms->all_info2.out.size = BVAL(blob->data, 0x30); + parms->all_info2.out.nlink = IVAL(blob->data, 0x38); + parms->all_info2.out.delete_pending = CVAL(blob->data, 0x3C); + parms->all_info2.out.directory = CVAL(blob->data, 0x3D); + parms->all_info2.out.file_id = BVAL(blob->data, 0x40); + parms->all_info2.out.ea_size = IVAL(blob->data, 0x48); + parms->all_info2.out.access_mask = IVAL(blob->data, 0x4C); + parms->all_info2.out.unknown2 = BVAL(blob->data, 0x50); + parms->all_info2.out.unknown3 = BVAL(blob->data, 0x58); + smbcli_blob_pull_string(NULL, mem_ctx, blob, + &parms->all_info2.out.fname, 0x60, 0x64, STR_UNICODE); + return NT_STATUS_OK; + + case RAW_FILEINFO_SEC_DESC: { + struct ndr_pull *ndr; + NTSTATUS status; + ndr = ndr_pull_init_blob(blob, mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + parms->query_secdesc.out.sd = talloc(mem_ctx, struct security_descriptor); + if (parms->query_secdesc.out.sd == NULL) { + return NT_STATUS_NO_MEMORY; + } + status = ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, + parms->query_secdesc.out.sd); + talloc_free(ndr); + return status; + } + default: break; } @@ -335,10 +374,6 @@ static NTSTATUS smb_raw_info_backend(struct smbcli_session *session, return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, RAW_FILEINFO_POSITION_INFORMATION, parms); - case RAW_FILEINFO_FULL_EA_INFORMATION: - return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, - RAW_FILEINFO_FULL_EA_INFORMATION, parms); - case RAW_FILEINFO_MODE_INFORMATION: return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, RAW_FILEINFO_MODE_INFORMATION, parms); @@ -381,6 +416,15 @@ static NTSTATUS smb_raw_info_backend(struct smbcli_session *session, case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION: return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION, parms); + + case RAW_FILEINFO_SMB2_ALL_INFORMATION: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_SMB2_ALL_INFORMATION, parms); + + case RAW_FILEINFO_SMB2_ALL_EAS: + return smb_raw_fileinfo_passthru_parse(blob, mem_ctx, + RAW_FILEINFO_SMB2_ALL_EAS, parms); + } return NT_STATUS_INVALID_LEVEL; diff --git a/source4/libcli/smb2/getinfo.c b/source4/libcli/smb2/getinfo.c index fe27cc711b..cb8ce76a07 100644 --- a/source4/libcli/smb2/getinfo.c +++ b/source4/libcli/smb2/getinfo.c @@ -41,8 +41,8 @@ struct smb2_request *smb2_getinfo_send(struct smb2_tree *tree, struct smb2_getin SSVAL(req->out.body, 0x02, io->in.level); SIVAL(req->out.body, 0x04, io->in.max_response_size); SIVAL(req->out.body, 0x08, io->in.unknown1); - SIVAL(req->out.body, 0x0C, io->in.flags); - SIVAL(req->out.body, 0x10, io->in.unknown3); + SIVAL(req->out.body, 0x0C, io->in.unknown2); + SIVAL(req->out.body, 0x10, io->in.flags); SIVAL(req->out.body, 0x14, io->in.unknown4); smb2_push_handle(req->out.body+0x18, &io->in.handle); @@ -87,203 +87,64 @@ NTSTATUS smb2_getinfo(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, /* - parse a returned getinfo data blob + recv a getinfo reply and parse the level info */ -NTSTATUS smb2_getinfo_parse(TALLOC_CTX *mem_ctx, - uint16_t level, - DATA_BLOB blob, - union smb2_fileinfo *io) +NTSTATUS smb2_getinfo_file_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, + union smb_fileinfo *io) { - switch (level) { - case SMB2_GETINFO_FILE_BASIC_INFO: - if (blob.length != 0x28) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->basic_info.create_time = smbcli_pull_nttime(blob.data, 0x00); - io->basic_info.access_time = smbcli_pull_nttime(blob.data, 0x08); - io->basic_info.write_time = smbcli_pull_nttime(blob.data, 0x10); - io->basic_info.change_time = smbcli_pull_nttime(blob.data, 0x18); - io->basic_info.file_attr = IVAL(blob.data, 0x20); - io->basic_info.unknown = IVAL(blob.data, 0x24); - break; - - case SMB2_GETINFO_FILE_SIZE_INFO: - if (blob.length != 0x18) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->size_info.alloc_size = BVAL(blob.data, 0x00); - io->size_info.size = BVAL(blob.data, 0x08); - io->size_info.nlink = IVAL(blob.data, 0x10); - io->size_info.delete_pending = CVAL(blob.data, 0x14); - io->size_info.directory = CVAL(blob.data, 0x15); - break; - - case SMB2_GETINFO_FILE_ID: - if (blob.length != 0x8) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->file_id.file_id = BVAL(blob.data, 0x00); - break; - - case SMB2_GETINFO_FILE_EA_SIZE: - if (blob.length != 0x4) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->ea_size.ea_size = IVAL(blob.data, 0x00); - break; - - case SMB2_GETINFO_FILE_ACCESS_INFO: - if (blob.length != 0x4) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->access_info.access_mask = IVAL(blob.data, 0x00); - break; - - case SMB2_GETINFO_FILE_0E: - if (blob.length != 0x8) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->unknown0e.unknown1 = IVAL(blob.data, 0x00); - io->unknown0e.unknown2 = IVAL(blob.data, 0x04); - break; - - case SMB2_GETINFO_FILE_ALL_EAS: - return ea_pull_list_chained(&blob, mem_ctx, - &io->all_eas.num_eas, - &io->all_eas.eas); - - case SMB2_GETINFO_FILE_10: - if (blob.length != 0x4) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->unknown10.unknown = IVAL(blob.data, 0x00); - break; - - case SMB2_GETINFO_FILE_11: - if (blob.length != 0x4) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->unknown11.unknown = IVAL(blob.data, 0x00); - break; - - case SMB2_GETINFO_FILE_ALL_INFO: { - uint32_t nlen; - ssize_t size; - void *vstr; - if (blob.length < 0x64) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->all_info.create_time = smbcli_pull_nttime(blob.data, 0x00); - io->all_info.access_time = smbcli_pull_nttime(blob.data, 0x08); - io->all_info.write_time = smbcli_pull_nttime(blob.data, 0x10); - io->all_info.change_time = smbcli_pull_nttime(blob.data, 0x18); - io->all_info.file_attr = IVAL(blob.data, 0x20); - io->all_info.unknown1 = IVAL(blob.data, 0x24); - io->all_info.alloc_size = BVAL(blob.data, 0x28); - io->all_info.size = BVAL(blob.data, 0x30); - io->all_info.nlink = IVAL(blob.data, 0x38); - io->all_info.delete_pending = CVAL(blob.data, 0x3C); - io->all_info.directory = CVAL(blob.data, 0x3D); - io->all_info.file_id = BVAL(blob.data, 0x40); - io->all_info.ea_size = IVAL(blob.data, 0x48); - io->all_info.access_mask = IVAL(blob.data, 0x4C); - io->all_info.unknown5 = BVAL(blob.data, 0x50); - io->all_info.unknown6 = BVAL(blob.data, 0x58); - nlen = IVAL(blob.data, 0x60); - if (nlen > blob.length - 0x64) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, - blob.data+0x64, nlen, &vstr); - if (size == -1) { - return NT_STATUS_ILLEGAL_CHARACTER; - } - io->all_info.fname = vstr; - break; - } + struct smb2_getinfo b; + NTSTATUS status; - case SMB2_GETINFO_FILE_SHORT_INFO: { - uint32_t nlen; - ssize_t size; - void *vstr; - if (blob.length < 0x04) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - nlen = IVAL(blob.data, 0x00); - if (nlen > blob.length - 0x04) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, - blob.data+0x04, nlen, &vstr); - if (size == -1) { - return NT_STATUS_ILLEGAL_CHARACTER; - } - io->short_info.short_name = vstr; - break; - } + status = smb2_getinfo_recv(req, mem_ctx, &b); + NT_STATUS_NOT_OK_RETURN(status); - case SMB2_GETINFO_FILE_STREAM_INFO: - return smbcli_parse_stream_info(blob, mem_ctx, &io->stream_info); - - case SMB2_GETINFO_FILE_EOF_INFO: - if (blob.length != 0x10) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->eof_info.size = BVAL(blob.data, 0x00); - io->eof_info.unknown = BVAL(blob.data, 0x08); - break; - - case SMB2_GETINFO_FILE_STANDARD_INFO: - if (blob.length != 0x38) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->standard_info.create_time = smbcli_pull_nttime(blob.data, 0x00); - io->standard_info.access_time = smbcli_pull_nttime(blob.data, 0x08); - io->standard_info.write_time = smbcli_pull_nttime(blob.data, 0x10); - io->standard_info.change_time = smbcli_pull_nttime(blob.data, 0x18); - io->standard_info.alloc_size = BVAL(blob.data, 0x20); - io->standard_info.size = BVAL(blob.data, 0x28); - io->standard_info.file_attr = IVAL(blob.data, 0x30); - io->standard_info.unknown = IVAL(blob.data, 0x34); - break; - - case SMB2_GETINFO_FILE_ATTRIB_INFO: - if (blob.length != 0x08) { - return NT_STATUS_INFO_LENGTH_MISMATCH; - } - io->attrib_info.file_attr = IVAL(blob.data, 0x00); - io->attrib_info.unknown = IVAL(blob.data, 0x04); - break; - - case SMB2_GETINFO_SECURITY: { - struct ndr_pull *ndr; - NTSTATUS status; - ndr = ndr_pull_init_blob(&blob, mem_ctx); - if (!ndr) { - return NT_STATUS_NO_MEMORY; - } - io->security.sd = talloc(mem_ctx, struct security_descriptor); - if (io->security.sd == NULL) { - return NT_STATUS_NO_MEMORY; - } - status = ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, io->security.sd); - talloc_free(ndr); - return status; + status = smb_raw_fileinfo_passthru_parse(&b.out.blob, mem_ctx, io->generic.level, io); + data_blob_free(&b.out.blob); + + return status; +} + +/* + level specific getinfo call +*/ +NTSTATUS smb2_getinfo_file(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, + union smb_fileinfo *io) +{ + struct smb2_getinfo b; + struct smb2_request *req; + uint16_t smb2_level; + + if (io->generic.level == RAW_FILEINFO_SEC_DESC) { + smb2_level = SMB2_GETINFO_SECURITY; + } else if ((io->generic.level & 0xFF) == SMB2_GETINFO_FILE) { + smb2_level = io->generic.level; + } else if (io->generic.level > 1000) { + smb2_level = ((io->generic.level-1000)<<8) | SMB2_GETINFO_FILE; + } else { + /* SMB2 only does the passthru levels */ + return NT_STATUS_INVALID_LEVEL; } - - default: - return NT_STATUS_INVALID_INFO_CLASS; + + ZERO_STRUCT(b); + b.in.max_response_size = 0x10000; + b.in.handle = io->generic.in.handle; + b.in.level = smb2_level; + + if (io->generic.level == RAW_FILEINFO_SEC_DESC) { + b.in.flags = io->query_secdesc.secinfo_flags; } - return NT_STATUS_OK; + req = smb2_getinfo_send(tree, &b); + + return smb2_getinfo_file_recv(req, mem_ctx, io); } /* recv a getinfo reply and parse the level info */ -NTSTATUS smb2_getinfo_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, - uint16_t level, union smb2_fileinfo *io) +NTSTATUS smb2_getinfo_fs_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, + union smb_fsinfo *io) { struct smb2_getinfo b; NTSTATUS status; @@ -291,7 +152,7 @@ NTSTATUS smb2_getinfo_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, status = smb2_getinfo_recv(req, mem_ctx, &b); NT_STATUS_NOT_OK_RETURN(status); - status = smb2_getinfo_parse(mem_ctx, level, b.out.blob, io); + status = smb_raw_fsinfo_passthru_parse(b.out.blob, mem_ctx, io->generic.level, io); data_blob_free(&b.out.blob); return status; @@ -300,19 +161,29 @@ NTSTATUS smb2_getinfo_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, /* level specific getinfo call */ -NTSTATUS smb2_getinfo_level(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, - struct smb2_handle handle, - uint16_t level, union smb2_fileinfo *io) +NTSTATUS smb2_getinfo_fs(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, + union smb_fsinfo *io) { struct smb2_getinfo b; struct smb2_request *req; + uint16_t smb2_level; + + if ((io->generic.level & 0xFF) == SMB2_GETINFO_FS) { + smb2_level = io->generic.level; + } else if (io->generic.level > 1000) { + smb2_level = ((io->generic.level-1000)<<8) | SMB2_GETINFO_FS; + } else { + /* SMB2 only does the passthru levels */ + return NT_STATUS_INVALID_LEVEL; + } ZERO_STRUCT(b); b.in.max_response_size = 0x10000; - b.in.handle = handle; - b.in.level = level; + b.in.handle = io->generic.handle; + b.in.level = smb2_level; req = smb2_getinfo_send(tree, &b); - return smb2_getinfo_level_recv(req, mem_ctx, level, io); + return smb2_getinfo_fs_recv(req, mem_ctx, io); } + diff --git a/source4/libcli/smb2/smb2_calls.h b/source4/libcli/smb2/smb2_calls.h index 872e20f156..3ccb5309e5 100644 --- a/source4/libcli/smb2/smb2_calls.h +++ b/source4/libcli/smb2/smb2_calls.h @@ -103,14 +103,6 @@ struct smb2_tree_connect { } out; }; -/* - file handles in SMB2 are 16 bytes -*/ -struct smb2_handle { - uint64_t data[2]; -}; - - #define SMB2_CREATE_FLAG_REQUEST_OPLOCK 0x0100 #define SMB2_CREATE_FLAG_REQUEST_EXCLUSIVE_OPLOCK 0x0800 #define SMB2_CREATE_FLAG_GRANT_OPLOCK 0x0001 @@ -190,35 +182,14 @@ struct smb2_close { } out; }; -/* fs information levels */ -#define SMB2_GETINFO_FS_VOLUME_INFO 0x0102 -#define SMB2_GETINFO_FS_SIZE_INFO 0x0302 -#define SMB2_GETINFO_FS_DEVICE_INFO 0x0402 -#define SMB2_GETINFO_FS_ATTRIBUTE_INFO 0x0502 -#define SMB2_GETINFO_FS_QUOTA_INFO 0x0602 -#define SMB2_GETINFO_FS_FULL_SIZE_INFO 0x0702 -#define SMB2_GETINFO_FS_OBJECTID_INFO 0x0802 - -/* class 3 levels */ -#define SMB2_GETINFO_SECURITY 0x0003 - -/* file information levels */ -#define SMB2_GETINFO_FILE_BASIC_INFO 0x0401 -#define SMB2_GETINFO_FILE_SIZE_INFO 0x0501 -#define SMB2_GETINFO_FILE_ID 0x0601 -#define SMB2_GETINFO_FILE_EA_SIZE 0x0701 -#define SMB2_GETINFO_FILE_ACCESS_INFO 0x0801 -#define SMB2_GETINFO_FILE_0E 0x0e01 -#define SMB2_GETINFO_FILE_ALL_EAS 0x0f01 -#define SMB2_GETINFO_FILE_10 0x1001 -#define SMB2_GETINFO_FILE_11 0x1101 -#define SMB2_GETINFO_FILE_ALL_INFO 0x1201 -#define SMB2_GETINFO_FILE_SHORT_INFO 0x1501 -#define SMB2_GETINFO_FILE_STREAM_INFO 0x1601 -#define SMB2_GETINFO_FILE_EOF_INFO 0x1c01 -#define SMB2_GETINFO_FILE_STANDARD_INFO 0x2201 -#define SMB2_GETINFO_FILE_ATTRIB_INFO 0x2301 +/* getinfo classes */ +#define SMB2_GETINFO_FILE 0x01 +#define SMB2_GETINFO_FS 0x02 +#define SMB2_GETINFO_SECURITY 0x03 +/* NOTE! the getinfo fs and file levels exactly match up with the + 'passthru' SMB levels, which are levels >= 1000. The SMB2 client + lib uses the names from the libcli/raw/ library */ struct smb2_getinfo { struct { @@ -227,8 +198,8 @@ struct smb2_getinfo { uint16_t level; uint32_t max_response_size; uint32_t unknown1; + uint32_t unknown2; uint32_t flags; /* level specific */ - uint32_t unknown3; uint32_t unknown4; struct smb2_handle handle; } in; @@ -244,105 +215,6 @@ struct smb2_getinfo { } out; }; -union smb2_fileinfo { - struct { - NTTIME create_time; - NTTIME access_time; - NTTIME write_time; - NTTIME change_time; - uint32_t file_attr; - uint32_t unknown; - } basic_info; - - struct { - uint64_t alloc_size; - uint64_t size; - uint32_t nlink; - uint8_t delete_pending; - uint8_t directory; - } size_info; - - struct { - uint64_t file_id; - } file_id; - - struct { - uint32_t ea_size; - } ea_size; - - struct { - uint32_t access_mask; - } access_info; - - struct { - uint32_t unknown1; - uint32_t unknown2; - } unknown0e; - - struct smb_ea_list all_eas; - - struct { - uint32_t unknown; - } unknown10; - - struct { - uint32_t unknown; - } unknown11; - - struct { - NTTIME create_time; - NTTIME access_time; - NTTIME write_time; - NTTIME change_time; - uint32_t file_attr; - uint32_t unknown1; - uint64_t alloc_size; - uint64_t size; - uint32_t nlink; - uint8_t delete_pending; - uint8_t directory; - /* uint16_t _pad; */ - uint64_t file_id; - uint32_t ea_size; - uint32_t access_mask; - uint64_t unknown5; - uint64_t unknown6; - const char *fname; - } all_info; - - struct { - const char *short_name; - } short_info; - - struct stream_information stream_info; - - struct { - uint64_t size; - uint64_t unknown; - } eof_info; - - struct { - NTTIME create_time; - NTTIME access_time; - NTTIME write_time; - NTTIME change_time; - uint64_t alloc_size; - uint64_t size; - uint32_t file_attr; - uint32_t unknown; - } standard_info; - - struct { - uint32_t file_attr; - uint32_t unknown; - } attrib_info; - - struct { - struct security_descriptor *sd; - } security; -}; - - struct smb2_write { struct { /* static body buffer 48 (0x30) bytes */ diff --git a/source4/torture/smb2/getinfo.c b/source4/torture/smb2/getinfo.c index f175b19f89..327ca8a12b 100644 --- a/source4/torture/smb2/getinfo.c +++ b/source4/torture/smb2/getinfo.c @@ -23,63 +23,63 @@ #include "includes.h" #include "libcli/smb2/smb2.h" #include "libcli/smb2/smb2_calls.h" +#include "librpc/gen_ndr/security.h" static struct { const char *name; uint16_t level; NTSTATUS fstatus; NTSTATUS dstatus; - union smb2_fileinfo finfo; - union smb2_fileinfo dinfo; -} levels[] = { + union smb_fileinfo finfo; + union smb_fileinfo dinfo; +} file_levels[] = { #define LEVEL(x) #x, x - { LEVEL(SMB2_GETINFO_FS_VOLUME_INFO) }, - { LEVEL(SMB2_GETINFO_FS_SIZE_INFO) }, - { LEVEL(SMB2_GETINFO_FS_DEVICE_INFO) }, - { LEVEL(SMB2_GETINFO_FS_ATTRIBUTE_INFO) }, - { LEVEL(SMB2_GETINFO_FS_QUOTA_INFO) }, - { LEVEL(SMB2_GETINFO_FS_FULL_SIZE_INFO) }, - { LEVEL(SMB2_GETINFO_FS_OBJECTID_INFO) }, - { LEVEL(SMB2_GETINFO_SECURITY) }, - { LEVEL(SMB2_GETINFO_FILE_BASIC_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_SIZE_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_ID) }, - { LEVEL(SMB2_GETINFO_FILE_EA_SIZE) }, - { LEVEL(SMB2_GETINFO_FILE_ACCESS_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_0E) }, - { LEVEL(SMB2_GETINFO_FILE_ALL_EAS) }, - { LEVEL(SMB2_GETINFO_FILE_10) }, - { LEVEL(SMB2_GETINFO_FILE_11) }, - { LEVEL(SMB2_GETINFO_FILE_ALL_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_SHORT_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_STREAM_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_EOF_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_STANDARD_INFO) }, - { LEVEL(SMB2_GETINFO_FILE_ATTRIB_INFO) } + { LEVEL(RAW_FILEINFO_BASIC_INFORMATION) }, + { LEVEL(RAW_FILEINFO_STANDARD_INFORMATION) }, + { LEVEL(RAW_FILEINFO_INTERNAL_INFORMATION) }, + { LEVEL(RAW_FILEINFO_EA_INFORMATION) }, + { LEVEL(RAW_FILEINFO_ACCESS_INFORMATION) }, + { LEVEL(RAW_FILEINFO_POSITION_INFORMATION) }, + { LEVEL(RAW_FILEINFO_MODE_INFORMATION) }, + { LEVEL(RAW_FILEINFO_ALIGNMENT_INFORMATION) }, + { LEVEL(RAW_FILEINFO_ALL_INFORMATION) }, + { LEVEL(RAW_FILEINFO_ALT_NAME_INFORMATION) }, + { LEVEL(RAW_FILEINFO_STREAM_INFORMATION) }, + { LEVEL(RAW_FILEINFO_COMPRESSION_INFORMATION) }, + { LEVEL(RAW_FILEINFO_NETWORK_OPEN_INFORMATION) }, + { LEVEL(RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION) }, + { LEVEL(RAW_FILEINFO_SMB2_ALL_EAS) }, + { LEVEL(RAW_FILEINFO_SMB2_ALL_INFORMATION) }, + { LEVEL(RAW_FILEINFO_SEC_DESC) } +}; + +static struct { + const char *name; + uint16_t level; + NTSTATUS status; + union smb_fsinfo info; +} fs_levels[] = { + { LEVEL(RAW_QFS_VOLUME_INFORMATION) }, + { LEVEL(RAW_QFS_SIZE_INFORMATION) }, + { LEVEL(RAW_QFS_DEVICE_INFORMATION) }, + { LEVEL(RAW_QFS_ATTRIBUTE_INFORMATION) }, + { LEVEL(RAW_QFS_QUOTA_INFORMATION) }, + { LEVEL(RAW_QFS_FULL_SIZE_INFORMATION) }, + { LEVEL(RAW_QFS_OBJECTID_INFORMATION) } }; #define FNAME "testsmb2_file.dat" #define DNAME "testsmb2_dir" -/* basic testing of all SMB2 getinfo levels +/* + test fileinfo levels */ -BOOL torture_smb2_getinfo(void) +static BOOL torture_smb2_fileinfo(struct smb2_tree *tree) { - TALLOC_CTX *mem_ctx = talloc_new(NULL); struct smb2_handle hfile, hdir; - struct smb2_tree *tree; NTSTATUS status; int i; - if (!torture_smb2_connection(mem_ctx, &tree)) { - goto failed; - } - - torture_setup_complex_file(FNAME); - torture_setup_complex_file(FNAME ":streamtwo"); - torture_setup_complex_dir(DNAME); - torture_setup_complex_file(DNAME ":streamtwo"); - status = torture_smb2_testfile(tree, FNAME, &hfile); if (!NT_STATUS_IS_OK(status)) { printf("Unable to create test file '%s' - %s\n", FNAME, nt_errstr(status)); @@ -95,22 +95,81 @@ BOOL torture_smb2_getinfo(void) torture_smb2_all_info(tree, hfile); torture_smb2_all_info(tree, hdir); - for (i=0;i<ARRAY_SIZE(levels);i++) { - levels[i].fstatus = smb2_getinfo_level(tree, mem_ctx, hfile, - levels[i].level, &levels[i].finfo); - if (!NT_STATUS_IS_OK(levels[i].fstatus)) { - printf("%s failed on file - %s\n", levels[i].name, nt_errstr(levels[i].fstatus)); + for (i=0;i<ARRAY_SIZE(file_levels);i++) { + if (file_levels[i].level == RAW_FILEINFO_SEC_DESC) { + file_levels[i].finfo.query_secdesc.secinfo_flags = 0x7; + file_levels[i].dinfo.query_secdesc.secinfo_flags = 0x7; } - levels[i].dstatus = smb2_getinfo_level(tree, mem_ctx, hdir, - levels[i].level, &levels[i].dinfo); - if (!NT_STATUS_IS_OK(levels[i].dstatus)) { - printf("%s failed on dir - %s\n", levels[i].name, nt_errstr(levels[i].dstatus)); + file_levels[i].finfo.generic.level = file_levels[i].level; + file_levels[i].finfo.generic.in.handle = hfile; + file_levels[i].fstatus = smb2_getinfo_file(tree, tree, &file_levels[i].finfo); + if (!NT_STATUS_IS_OK(file_levels[i].fstatus)) { + printf("%s failed on file - %s\n", file_levels[i].name, nt_errstr(file_levels[i].fstatus)); + } + file_levels[i].dinfo.generic.level = file_levels[i].level; + file_levels[i].dinfo.generic.in.handle = hdir; + file_levels[i].dstatus = smb2_getinfo_file(tree, tree, &file_levels[i].dinfo); + if (!NT_STATUS_IS_OK(file_levels[i].dstatus)) { + printf("%s failed on dir - %s\n", file_levels[i].name, nt_errstr(file_levels[i].dstatus)); } } return True; failed: - talloc_free(mem_ctx); return False; } + + +/* + test fsinfo levels +*/ +static BOOL torture_smb2_fsinfo(struct smb2_tree *tree) +{ + int i; + NTSTATUS status; + struct smb2_handle handle; + + status = torture_smb2_testdir(tree, DNAME, &handle); + if (!NT_STATUS_IS_OK(status)) { + printf("Unable to create test directory '%s' - %s\n", DNAME, nt_errstr(status)); + return False; + } + + for (i=0;i<ARRAY_SIZE(fs_levels);i++) { + fs_levels[i].info.generic.level = fs_levels[i].level; + fs_levels[i].info.generic.handle = handle; + fs_levels[i].status = smb2_getinfo_fs(tree, tree, &fs_levels[i].info); + if (!NT_STATUS_IS_OK(fs_levels[i].status)) { + printf("%s failed - %s\n", fs_levels[i].name, nt_errstr(fs_levels[i].status)); + } + } + + return True; +} + + +/* basic testing of all SMB2 getinfo levels +*/ +BOOL torture_smb2_getinfo(void) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct smb2_tree *tree; + BOOL ret = True; + + if (!torture_smb2_connection(mem_ctx, &tree)) { + return False; + } + + torture_setup_complex_file(FNAME); + torture_setup_complex_file(FNAME ":streamtwo"); + torture_setup_complex_dir(DNAME); + torture_setup_complex_file(DNAME ":streamtwo"); + + ret &= torture_smb2_fileinfo(tree); + ret &= torture_smb2_fsinfo(tree); + + talloc_free(mem_ctx); + + return ret; +} diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c index 6cbc230630..95624220f7 100644 --- a/source4/torture/smb2/util.c +++ b/source4/torture/smb2/util.c @@ -34,65 +34,68 @@ void torture_smb2_all_info(struct smb2_tree *tree, struct smb2_handle handle) { NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(tree); - union smb2_fileinfo io; + union smb_fileinfo io; - status = smb2_getinfo_level(tree, tmp_ctx, handle, SMB2_GETINFO_FILE_ALL_INFO, &io); + io.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION; + io.generic.in.handle = handle; + + status = smb2_getinfo_file(tree, tmp_ctx, &io); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("getinfo failed - %s\n", nt_errstr(status))); talloc_free(tmp_ctx); return; } - d_printf("\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info.create_time)); - d_printf("\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info.access_time)); - d_printf("\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info.write_time)); - d_printf("\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info.change_time)); - d_printf("\tattrib: 0x%x\n", io.all_info.file_attr); - d_printf("\tunknown1: 0x%x\n", io.all_info.unknown1); - d_printf("\talloc_size: %llu\n", (uint64_t)io.all_info.alloc_size); - d_printf("\tsize: %llu\n", (uint64_t)io.all_info.size); - d_printf("\tnlink: %u\n", io.all_info.nlink); - d_printf("\tdelete_pending: %u\n", io.all_info.delete_pending); - d_printf("\tdirectory: %u\n", io.all_info.directory); - d_printf("\tfile_id: %llu\n", io.all_info.file_id); - d_printf("\tea_size: %u\n", io.all_info.ea_size); - d_printf("\taccess_mask: 0x%08x\n", io.all_info.access_mask); - d_printf("\tunknown5: 0x%llx\n", io.all_info.unknown5); - d_printf("\tunknown6: 0x%llx\n", io.all_info.unknown6); - d_printf("\tfname: '%s'\n", io.all_info.fname); + d_printf("\tcreate_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.create_time)); + d_printf("\taccess_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.access_time)); + d_printf("\twrite_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.write_time)); + d_printf("\tchange_time: %s\n", nt_time_string(tmp_ctx, io.all_info2.out.change_time)); + d_printf("\tattrib: 0x%x\n", io.all_info2.out.attrib); + d_printf("\tunknown1: 0x%x\n", io.all_info2.out.unknown1); + d_printf("\talloc_size: %llu\n", (uint64_t)io.all_info2.out.alloc_size); + d_printf("\tsize: %llu\n", (uint64_t)io.all_info2.out.size); + d_printf("\tnlink: %u\n", io.all_info2.out.nlink); + d_printf("\tdelete_pending: %u\n", io.all_info2.out.delete_pending); + d_printf("\tdirectory: %u\n", io.all_info2.out.directory); + d_printf("\tfile_id: %llu\n", io.all_info2.out.file_id); + d_printf("\tea_size: %u\n", io.all_info2.out.ea_size); + d_printf("\taccess_mask: 0x%08x\n", io.all_info2.out.access_mask); + d_printf("\tunknown2: 0x%llx\n", io.all_info2.out.unknown2); + d_printf("\tunknown3: 0x%llx\n", io.all_info2.out.unknown3); + d_printf("\tfname: '%s'\n", io.all_info2.out.fname.s); /* short name, if any */ - status = smb2_getinfo_level(tree, tmp_ctx, handle, - SMB2_GETINFO_FILE_SHORT_INFO, &io); + io.generic.level = RAW_FILEINFO_ALT_NAME_INFORMATION; + status = smb2_getinfo_file(tree, tmp_ctx, &io); if (NT_STATUS_IS_OK(status)) { - d_printf("\tshort name: '%s'\n", io.short_info.short_name); + d_printf("\tshort name: '%s'\n", io.alt_name_info.out.fname.s); } /* the EAs, if any */ - status = smb2_getinfo_level(tree, tmp_ctx, handle, - SMB2_GETINFO_FILE_ALL_EAS, &io); + io.generic.level = RAW_FILEINFO_SMB2_ALL_EAS; + status = smb2_getinfo_file(tree, tmp_ctx, &io); if (NT_STATUS_IS_OK(status)) { int i; - for (i=0;i<io.all_eas.num_eas;i++) { + for (i=0;i<io.all_eas.out.num_eas;i++) { d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i, - io.all_eas.eas[i].flags, - (int)io.all_eas.eas[i].value.length, - io.all_eas.eas[i].name.s); + io.all_eas.out.eas[i].flags, + (int)io.all_eas.out.eas[i].value.length, + io.all_eas.out.eas[i].name.s); } } /* streams, if available */ - status = smb2_getinfo_level(tree, tmp_ctx, handle, - SMB2_GETINFO_FILE_STREAM_INFO, &io); + io.generic.level = RAW_FILEINFO_STREAM_INFORMATION; + status = smb2_getinfo_file(tree, tmp_ctx, &io); if (NT_STATUS_IS_OK(status)) { int i; - for (i=0;i<io.stream_info.num_streams;i++) { + for (i=0;i<io.stream_info.out.num_streams;i++) { d_printf("\tstream %d:\n", i); d_printf("\t\tsize %ld\n", - (long)io.stream_info.streams[i].size); + (long)io.stream_info.out.streams[i].size); d_printf("\t\talloc size %ld\n", - (long)io.stream_info.streams[i].alloc_size); - d_printf("\t\tname %s\n", io.stream_info.streams[i].stream_name.s); + (long)io.stream_info.out.streams[i].alloc_size); + d_printf("\t\tname %s\n", io.stream_info.out.streams[i].stream_name.s); } } @@ -173,7 +176,7 @@ NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname, io.in.access_mask = SEC_RIGHTS_DIR_ALL; io.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; io.in.open_disposition = NTCREATEX_DISP_OPEN_IF; - io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE; + io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE; io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; io.in.fname = fname; io.in.blob = data_blob(NULL, 0); |