diff options
-rw-r--r-- | source4/libcli/raw/rawsetfileinfo.c | 143 | ||||
-rw-r--r-- | source4/libcli/smb2/config.mk | 3 | ||||
-rw-r--r-- | source4/libcli/smb2/getinfo.c | 98 | ||||
-rw-r--r-- | source4/libcli/smb2/request.c | 51 | ||||
-rw-r--r-- | source4/libcli/smb2/setinfo.c | 109 | ||||
-rw-r--r-- | source4/libcli/smb2/smb2_calls.h | 9 |
6 files changed, 328 insertions, 85 deletions
diff --git a/source4/libcli/raw/rawsetfileinfo.c b/source4/libcli/raw/rawsetfileinfo.c index 5e780757e8..5779cf33fb 100644 --- a/source4/libcli/raw/rawsetfileinfo.c +++ b/source4/libcli/raw/rawsetfileinfo.c @@ -22,13 +22,14 @@ #include "includes.h" #include "libcli/raw/libcliraw.h" -/**************************************************************************** - Handle setfileinfo/setpathinfo trans2 backend. -****************************************************************************/ -static BOOL smb_raw_setinfo_backend(struct smbcli_tree *tree, - TALLOC_CTX *mem_ctx, - union smb_setfileinfo *parms, - DATA_BLOB *blob) + +/* + Handle setfileinfo/setpathinfo passthu constructions +*/ +BOOL smb_raw_setfileinfo_passthru(TALLOC_CTX *mem_ctx, + enum smb_setfileinfo_level level, + union smb_setfileinfo *parms, + DATA_BLOB *blob) { uint_t len; @@ -37,6 +38,77 @@ static BOOL smb_raw_setinfo_backend(struct smbcli_tree *tree, if (blob->data == NULL) return False; \ } while (0) + switch (level) { + case RAW_SFILEINFO_BASIC_INFORMATION: + NEED_BLOB(40); + smbcli_push_nttime(blob->data, 0, parms->basic_info.in.create_time); + smbcli_push_nttime(blob->data, 8, parms->basic_info.in.access_time); + smbcli_push_nttime(blob->data, 16, parms->basic_info.in.write_time); + smbcli_push_nttime(blob->data, 24, parms->basic_info.in.change_time); + SIVAL(blob->data, 32, parms->basic_info.in.attrib); + SIVAL(blob->data, 36, 0); /* padding */ + return True; + + case RAW_SFILEINFO_DISPOSITION_INFORMATION: + NEED_BLOB(4); + SIVAL(blob->data, 0, parms->disposition_info.in.delete_on_close); + return True; + + case RAW_SFILEINFO_ALLOCATION_INFORMATION: + NEED_BLOB(8); + SBVAL(blob->data, 0, parms->allocation_info.in.alloc_size); + return True; + + case RAW_SFILEINFO_END_OF_FILE_INFORMATION: + NEED_BLOB(8); + SBVAL(blob->data, 0, parms->end_of_file_info.in.size); + return True; + + case RAW_SFILEINFO_RENAME_INFORMATION: + NEED_BLOB(12); + SIVAL(blob->data, 0, parms->rename_information.in.overwrite); + SIVAL(blob->data, 4, parms->rename_information.in.root_fid); + len = smbcli_blob_append_string(NULL, mem_ctx, blob, + parms->rename_information.in.new_name, + STR_UNICODE|STR_TERMINATE); + SIVAL(blob->data, 8, len - 2); + return True; + + case RAW_SFILEINFO_POSITION_INFORMATION: + NEED_BLOB(8); + SBVAL(blob->data, 0, parms->position_information.in.position); + return True; + + case RAW_SFILEINFO_MODE_INFORMATION: + NEED_BLOB(4); + SIVAL(blob->data, 0, parms->mode_information.in.mode); + return True; + + /* Unhandled levels */ + case RAW_SFILEINFO_1023: + case RAW_SFILEINFO_1025: + case RAW_SFILEINFO_1029: + case RAW_SFILEINFO_1032: + case RAW_SFILEINFO_1039: + case RAW_SFILEINFO_1040: + break; + + default: + DEBUG(0,("Unhandled setfileinfo passthru level %d\n", level)); + return False; + } + + return False; +} + +/* + Handle setfileinfo/setpathinfo trans2 backend. +*/ +static BOOL smb_raw_setinfo_backend(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + union smb_setfileinfo *parms, + DATA_BLOB *blob) +{ switch (parms->generic.level) { case RAW_SFILEINFO_GENERIC: case RAW_SFILEINFO_SETATTR: @@ -62,14 +134,8 @@ static BOOL smb_raw_setinfo_backend(struct smbcli_tree *tree, case RAW_SFILEINFO_BASIC_INFO: case RAW_SFILEINFO_BASIC_INFORMATION: - NEED_BLOB(40); - smbcli_push_nttime(blob->data, 0, parms->basic_info.in.create_time); - smbcli_push_nttime(blob->data, 8, parms->basic_info.in.access_time); - smbcli_push_nttime(blob->data, 16, parms->basic_info.in.write_time); - smbcli_push_nttime(blob->data, 24, parms->basic_info.in.change_time); - SIVAL(blob->data, 32, parms->basic_info.in.attrib); - SIVAL(blob->data, 36, 0); /* padding */ - return True; + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_BASIC_INFORMATION, + parms, blob); case RAW_SFILEINFO_UNIX_BASIC: NEED_BLOB(92); @@ -89,52 +155,45 @@ static BOOL smb_raw_setinfo_backend(struct smbcli_tree *tree, case RAW_SFILEINFO_DISPOSITION_INFO: case RAW_SFILEINFO_DISPOSITION_INFORMATION: - NEED_BLOB(4); - SIVAL(blob->data, 0, parms->disposition_info.in.delete_on_close); - return True; + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_DISPOSITION_INFORMATION, + parms, blob); case RAW_SFILEINFO_ALLOCATION_INFO: case RAW_SFILEINFO_ALLOCATION_INFORMATION: - NEED_BLOB(8); - SBVAL(blob->data, 0, parms->allocation_info.in.alloc_size); - return True; + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_ALLOCATION_INFORMATION, + parms, blob); case RAW_SFILEINFO_END_OF_FILE_INFO: case RAW_SFILEINFO_END_OF_FILE_INFORMATION: - NEED_BLOB(8); - SBVAL(blob->data, 0, parms->end_of_file_info.in.size); - return True; + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_END_OF_FILE_INFORMATION, + parms, blob); case RAW_SFILEINFO_RENAME_INFORMATION: - NEED_BLOB(12); - SIVAL(blob->data, 0, parms->rename_information.in.overwrite); - SIVAL(blob->data, 4, parms->rename_information.in.root_fid); - len = smbcli_blob_append_string(tree->session, mem_ctx, blob, - parms->rename_information.in.new_name, - STR_UNICODE|STR_TERMINATE); - SIVAL(blob->data, 8, len - 2); - return True; + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_RENAME_INFORMATION, + parms, blob); case RAW_SFILEINFO_POSITION_INFORMATION: - NEED_BLOB(8); - SBVAL(blob->data, 0, parms->position_information.in.position); - return True; + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_POSITION_INFORMATION, + parms, blob); case RAW_SFILEINFO_MODE_INFORMATION: - NEED_BLOB(4); - SIVAL(blob->data, 0, parms->mode_information.in.mode); - return True; + return smb_raw_setfileinfo_passthru(mem_ctx, RAW_SFILEINFO_MODE_INFORMATION, + parms, blob); - /* Unhandled levels */ - - case RAW_SFILEINFO_UNIX_LINK: - case RAW_SFILEINFO_UNIX_HLINK: + /* Unhandled passthru levels */ case RAW_SFILEINFO_1023: case RAW_SFILEINFO_1025: case RAW_SFILEINFO_1029: case RAW_SFILEINFO_1032: case RAW_SFILEINFO_1039: case RAW_SFILEINFO_1040: + return smb_raw_setfileinfo_passthru(mem_ctx, parms->generic.level, + parms, blob); + + /* Unhandled levels */ + + case RAW_SFILEINFO_UNIX_LINK: + case RAW_SFILEINFO_UNIX_HLINK: break; } diff --git a/source4/libcli/smb2/config.mk b/source4/libcli/smb2/config.mk index 15f49ba88e..fcea996f01 100644 --- a/source4/libcli/smb2/config.mk +++ b/source4/libcli/smb2/config.mk @@ -10,5 +10,6 @@ OBJ_FILES = \ connect.o \ getinfo.o \ write.o \ - read.o + read.o \ + setinfo.o REQUIRED_SUBSYSTEMS = LIBCLI_RAW LIBPACKET diff --git a/source4/libcli/smb2/getinfo.c b/source4/libcli/smb2/getinfo.c index cb8ce76a07..4575ae2a40 100644 --- a/source4/libcli/smb2/getinfo.c +++ b/source4/libcli/smb2/getinfo.c @@ -87,6 +87,44 @@ NTSTATUS smb2_getinfo(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, /* + map a generic info level to a SMB2 info level +*/ +uint16_t smb2_getinfo_map_level(uint16_t level, uint8_t class) +{ + if ((level & 0xFF) == class) { + return level; + } else if (level > 1000) { + return ((level-1000)<<8) | class; + } + DEBUG(0,("Unable to map SMB2 info level 0x%04x of class %d\n", level, class)); + return 0; +} + +/* + level specific getinfo call - async send +*/ +struct smb2_request *smb2_getinfo_file_send(struct smb2_tree *tree, union smb_fileinfo *io) +{ + struct smb2_getinfo b; + uint16_t smb2_level = smb2_getinfo_map_level(io->generic.level, SMB2_GETINFO_FILE); + + if (smb2_level == 0) { + return NULL; + } + + 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 smb2_getinfo_send(tree, &b); +} + +/* recv a getinfo reply and parse the level info */ NTSTATUS smb2_getinfo_file_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, @@ -110,36 +148,31 @@ NTSTATUS smb2_getinfo_file_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, 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; + struct smb2_request *req = smb2_getinfo_file_send(tree, io); + return smb2_getinfo_file_recv(req, mem_ctx, io); +} - 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; - } +/* + level specific getinfo call - async send +*/ +struct smb2_request *smb2_getinfo_fs_send(struct smb2_tree *tree, union smb_fsinfo *io) +{ + struct smb2_getinfo b; + uint16_t smb2_level = smb2_getinfo_map_level(io->generic.level, SMB2_GETINFO_FS); + + if (smb2_level == 0) { + return NULL; + } + ZERO_STRUCT(b); b.in.max_response_size = 0x10000; - b.in.handle = io->generic.in.handle; + b.in.handle = io->generic.handle; b.in.level = smb2_level; - if (io->generic.level == RAW_FILEINFO_SEC_DESC) { - b.in.flags = io->query_secdesc.secinfo_flags; - } - - req = smb2_getinfo_send(tree, &b); - - return smb2_getinfo_file_recv(req, mem_ctx, io); + return smb2_getinfo_send(tree, &b); } - /* recv a getinfo reply and parse the level info */ @@ -164,26 +197,7 @@ NTSTATUS smb2_getinfo_fs_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, 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 = io->generic.handle; - b.in.level = smb2_level; - - req = smb2_getinfo_send(tree, &b); - + struct smb2_request *req = smb2_getinfo_fs_send(tree, io); return smb2_getinfo_fs_recv(req, mem_ctx, io); } diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c index 1a98ba9987..41e2ad74e2 100644 --- a/source4/libcli/smb2/request.c +++ b/source4/libcli/smb2/request.c @@ -390,6 +390,57 @@ NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, return NT_STATUS_OK; } + +/* + push a uint32_t length/ uint32_t ofs/blob triple into a data blob + the ofs points to the start of the length/offset pair, and is relative + to the body start +*/ +NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf, + uint32_t ofs, DATA_BLOB blob) +{ + NTSTATUS status; + size_t offset; + size_t padding_length; + uint8_t *ptr = buf->body+ofs; + + if (buf->dynamic == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* check if there're enough room for ofs and size */ + if (smb2_oob(buf, ptr, 8)) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + if (blob.length == 0) { + SIVAL(ptr, 0, 0); + SIVAL(ptr, 4, 0); + return NT_STATUS_OK; + } + + offset = buf->dynamic - buf->hdr; + padding_length = smb2_padding_size(offset, 8); + offset += padding_length; + + SIVAL(ptr, 0, blob.length); + SIVAL(ptr, 4, offset); + + status = smb2_grow_buffer(buf, padding_length + blob.length); + NT_STATUS_NOT_OK_RETURN(status); + + memset(buf->dynamic, 0, padding_length); + buf->dynamic += padding_length; + + memcpy(buf->dynamic, blob.data, blob.length); + buf->dynamic += blob.length; + + buf->size += blob.length + padding_length; + buf->body_size += blob.length + padding_length; + + return NT_STATUS_OK; +} + /* pull a uint16_t ofs/ uint32_t length/blob triple from a data blob the ptr points to the start of the offset/length pair diff --git a/source4/libcli/smb2/setinfo.c b/source4/libcli/smb2/setinfo.c new file mode 100644 index 0000000000..d6c5555a33 --- /dev/null +++ b/source4/libcli/smb2/setinfo.c @@ -0,0 +1,109 @@ +/* + Unix SMB/CIFS implementation. + + SMB2 client setinfo calls + + Copyright (C) Andrew Tridgell 2005 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" + +/* + send a setinfo request +*/ +struct smb2_request *smb2_setinfo_send(struct smb2_tree *tree, struct smb2_setinfo *io) +{ + struct smb2_request *req; + + req = smb2_request_init_tree(tree, SMB2_OP_SETINFO, 0x20, io->in.blob.length); + if (req == NULL) return NULL; + + SSVAL(req->out.body, 0x02, io->in.level); + smb2_push_s32o32_blob(&req->out, 0x04, io->in.blob); + SIVAL(req->out.body, 0x0C, io->in.flags); + smb2_push_handle(req->out.body+0x10, &io->in.handle); + + smb2_transport_send(req); + + return req; +} + + +/* + recv a setinfo reply +*/ +NTSTATUS smb2_setinfo_recv(struct smb2_request *req) +{ + if (!smb2_request_receive(req) || + smb2_request_is_error(req)) { + return smb2_request_destroy(req); + } + + SMB2_CHECK_PACKET_RECV(req, 0x02, False); + + return smb2_request_destroy(req); +} + +/* + sync setinfo request +*/ +NTSTATUS smb2_setinfo(struct smb2_tree *tree, struct smb2_setinfo *io) +{ + struct smb2_request *req = smb2_setinfo_send(tree, io); + return smb2_setinfo_recv(req); +} + +/* + level specific file setinfo call - async send +*/ +struct smb2_request *smb2_setinfo_file_send(struct smb2_tree *tree, union smb_setfileinfo *io) +{ + struct smb2_setinfo b; + uint16_t smb2_level = smb2_getinfo_map_level(io->generic.level, SMB2_GETINFO_FILE); + struct smb2_request *req; + + if (smb2_level == 0) { + return NULL; + } + + ZERO_STRUCT(b); + b.in.level = smb2_level; + b.in.handle = io->generic.file.handle; + if (!smb_raw_setfileinfo_passthru(tree, io->generic.level, io, &b.in.blob)) { + return NULL; + } + + if (io->generic.level == RAW_SFILEINFO_SEC_DESC) { + b.in.flags = io->set_secdesc.in.secinfo_flags; + } + + req = smb2_setinfo_send(tree, &b); + data_blob_free(&b.in.blob); + return req; +} + +/* + level specific file setinfo call - sync +*/ +NTSTATUS smb2_setinfo_file(struct smb2_tree *tree, union smb_setfileinfo *io) +{ + struct smb2_request *req = smb2_setinfo_file_send(tree, io); + return smb2_setinfo_recv(req); +} diff --git a/source4/libcli/smb2/smb2_calls.h b/source4/libcli/smb2/smb2_calls.h index 3ccb5309e5..1ef056da13 100644 --- a/source4/libcli/smb2/smb2_calls.h +++ b/source4/libcli/smb2/smb2_calls.h @@ -215,6 +215,15 @@ struct smb2_getinfo { } out; }; +struct smb2_setinfo { + struct { + uint16_t level; + uint32_t flags; + struct smb2_handle handle; + DATA_BLOB blob; + } in; +}; + struct smb2_write { struct { /* static body buffer 48 (0x30) bytes */ |