2 Unix SMB/CIFS implementation.
3 client directory search routines
4 Copyright (C) James Myers 2003 <myersjj@samba.org>
5 Copyright (C) James Peach 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
25 /****************************************************************************
26 Old style search backend - process output.
27 ****************************************************************************/
28 static void smb_raw_search_backend(struct smbcli_request
*req
,
32 smbcli_search_callback callback
)
35 union smb_search_data search_data
;
39 if (req
->in
.data_size
< 3 + count
*43) {
40 req
->status
= NT_STATUS_INVALID_PARAMETER
;
46 for (i
=0; i
< count
; i
++) {
49 search_data
.search
.id
.reserved
= CVAL(p
, 0);
50 memcpy(search_data
.search
.id
.name
, p
+1, 11);
51 search_data
.search
.id
.handle
= CVAL(p
, 12);
52 search_data
.search
.id
.server_cookie
= IVAL(p
, 13);
53 search_data
.search
.id
.client_cookie
= IVAL(p
, 17);
54 search_data
.search
.attrib
= CVAL(p
, 21);
55 search_data
.search
.write_time
= raw_pull_dos_date(req
->transport
,
57 search_data
.search
.size
= IVAL(p
, 26);
58 smbcli_req_pull_ascii(&req
->in
.bufinfo
, mem_ctx
, &name
, p
+30, 13, STR_ASCII
);
59 search_data
.search
.name
= name
;
60 if (!callback(private_data
, &search_data
)) {
67 /****************************************************************************
68 Old style search first.
69 ****************************************************************************/
70 static NTSTATUS
smb_raw_search_first_old(struct smbcli_tree
*tree
,
72 union smb_search_first
*io
, void *private_data
,
73 smbcli_search_callback callback
)
76 struct smbcli_request
*req
;
77 uint8_t op
= SMBsearch
;
79 if (io
->generic
.level
== RAW_SEARCH_FFIRST
) {
81 } else if (io
->generic
.level
== RAW_SEARCH_FUNIQUE
) {
85 req
= smbcli_request_setup(tree
, op
, 2, 0);
87 return NT_STATUS_NO_MEMORY
;
90 SSVAL(req
->out
.vwv
, VWV(0), io
->search_first
.in
.max_count
);
91 SSVAL(req
->out
.vwv
, VWV(1), io
->search_first
.in
.search_attrib
);
92 smbcli_req_append_ascii4(req
, io
->search_first
.in
.pattern
, STR_TERMINATE
);
93 smbcli_req_append_var_block(req
, NULL
, 0);
95 if (!smbcli_request_send(req
) ||
96 !smbcli_request_receive(req
)) {
97 return smbcli_request_destroy(req
);
100 if (NT_STATUS_IS_OK(req
->status
)) {
101 io
->search_first
.out
.count
= SVAL(req
->in
.vwv
, VWV(0));
102 smb_raw_search_backend(req
, mem_ctx
, io
->search_first
.out
.count
, private_data
, callback
);
105 return smbcli_request_destroy(req
);
108 /****************************************************************************
109 Old style search next.
110 ****************************************************************************/
111 static NTSTATUS
smb_raw_search_next_old(struct smbcli_tree
*tree
,
113 union smb_search_next
*io
, void *private_data
,
114 smbcli_search_callback callback
)
117 struct smbcli_request
*req
;
118 uint8_t var_block
[21];
119 uint8_t op
= SMBsearch
;
121 if (io
->generic
.level
== RAW_SEARCH_FFIRST
) {
125 req
= smbcli_request_setup(tree
, op
, 2, 0);
127 return NT_STATUS_NO_MEMORY
;
130 SSVAL(req
->out
.vwv
, VWV(0), io
->search_next
.in
.max_count
);
131 SSVAL(req
->out
.vwv
, VWV(1), io
->search_next
.in
.search_attrib
);
132 smbcli_req_append_ascii4(req
, "", STR_TERMINATE
);
134 SCVAL(var_block
, 0, io
->search_next
.in
.id
.reserved
);
135 memcpy(&var_block
[1], io
->search_next
.in
.id
.name
, 11);
136 SCVAL(var_block
, 12, io
->search_next
.in
.id
.handle
);
137 SIVAL(var_block
, 13, io
->search_next
.in
.id
.server_cookie
);
138 SIVAL(var_block
, 17, io
->search_next
.in
.id
.client_cookie
);
140 smbcli_req_append_var_block(req
, var_block
, 21);
142 if (!smbcli_request_send(req
) ||
143 !smbcli_request_receive(req
)) {
144 return smbcli_request_destroy(req
);
147 if (NT_STATUS_IS_OK(req
->status
)) {
148 io
->search_next
.out
.count
= SVAL(req
->in
.vwv
, VWV(0));
149 smb_raw_search_backend(req
, mem_ctx
, io
->search_next
.out
.count
, private_data
, callback
);
152 return smbcli_request_destroy(req
);
156 /****************************************************************************
157 Old style search next.
158 ****************************************************************************/
159 static NTSTATUS
smb_raw_search_close_old(struct smbcli_tree
*tree
,
160 union smb_search_close
*io
)
162 struct smbcli_request
*req
;
163 uint8_t var_block
[21];
165 req
= smbcli_request_setup(tree
, SMBfclose
, 2, 0);
167 return NT_STATUS_NO_MEMORY
;
170 SSVAL(req
->out
.vwv
, VWV(0), io
->fclose
.in
.max_count
);
171 SSVAL(req
->out
.vwv
, VWV(1), io
->fclose
.in
.search_attrib
);
172 smbcli_req_append_ascii4(req
, "", STR_TERMINATE
);
174 SCVAL(var_block
, 0, io
->fclose
.in
.id
.reserved
);
175 memcpy(&var_block
[1], io
->fclose
.in
.id
.name
, 11);
176 SCVAL(var_block
, 12, io
->fclose
.in
.id
.handle
);
177 SIVAL(var_block
, 13, io
->fclose
.in
.id
.server_cookie
);
178 SIVAL(var_block
, 17, io
->fclose
.in
.id
.client_cookie
);
180 smbcli_req_append_var_block(req
, var_block
, 21);
182 if (!smbcli_request_send(req
) ||
183 !smbcli_request_receive(req
)) {
184 return smbcli_request_destroy(req
);
187 return smbcli_request_destroy(req
);
192 /****************************************************************************
193 Very raw search first - returns param/data blobs.
194 ****************************************************************************/
195 static NTSTATUS
smb_raw_search_first_blob(struct smbcli_tree
*tree
,
196 TALLOC_CTX
*mem_ctx
, /* used to allocate output blobs */
197 union smb_search_first
*io
,
198 DATA_BLOB
*out_param_blob
,
199 DATA_BLOB
*out_data_blob
)
201 struct smb_trans2 tp
;
202 uint16_t setup
= TRANSACT2_FINDFIRST
;
208 tp
.in
.setup_count
= 1;
209 tp
.in
.data
= data_blob(NULL
, 0);
210 tp
.in
.max_param
= 10;
211 tp
.in
.max_data
= 0xFFFF;
212 tp
.in
.setup
= &setup
;
214 if (io
->t2ffirst
.level
!= RAW_SEARCH_TRANS2
) {
215 return NT_STATUS_INVALID_LEVEL
;
218 if (io
->t2ffirst
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
219 return NT_STATUS_INVALID_LEVEL
;
222 if (io
->t2ffirst
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
223 if (!ea_push_name_list(mem_ctx
,
225 io
->t2ffirst
.in
.num_names
,
226 io
->t2ffirst
.in
.ea_names
)) {
227 return NT_STATUS_NO_MEMORY
;
231 tp
.in
.params
= data_blob_talloc(mem_ctx
, NULL
, 12);
232 if (!tp
.in
.params
.data
) {
233 return NT_STATUS_NO_MEMORY
;
236 SSVAL(tp
.in
.params
.data
, 0, io
->t2ffirst
.in
.search_attrib
);
237 SSVAL(tp
.in
.params
.data
, 2, io
->t2ffirst
.in
.max_count
);
238 SSVAL(tp
.in
.params
.data
, 4, io
->t2ffirst
.in
.flags
);
239 SSVAL(tp
.in
.params
.data
, 6, io
->t2ffirst
.data_level
);
240 SIVAL(tp
.in
.params
.data
, 8, io
->t2ffirst
.in
.storage_type
);
242 smbcli_blob_append_string(tree
->session
, mem_ctx
, &tp
.in
.params
,
243 io
->t2ffirst
.in
.pattern
, STR_TERMINATE
);
245 status
= smb_raw_trans2(tree
, mem_ctx
, &tp
);
246 if (!NT_STATUS_IS_OK(status
)) {
250 out_param_blob
->length
= tp
.out
.params
.length
;
251 out_param_blob
->data
= tp
.out
.params
.data
;
252 out_data_blob
->length
= tp
.out
.data
.length
;
253 out_data_blob
->data
= tp
.out
.data
.data
;
259 /****************************************************************************
260 Very raw search first - returns param/data blobs.
261 Used in CIFS-on-CIFS NTVFS.
262 ****************************************************************************/
263 static NTSTATUS
smb_raw_search_next_blob(struct smbcli_tree
*tree
,
265 union smb_search_next
*io
,
266 DATA_BLOB
*out_param_blob
,
267 DATA_BLOB
*out_data_blob
)
269 struct smb_trans2 tp
;
270 uint16_t setup
= TRANSACT2_FINDNEXT
;
276 tp
.in
.setup_count
= 1;
277 tp
.in
.data
= data_blob(NULL
, 0);
278 tp
.in
.max_param
= 10;
279 tp
.in
.max_data
= 0xFFFF;
280 tp
.in
.setup
= &setup
;
282 if (io
->t2fnext
.level
!= RAW_SEARCH_TRANS2
) {
283 return NT_STATUS_INVALID_LEVEL
;
286 if (io
->t2fnext
.data_level
>= RAW_SEARCH_DATA_GENERIC
) {
287 return NT_STATUS_INVALID_LEVEL
;
290 if (io
->t2fnext
.data_level
== RAW_SEARCH_DATA_EA_LIST
) {
291 if (!ea_push_name_list(mem_ctx
,
293 io
->t2fnext
.in
.num_names
,
294 io
->t2fnext
.in
.ea_names
)) {
295 return NT_STATUS_NO_MEMORY
;
299 tp
.in
.params
= data_blob_talloc(mem_ctx
, NULL
, 12);
300 if (!tp
.in
.params
.data
) {
301 return NT_STATUS_NO_MEMORY
;
304 SSVAL(tp
.in
.params
.data
, 0, io
->t2fnext
.in
.handle
);
305 SSVAL(tp
.in
.params
.data
, 2, io
->t2fnext
.in
.max_count
);
306 SSVAL(tp
.in
.params
.data
, 4, io
->t2fnext
.data_level
);
307 SIVAL(tp
.in
.params
.data
, 6, io
->t2fnext
.in
.resume_key
);
308 SSVAL(tp
.in
.params
.data
, 10, io
->t2fnext
.in
.flags
);
310 smbcli_blob_append_string(tree
->session
, mem_ctx
, &tp
.in
.params
,
311 io
->t2fnext
.in
.last_name
,
314 status
= smb_raw_trans2(tree
, mem_ctx
, &tp
);
315 if (!NT_STATUS_IS_OK(status
)) {
319 out_param_blob
->length
= tp
.out
.params
.length
;
320 out_param_blob
->data
= tp
.out
.params
.data
;
321 out_data_blob
->length
= tp
.out
.data
.length
;
322 out_data_blob
->data
= tp
.out
.data
.data
;
329 parse the wire search formats that are in common between SMB and
332 NTSTATUS
smb_raw_search_common(TALLOC_CTX
*mem_ctx
,
333 enum smb_search_data_level level
,
334 const DATA_BLOB
*blob
,
335 union smb_search_data
*data
,
336 unsigned int *next_ofs
,
337 unsigned int str_flags
)
339 unsigned int len
, blen
;
341 if (blob
->length
< 4) {
342 return NT_STATUS_INFO_LENGTH_MISMATCH
;
345 *next_ofs
= IVAL(blob
->data
, 0);
346 if (*next_ofs
!= 0) {
353 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
354 if (blen
< 65) return NT_STATUS_INFO_LENGTH_MISMATCH
;
355 data
->directory_info
.file_index
= IVAL(blob
->data
, 4);
356 data
->directory_info
.create_time
= smbcli_pull_nttime(blob
->data
, 8);
357 data
->directory_info
.access_time
= smbcli_pull_nttime(blob
->data
, 16);
358 data
->directory_info
.write_time
= smbcli_pull_nttime(blob
->data
, 24);
359 data
->directory_info
.change_time
= smbcli_pull_nttime(blob
->data
, 32);
360 data
->directory_info
.size
= BVAL(blob
->data
, 40);
361 data
->directory_info
.alloc_size
= BVAL(blob
->data
, 48);
362 data
->directory_info
.attrib
= IVAL(blob
->data
, 56);
363 len
= smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
364 &data
->directory_info
.name
,
366 if (*next_ofs
!= 0 && *next_ofs
< 64+len
) {
367 return NT_STATUS_INFO_LENGTH_MISMATCH
;
371 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
372 if (blen
< 69) return NT_STATUS_INFO_LENGTH_MISMATCH
;
373 data
->full_directory_info
.file_index
= IVAL(blob
->data
, 4);
374 data
->full_directory_info
.create_time
= smbcli_pull_nttime(blob
->data
, 8);
375 data
->full_directory_info
.access_time
= smbcli_pull_nttime(blob
->data
, 16);
376 data
->full_directory_info
.write_time
= smbcli_pull_nttime(blob
->data
, 24);
377 data
->full_directory_info
.change_time
= smbcli_pull_nttime(blob
->data
, 32);
378 data
->full_directory_info
.size
= BVAL(blob
->data
, 40);
379 data
->full_directory_info
.alloc_size
= BVAL(blob
->data
, 48);
380 data
->full_directory_info
.attrib
= IVAL(blob
->data
, 56);
381 data
->full_directory_info
.ea_size
= IVAL(blob
->data
, 64);
382 len
= smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
383 &data
->full_directory_info
.name
,
385 if (*next_ofs
!= 0 && *next_ofs
< 68+len
) {
386 return NT_STATUS_INFO_LENGTH_MISMATCH
;
390 case RAW_SEARCH_DATA_NAME_INFO
:
391 if (blen
< 13) return NT_STATUS_INFO_LENGTH_MISMATCH
;
392 data
->name_info
.file_index
= IVAL(blob
->data
, 4);
393 len
= smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
394 &data
->name_info
.name
,
396 if (*next_ofs
!= 0 && *next_ofs
< 12+len
) {
397 return NT_STATUS_INFO_LENGTH_MISMATCH
;
402 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
403 if (blen
< 95) return NT_STATUS_INFO_LENGTH_MISMATCH
;
404 data
->both_directory_info
.file_index
= IVAL(blob
->data
, 4);
405 data
->both_directory_info
.create_time
= smbcli_pull_nttime(blob
->data
, 8);
406 data
->both_directory_info
.access_time
= smbcli_pull_nttime(blob
->data
, 16);
407 data
->both_directory_info
.write_time
= smbcli_pull_nttime(blob
->data
, 24);
408 data
->both_directory_info
.change_time
= smbcli_pull_nttime(blob
->data
, 32);
409 data
->both_directory_info
.size
= BVAL(blob
->data
, 40);
410 data
->both_directory_info
.alloc_size
= BVAL(blob
->data
, 48);
411 data
->both_directory_info
.attrib
= IVAL(blob
->data
, 56);
412 data
->both_directory_info
.ea_size
= IVAL(blob
->data
, 64);
413 smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
414 &data
->both_directory_info
.short_name
,
415 68, 70, STR_LEN8BIT
| STR_UNICODE
);
416 len
= smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
417 &data
->both_directory_info
.name
,
419 if (*next_ofs
!= 0 && *next_ofs
< 94+len
) {
420 return NT_STATUS_INFO_LENGTH_MISMATCH
;
425 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
426 if (blen
< 81) return NT_STATUS_INFO_LENGTH_MISMATCH
;
427 data
->id_full_directory_info
.file_index
= IVAL(blob
->data
, 4);
428 data
->id_full_directory_info
.create_time
= smbcli_pull_nttime(blob
->data
, 8);
429 data
->id_full_directory_info
.access_time
= smbcli_pull_nttime(blob
->data
, 16);
430 data
->id_full_directory_info
.write_time
= smbcli_pull_nttime(blob
->data
, 24);
431 data
->id_full_directory_info
.change_time
= smbcli_pull_nttime(blob
->data
, 32);
432 data
->id_full_directory_info
.size
= BVAL(blob
->data
, 40);
433 data
->id_full_directory_info
.alloc_size
= BVAL(blob
->data
, 48);
434 data
->id_full_directory_info
.attrib
= IVAL(blob
->data
, 56);
435 data
->id_full_directory_info
.ea_size
= IVAL(blob
->data
, 64);
436 data
->id_full_directory_info
.file_id
= BVAL(blob
->data
, 72);
437 len
= smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
438 &data
->id_full_directory_info
.name
,
440 if (*next_ofs
!= 0 && *next_ofs
< 80+len
) {
441 return NT_STATUS_INFO_LENGTH_MISMATCH
;
445 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
446 if (blen
< 105) return NT_STATUS_INFO_LENGTH_MISMATCH
;
447 data
->id_both_directory_info
.file_index
= IVAL(blob
->data
, 4);
448 data
->id_both_directory_info
.create_time
= smbcli_pull_nttime(blob
->data
, 8);
449 data
->id_both_directory_info
.access_time
= smbcli_pull_nttime(blob
->data
, 16);
450 data
->id_both_directory_info
.write_time
= smbcli_pull_nttime(blob
->data
, 24);
451 data
->id_both_directory_info
.change_time
= smbcli_pull_nttime(blob
->data
, 32);
452 data
->id_both_directory_info
.size
= BVAL(blob
->data
, 40);
453 data
->id_both_directory_info
.alloc_size
= BVAL(blob
->data
, 48);
454 data
->id_both_directory_info
.attrib
= SVAL(blob
->data
, 56);
455 data
->id_both_directory_info
.ea_size
= IVAL(blob
->data
, 64);
456 smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
457 &data
->id_both_directory_info
.short_name
,
458 68, 70, STR_LEN8BIT
| STR_UNICODE
);
459 data
->id_both_directory_info
.file_id
= BVAL(blob
->data
, 96);
460 len
= smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
461 &data
->id_both_directory_info
.name
,
463 if (*next_ofs
!= 0 && *next_ofs
< 104+len
) {
464 return NT_STATUS_INFO_LENGTH_MISMATCH
;
473 return NT_STATUS_INVALID_INFO_CLASS
;
478 parse a trans2 search response.
479 Return the number of bytes consumed
480 return 0 for success with end of list
481 return -1 for a parse error
483 static int parse_trans2_search(struct smbcli_tree
*tree
,
485 enum smb_search_data_level level
,
488 union smb_search_data
*data
)
490 unsigned int len
, ofs
;
496 case RAW_SEARCH_DATA_GENERIC
:
497 case RAW_SEARCH_DATA_SEARCH
:
498 /* handled elsewhere */
501 case RAW_SEARCH_DATA_STANDARD
:
502 if (flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
503 if (blob
->length
< 4) return -1;
504 data
->standard
.resume_key
= IVAL(blob
->data
, 0);
508 if (blob
->length
< 24) return -1;
509 data
->standard
.create_time
= raw_pull_dos_date2(tree
->session
->transport
,
511 data
->standard
.access_time
= raw_pull_dos_date2(tree
->session
->transport
,
513 data
->standard
.write_time
= raw_pull_dos_date2(tree
->session
->transport
,
515 data
->standard
.size
= IVAL(blob
->data
, 12);
516 data
->standard
.alloc_size
= IVAL(blob
->data
, 16);
517 data
->standard
.attrib
= SVAL(blob
->data
, 20);
518 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
519 &data
->standard
.name
,
520 22, 23, STR_LEN8BIT
| STR_TERMINATE
| STR_LEN_NOTERM
);
523 case RAW_SEARCH_DATA_EA_SIZE
:
524 if (flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
525 if (blob
->length
< 4) return -1;
526 data
->ea_size
.resume_key
= IVAL(blob
->data
, 0);
530 if (blob
->length
< 28) return -1;
531 data
->ea_size
.create_time
= raw_pull_dos_date2(tree
->session
->transport
,
533 data
->ea_size
.access_time
= raw_pull_dos_date2(tree
->session
->transport
,
535 data
->ea_size
.write_time
= raw_pull_dos_date2(tree
->session
->transport
,
537 data
->ea_size
.size
= IVAL(blob
->data
, 12);
538 data
->ea_size
.alloc_size
= IVAL(blob
->data
, 16);
539 data
->ea_size
.attrib
= SVAL(blob
->data
, 20);
540 data
->ea_size
.ea_size
= IVAL(blob
->data
, 22);
541 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
543 26, 27, STR_LEN8BIT
| STR_TERMINATE
| STR_NOALIGN
);
546 case RAW_SEARCH_DATA_EA_LIST
:
547 if (flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
548 if (blob
->length
< 4) return -1;
549 data
->ea_list
.resume_key
= IVAL(blob
->data
, 0);
553 if (blob
->length
< 28) return -1;
554 data
->ea_list
.create_time
= raw_pull_dos_date2(tree
->session
->transport
,
556 data
->ea_list
.access_time
= raw_pull_dos_date2(tree
->session
->transport
,
558 data
->ea_list
.write_time
= raw_pull_dos_date2(tree
->session
->transport
,
560 data
->ea_list
.size
= IVAL(blob
->data
, 12);
561 data
->ea_list
.alloc_size
= IVAL(blob
->data
, 16);
562 data
->ea_list
.attrib
= SVAL(blob
->data
, 20);
563 ea_size
= IVAL(blob
->data
, 22);
564 if (ea_size
> 0xFFFF) {
567 eablob
.data
= blob
->data
+ 22;
568 eablob
.length
= ea_size
;
569 if (eablob
.length
> blob
->length
- 24) {
572 status
= ea_pull_list(&eablob
, mem_ctx
,
573 &data
->ea_list
.eas
.num_eas
,
574 &data
->ea_list
.eas
.eas
);
575 if (!NT_STATUS_IS_OK(status
)) {
578 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
580 22+ea_size
, 23+ea_size
,
581 STR_LEN8BIT
| STR_NOALIGN
);
582 return len
+ ea_size
+ 23 + 1;
584 case RAW_SEARCH_DATA_UNIX_INFO
:
585 if (blob
->length
< 109) return -1;
586 ofs
= IVAL(blob
->data
, 0);
587 data
->unix_info
.file_index
= IVAL(blob
->data
, 4);
588 data
->unix_info
.size
= BVAL(blob
->data
, 8);
589 data
->unix_info
.alloc_size
= BVAL(blob
->data
, 16);
590 data
->unix_info
.status_change_time
= smbcli_pull_nttime(blob
->data
, 24);
591 data
->unix_info
.access_time
= smbcli_pull_nttime(blob
->data
, 32);
592 data
->unix_info
.change_time
= smbcli_pull_nttime(blob
->data
, 40);
593 data
->unix_info
.uid
= IVAL(blob
->data
, 48);
594 data
->unix_info
.gid
= IVAL(blob
->data
, 56);
595 data
->unix_info
.file_type
= IVAL(blob
->data
, 64);
596 data
->unix_info
.dev_major
= BVAL(blob
->data
, 68);
597 data
->unix_info
.dev_minor
= BVAL(blob
->data
, 76);
598 data
->unix_info
.unique_id
= BVAL(blob
->data
, 84);
599 data
->unix_info
.permissions
= IVAL(blob
->data
, 92);
600 data
->unix_info
.nlink
= IVAL(blob
->data
, 100);
601 /* There is no length field for this name but we know it's null terminated. */
602 len
= smbcli_blob_pull_unix_string(tree
->session
, mem_ctx
, blob
,
603 &data
->unix_info
.name
, 108, 0);
604 if (ofs
!= 0 && ofs
< 108+len
) {
609 case RAW_SEARCH_DATA_UNIX_INFO2
:
610 /* 8 - size of ofs + file_index
611 * 116 - size of unix_info2
612 * 4 - size of name length
613 * 2 - "." is the shortest name
615 if (blob
->length
< (116 + 8 + 4 + 2)) {
619 ofs
= IVAL(blob
->data
, 0);
620 data
->unix_info2
.file_index
= IVAL(blob
->data
, 4);
621 data
->unix_info2
.end_of_file
= BVAL(blob
->data
, 8);
622 data
->unix_info2
.num_bytes
= BVAL(blob
->data
, 16);
623 data
->unix_info2
.status_change_time
= smbcli_pull_nttime(blob
->data
, 24);
624 data
->unix_info2
.access_time
= smbcli_pull_nttime(blob
->data
, 32);
625 data
->unix_info2
.change_time
= smbcli_pull_nttime(blob
->data
, 40);
626 data
->unix_info2
.uid
= IVAL(blob
->data
, 48);
627 data
->unix_info2
.gid
= IVAL(blob
->data
, 56);
628 data
->unix_info2
.file_type
= IVAL(blob
->data
, 64);
629 data
->unix_info2
.dev_major
= BVAL(blob
->data
, 68);
630 data
->unix_info2
.dev_minor
= BVAL(blob
->data
, 76);
631 data
->unix_info2
.unique_id
= BVAL(blob
->data
, 84);
632 data
->unix_info2
.permissions
= IVAL(blob
->data
, 92);
633 data
->unix_info2
.nlink
= IVAL(blob
->data
, 100);
634 data
->unix_info2
.create_time
= smbcli_pull_nttime(blob
->data
, 108);
635 data
->unix_info2
.file_flags
= IVAL(blob
->data
, 116);
636 data
->unix_info2
.flags_mask
= IVAL(blob
->data
, 120);
638 /* There is a 4 byte length field for this name. The length
639 * does not include the NULL terminator.
641 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
642 &data
->unix_info2
.name
,
643 8 + 116, /* offset to length */
644 8 + 116 + 4, /* offset to string */
647 if (ofs
!= 0 && ofs
< (8 + 116 + 4 + len
)) {
653 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
654 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
655 case RAW_SEARCH_DATA_NAME_INFO
:
656 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
657 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
658 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
: {
659 unsigned int str_flags
= STR_UNICODE
;
660 if (!(tree
->session
->transport
->negotiate
.capabilities
& CAP_UNICODE
)) {
661 str_flags
= STR_ASCII
;
664 status
= smb_raw_search_common(mem_ctx
, level
, blob
, data
, &ofs
, str_flags
);
665 if (!NT_STATUS_IS_OK(status
)) {
676 /****************************************************************************
677 Trans2 search backend - process output.
678 ****************************************************************************/
679 static NTSTATUS
smb_raw_t2search_backend(struct smbcli_tree
*tree
,
681 enum smb_search_data_level level
,
686 smbcli_search_callback callback
)
692 blob2
.data
= blob
->data
;
693 blob2
.length
= blob
->length
;
695 for (i
=0; i
< count
; i
++) {
696 union smb_search_data search_data
;
699 len
= parse_trans2_search(tree
, mem_ctx
, level
, flags
, &blob2
, &search_data
);
701 return NT_STATUS_INVALID_PARAMETER
;
704 /* the callback function can tell us that no more will
705 fit - in that case we stop, but it isn't an error */
706 if (!callback(private_data
, &search_data
)) {
720 /* Implements trans2findfirst2 and old search
722 _PUBLIC_ NTSTATUS
smb_raw_search_first(struct smbcli_tree
*tree
,
724 union smb_search_first
*io
, void *private_data
,
725 smbcli_search_callback callback
)
727 DATA_BLOB p_blob
, d_blob
;
730 switch (io
->generic
.level
) {
731 case RAW_SEARCH_SEARCH
:
732 case RAW_SEARCH_FFIRST
:
733 case RAW_SEARCH_FUNIQUE
:
734 return smb_raw_search_first_old(tree
, mem_ctx
, io
, private_data
, callback
);
736 case RAW_SEARCH_TRANS2
:
739 case RAW_SEARCH_SMB2
:
740 return NT_STATUS_INVALID_LEVEL
;
743 status
= smb_raw_search_first_blob(tree
, mem_ctx
,
744 io
, &p_blob
, &d_blob
);
745 if (!NT_STATUS_IS_OK(status
)) {
749 if (p_blob
.length
< 10) {
750 DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n",
751 (int)p_blob
.length
));
752 return NT_STATUS_INVALID_PARAMETER
;
755 /* process output data */
756 io
->t2ffirst
.out
.handle
= SVAL(p_blob
.data
, 0);
757 io
->t2ffirst
.out
.count
= SVAL(p_blob
.data
, 2);
758 io
->t2ffirst
.out
.end_of_search
= SVAL(p_blob
.data
, 4);
760 status
= smb_raw_t2search_backend(tree
, mem_ctx
,
761 io
->generic
.data_level
,
762 io
->t2ffirst
.in
.flags
, io
->t2ffirst
.out
.count
,
763 &d_blob
, private_data
, callback
);
768 /* Implements trans2findnext2 and old smbsearch
770 NTSTATUS
smb_raw_search_next(struct smbcli_tree
*tree
,
772 union smb_search_next
*io
, void *private_data
,
773 smbcli_search_callback callback
)
775 DATA_BLOB p_blob
, d_blob
;
778 switch (io
->generic
.level
) {
779 case RAW_SEARCH_SEARCH
:
780 case RAW_SEARCH_FFIRST
:
781 return smb_raw_search_next_old(tree
, mem_ctx
, io
, private_data
, callback
);
783 case RAW_SEARCH_FUNIQUE
:
784 return NT_STATUS_INVALID_LEVEL
;
786 case RAW_SEARCH_TRANS2
:
789 case RAW_SEARCH_SMB2
:
790 return NT_STATUS_INVALID_LEVEL
;
793 status
= smb_raw_search_next_blob(tree
, mem_ctx
,
794 io
, &p_blob
, &d_blob
);
795 if (!NT_STATUS_IS_OK(status
)) {
799 if (p_blob
.length
!= 8) {
800 DEBUG(1,("smb_raw_search_next: parms wrong size %d != expected_param_size\n",
801 (int)p_blob
.length
));
802 return NT_STATUS_INVALID_PARAMETER
;
805 /* process output data */
806 io
->t2fnext
.out
.count
= SVAL(p_blob
.data
, 0);
807 io
->t2fnext
.out
.end_of_search
= SVAL(p_blob
.data
, 2);
809 status
= smb_raw_t2search_backend(tree
, mem_ctx
,
810 io
->generic
.data_level
,
811 io
->t2fnext
.in
.flags
, io
->t2fnext
.out
.count
,
812 &d_blob
, private_data
, callback
);
818 Implements trans2findclose2
820 NTSTATUS
smb_raw_search_close(struct smbcli_tree
*tree
,
821 union smb_search_close
*io
)
823 struct smbcli_request
*req
;
825 if (io
->generic
.level
== RAW_FINDCLOSE_FCLOSE
) {
826 return smb_raw_search_close_old(tree
, io
);
829 req
= smbcli_request_setup(tree
, SMBfindclose
, 1, 0);
831 return NT_STATUS_NO_MEMORY
;
834 SSVAL(req
->out
.vwv
, VWV(0), io
->findclose
.in
.handle
);
836 if (smbcli_request_send(req
)) {
837 (void) smbcli_request_receive(req
);
840 return smbcli_request_destroy(req
);