2 Unix SMB/CIFS implementation.
4 SMB2 client getinfo calls
6 Copyright (C) Andrew Tridgell 2005
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
29 send a getinfo request
31 struct smb2_request *smb2_getinfo_send(struct smb2_tree *tree, struct smb2_getinfo *io)
33 struct smb2_request *req;
35 req = smb2_request_init_tree(tree, SMB2_OP_GETINFO, 0x28);
36 if (req == NULL) return NULL;
38 SSVAL(req->out.body, 0x00, io->in.buffer_code);
39 SSVAL(req->out.body, 0x02, io->in.level);
40 SIVAL(req->out.body, 0x04, io->in.max_response_size);
41 SIVAL(req->out.body, 0x08, io->in.unknown1);
42 SIVAL(req->out.body, 0x0C, io->in.flags);
43 SIVAL(req->out.body, 0x10, io->in.unknown3);
44 SIVAL(req->out.body, 0x14, io->in.unknown4);
45 smb2_put_handle(req->out.body+0x18, &io->in.handle);
47 smb2_transport_send(req);
56 NTSTATUS smb2_getinfo_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
57 struct smb2_getinfo *io)
61 if (!smb2_request_receive(req) ||
62 smb2_request_is_error(req)) {
63 return smb2_request_destroy(req);
66 if (req->in.body_size < 0x08) {
67 return NT_STATUS_BUFFER_TOO_SMALL;
70 SMB2_CHECK_BUFFER_CODE(req, 0x09);
72 status = smb2_pull_ofs_blob(&req->in, mem_ctx, req->in.body+0x02, &io->out.blob);
73 if (!NT_STATUS_IS_OK(status)) {
77 return smb2_request_destroy(req);
83 NTSTATUS smb2_getinfo(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
84 struct smb2_getinfo *io)
86 struct smb2_request *req = smb2_getinfo_send(tree, io);
87 return smb2_getinfo_recv(req, mem_ctx, io);
92 parse a returned getinfo data blob
94 NTSTATUS smb2_getinfo_parse(TALLOC_CTX *mem_ctx,
97 union smb2_fileinfo *io)
100 case SMB2_GETINFO_FILE_BASIC_INFO:
101 if (blob.length != 0x28) {
102 return NT_STATUS_INFO_LENGTH_MISMATCH;
104 io->basic_info.create_time = smbcli_pull_nttime(blob.data, 0x00);
105 io->basic_info.access_time = smbcli_pull_nttime(blob.data, 0x08);
106 io->basic_info.write_time = smbcli_pull_nttime(blob.data, 0x10);
107 io->basic_info.change_time = smbcli_pull_nttime(blob.data, 0x18);
108 io->basic_info.file_attr = IVAL(blob.data, 0x20);
109 io->basic_info.unknown = IVAL(blob.data, 0x24);
112 case SMB2_GETINFO_FILE_SIZE_INFO:
113 if (blob.length != 0x18) {
114 return NT_STATUS_INFO_LENGTH_MISMATCH;
116 io->size_info.alloc_size = BVAL(blob.data, 0x00);
117 io->size_info.size = BVAL(blob.data, 0x08);
118 io->size_info.nlink = IVAL(blob.data, 0x10);
119 io->size_info.delete_pending = CVAL(blob.data, 0x14);
120 io->size_info.directory = CVAL(blob.data, 0x15);
123 case SMB2_GETINFO_FILE_ID:
124 if (blob.length != 0x8) {
125 return NT_STATUS_INFO_LENGTH_MISMATCH;
127 io->file_id.file_id = BVAL(blob.data, 0x00);
130 case SMB2_GETINFO_FILE_EA_SIZE:
131 if (blob.length != 0x4) {
132 return NT_STATUS_INFO_LENGTH_MISMATCH;
134 io->ea_size.ea_size = IVAL(blob.data, 0x00);
137 case SMB2_GETINFO_FILE_ACCESS_INFO:
138 if (blob.length != 0x4) {
139 return NT_STATUS_INFO_LENGTH_MISMATCH;
141 io->access_info.access_mask = IVAL(blob.data, 0x00);
144 case SMB2_GETINFO_FILE_0E:
145 if (blob.length != 0x8) {
146 return NT_STATUS_INFO_LENGTH_MISMATCH;
148 io->unknown0e.unknown1 = IVAL(blob.data, 0x00);
149 io->unknown0e.unknown2 = IVAL(blob.data, 0x04);
152 case SMB2_GETINFO_FILE_ALL_EAS:
153 return ea_pull_list(&blob, mem_ctx,
154 &io->all_eas.eas.num_eas,
155 &io->all_eas.eas.eas);
157 case SMB2_GETINFO_FILE_10:
158 if (blob.length != 0x4) {
159 return NT_STATUS_INFO_LENGTH_MISMATCH;
161 io->unknown10.unknown = IVAL(blob.data, 0x00);
164 case SMB2_GETINFO_FILE_11:
165 if (blob.length != 0x4) {
166 return NT_STATUS_INFO_LENGTH_MISMATCH;
168 io->unknown11.unknown = IVAL(blob.data, 0x00);
171 case SMB2_GETINFO_FILE_ALL_INFO: {
175 if (blob.length < 0x64) {
176 return NT_STATUS_INFO_LENGTH_MISMATCH;
178 io->all_info.create_time = smbcli_pull_nttime(blob.data, 0x00);
179 io->all_info.access_time = smbcli_pull_nttime(blob.data, 0x08);
180 io->all_info.write_time = smbcli_pull_nttime(blob.data, 0x10);
181 io->all_info.change_time = smbcli_pull_nttime(blob.data, 0x18);
182 io->all_info.file_attr = IVAL(blob.data, 0x20);
183 io->all_info.alloc_size = BVAL(blob.data, 0x28);
184 io->all_info.size = BVAL(blob.data, 0x30);
185 io->all_info.nlink = IVAL(blob.data, 0x38);
186 io->all_info.delete_pending = CVAL(blob.data, 0x3C);
187 io->all_info.directory = CVAL(blob.data, 0x3D);
188 io->all_info.file_id = BVAL(blob.data, 0x40);
189 io->all_info.ea_size = IVAL(blob.data, 0x48);
190 io->all_info.access_mask = IVAL(blob.data, 0x4C);
191 io->all_info.unknown5 = BVAL(blob.data, 0x50);
192 io->all_info.unknown6 = BVAL(blob.data, 0x58);
193 nlen = IVAL(blob.data, 0x60);
194 if (nlen > blob.length - 0x64) {
195 return NT_STATUS_INFO_LENGTH_MISMATCH;
197 size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
198 blob.data+0x64, nlen, &vstr);
200 return NT_STATUS_ILLEGAL_CHARACTER;
202 io->all_info.fname = vstr;
206 case SMB2_GETINFO_FILE_SHORT_INFO: {
210 if (blob.length < 0x04) {
211 return NT_STATUS_INFO_LENGTH_MISMATCH;
213 nlen = IVAL(blob.data, 0x00);
214 if (nlen > blob.length - 0x04) {
215 return NT_STATUS_INFO_LENGTH_MISMATCH;
217 size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
218 blob.data+0x04, nlen, &vstr);
220 return NT_STATUS_ILLEGAL_CHARACTER;
222 io->short_info.short_name = vstr;
226 case SMB2_GETINFO_FILE_STREAM_INFO:
227 return smbcli_parse_stream_info(blob, mem_ctx, &io->stream_info);
229 case SMB2_GETINFO_FILE_EOF_INFO:
230 if (blob.length != 0x10) {
231 return NT_STATUS_INFO_LENGTH_MISMATCH;
233 io->eof_info.size = BVAL(blob.data, 0x00);
234 io->eof_info.unknown = BVAL(blob.data, 0x08);
237 case SMB2_GETINFO_FILE_STANDARD_INFO:
238 if (blob.length != 0x38) {
239 return NT_STATUS_INFO_LENGTH_MISMATCH;
241 io->standard_info.create_time = smbcli_pull_nttime(blob.data, 0x00);
242 io->standard_info.access_time = smbcli_pull_nttime(blob.data, 0x08);
243 io->standard_info.write_time = smbcli_pull_nttime(blob.data, 0x10);
244 io->standard_info.change_time = smbcli_pull_nttime(blob.data, 0x18);
245 io->standard_info.alloc_size = BVAL(blob.data, 0x20);
246 io->standard_info.size = BVAL(blob.data, 0x28);
247 io->standard_info.file_attr = IVAL(blob.data, 0x30);
248 io->standard_info.unknown = IVAL(blob.data, 0x34);
251 case SMB2_GETINFO_FILE_ATTRIB_INFO:
252 if (blob.length != 0x08) {
253 return NT_STATUS_INFO_LENGTH_MISMATCH;
255 io->standard_info.file_attr = IVAL(blob.data, 0x00);
256 io->standard_info.unknown = IVAL(blob.data, 0x04);
259 case SMB2_GETINFO_SECURITY: {
260 struct ndr_pull *ndr;
262 ndr = ndr_pull_init_blob(&blob, mem_ctx);
264 return NT_STATUS_NO_MEMORY;
266 io->security.sd = talloc(mem_ctx, struct security_descriptor);
267 if (io->security.sd == NULL) {
268 return NT_STATUS_NO_MEMORY;
270 status = ndr_pull_security_descriptor(ndr, NDR_SCALARS|NDR_BUFFERS, io->security.sd);
276 return NT_STATUS_INVALID_INFO_CLASS;
284 recv a getinfo reply and parse the level info
286 NTSTATUS smb2_getinfo_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx,
287 uint16_t level, union smb2_fileinfo *io)
289 struct smb2_getinfo b;
292 status = smb2_getinfo_recv(req, mem_ctx, &b);
293 NT_STATUS_NOT_OK_RETURN(status);
295 status = smb2_getinfo_parse(mem_ctx, level, b.out.blob, io);
296 data_blob_free(&b.out.blob);
302 level specific getinfo call
304 NTSTATUS smb2_getinfo_level(struct smb2_tree *tree, TALLOC_CTX *mem_ctx,
305 struct smb2_handle handle,
306 uint16_t level, union smb2_fileinfo *io)
308 struct smb2_getinfo b;
309 struct smb2_request *req;
312 b.in.buffer_code = 0x29;
313 b.in.max_response_size = 0x10000;
314 b.in.handle = handle;
317 req = smb2_getinfo_send(tree, &b);
319 return smb2_getinfo_level_recv(req, mem_ctx, level, io);