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 memcpy(data
->id_both_directory_info
.short_name_buf
, blob
->data
+ 70, 24);
460 data
->id_both_directory_info
.file_id
= BVAL(blob
->data
, 96);
461 len
= smbcli_blob_pull_string(NULL
, mem_ctx
, blob
,
462 &data
->id_both_directory_info
.name
,
464 if (*next_ofs
!= 0 && *next_ofs
< 104+len
) {
465 return NT_STATUS_INFO_LENGTH_MISMATCH
;
474 return NT_STATUS_INVALID_INFO_CLASS
;
479 parse a trans2 search response.
480 Return the number of bytes consumed
481 return 0 for success with end of list
482 return -1 for a parse error
484 static int parse_trans2_search(struct smbcli_tree
*tree
,
486 enum smb_search_data_level level
,
489 union smb_search_data
*data
)
491 unsigned int len
, ofs
;
497 case RAW_SEARCH_DATA_GENERIC
:
498 case RAW_SEARCH_DATA_SEARCH
:
499 /* handled elsewhere */
502 case RAW_SEARCH_DATA_STANDARD
:
503 if (flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
504 if (blob
->length
< 4) return -1;
505 data
->standard
.resume_key
= IVAL(blob
->data
, 0);
509 if (blob
->length
< 24) return -1;
510 data
->standard
.create_time
= raw_pull_dos_date2(tree
->session
->transport
,
512 data
->standard
.access_time
= raw_pull_dos_date2(tree
->session
->transport
,
514 data
->standard
.write_time
= raw_pull_dos_date2(tree
->session
->transport
,
516 data
->standard
.size
= IVAL(blob
->data
, 12);
517 data
->standard
.alloc_size
= IVAL(blob
->data
, 16);
518 data
->standard
.attrib
= SVAL(blob
->data
, 20);
519 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
520 &data
->standard
.name
,
521 22, 23, STR_LEN8BIT
| STR_TERMINATE
| STR_LEN_NOTERM
);
524 case RAW_SEARCH_DATA_EA_SIZE
:
525 if (flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
526 if (blob
->length
< 4) return -1;
527 data
->ea_size
.resume_key
= IVAL(blob
->data
, 0);
531 if (blob
->length
< 28) return -1;
532 data
->ea_size
.create_time
= raw_pull_dos_date2(tree
->session
->transport
,
534 data
->ea_size
.access_time
= raw_pull_dos_date2(tree
->session
->transport
,
536 data
->ea_size
.write_time
= raw_pull_dos_date2(tree
->session
->transport
,
538 data
->ea_size
.size
= IVAL(blob
->data
, 12);
539 data
->ea_size
.alloc_size
= IVAL(blob
->data
, 16);
540 data
->ea_size
.attrib
= SVAL(blob
->data
, 20);
541 data
->ea_size
.ea_size
= IVAL(blob
->data
, 22);
542 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
544 26, 27, STR_LEN8BIT
| STR_TERMINATE
| STR_NOALIGN
);
547 case RAW_SEARCH_DATA_EA_LIST
:
548 if (flags
& FLAG_TRANS2_FIND_REQUIRE_RESUME
) {
549 if (blob
->length
< 4) return -1;
550 data
->ea_list
.resume_key
= IVAL(blob
->data
, 0);
554 if (blob
->length
< 28) return -1;
555 data
->ea_list
.create_time
= raw_pull_dos_date2(tree
->session
->transport
,
557 data
->ea_list
.access_time
= raw_pull_dos_date2(tree
->session
->transport
,
559 data
->ea_list
.write_time
= raw_pull_dos_date2(tree
->session
->transport
,
561 data
->ea_list
.size
= IVAL(blob
->data
, 12);
562 data
->ea_list
.alloc_size
= IVAL(blob
->data
, 16);
563 data
->ea_list
.attrib
= SVAL(blob
->data
, 20);
564 ea_size
= IVAL(blob
->data
, 22);
565 if (ea_size
> 0xFFFF) {
568 eablob
.data
= blob
->data
+ 22;
569 eablob
.length
= ea_size
;
570 if (eablob
.length
> blob
->length
- 24) {
573 status
= ea_pull_list(&eablob
, mem_ctx
,
574 &data
->ea_list
.eas
.num_eas
,
575 &data
->ea_list
.eas
.eas
);
576 if (!NT_STATUS_IS_OK(status
)) {
579 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
581 22+ea_size
, 23+ea_size
,
582 STR_LEN8BIT
| STR_NOALIGN
);
583 return len
+ ea_size
+ 23 + 1;
585 case RAW_SEARCH_DATA_UNIX_INFO
:
586 if (blob
->length
< 109) return -1;
587 ofs
= IVAL(blob
->data
, 0);
588 data
->unix_info
.file_index
= IVAL(blob
->data
, 4);
589 data
->unix_info
.size
= BVAL(blob
->data
, 8);
590 data
->unix_info
.alloc_size
= BVAL(blob
->data
, 16);
591 data
->unix_info
.status_change_time
= smbcli_pull_nttime(blob
->data
, 24);
592 data
->unix_info
.access_time
= smbcli_pull_nttime(blob
->data
, 32);
593 data
->unix_info
.change_time
= smbcli_pull_nttime(blob
->data
, 40);
594 data
->unix_info
.uid
= IVAL(blob
->data
, 48);
595 data
->unix_info
.gid
= IVAL(blob
->data
, 56);
596 data
->unix_info
.file_type
= IVAL(blob
->data
, 64);
597 data
->unix_info
.dev_major
= BVAL(blob
->data
, 68);
598 data
->unix_info
.dev_minor
= BVAL(blob
->data
, 76);
599 data
->unix_info
.unique_id
= BVAL(blob
->data
, 84);
600 data
->unix_info
.permissions
= IVAL(blob
->data
, 92);
601 data
->unix_info
.nlink
= IVAL(blob
->data
, 100);
602 /* There is no length field for this name but we know it's null terminated. */
603 len
= smbcli_blob_pull_unix_string(tree
->session
, mem_ctx
, blob
,
604 &data
->unix_info
.name
, 108, 0);
605 if (ofs
!= 0 && ofs
< 108+len
) {
610 case RAW_SEARCH_DATA_UNIX_INFO2
:
611 /* 8 - size of ofs + file_index
612 * 116 - size of unix_info2
613 * 4 - size of name length
614 * 2 - "." is the shortest name
616 if (blob
->length
< (116 + 8 + 4 + 2)) {
620 ofs
= IVAL(blob
->data
, 0);
621 data
->unix_info2
.file_index
= IVAL(blob
->data
, 4);
622 data
->unix_info2
.end_of_file
= BVAL(blob
->data
, 8);
623 data
->unix_info2
.num_bytes
= BVAL(blob
->data
, 16);
624 data
->unix_info2
.status_change_time
= smbcli_pull_nttime(blob
->data
, 24);
625 data
->unix_info2
.access_time
= smbcli_pull_nttime(blob
->data
, 32);
626 data
->unix_info2
.change_time
= smbcli_pull_nttime(blob
->data
, 40);
627 data
->unix_info2
.uid
= IVAL(blob
->data
, 48);
628 data
->unix_info2
.gid
= IVAL(blob
->data
, 56);
629 data
->unix_info2
.file_type
= IVAL(blob
->data
, 64);
630 data
->unix_info2
.dev_major
= BVAL(blob
->data
, 68);
631 data
->unix_info2
.dev_minor
= BVAL(blob
->data
, 76);
632 data
->unix_info2
.unique_id
= BVAL(blob
->data
, 84);
633 data
->unix_info2
.permissions
= IVAL(blob
->data
, 92);
634 data
->unix_info2
.nlink
= IVAL(blob
->data
, 100);
635 data
->unix_info2
.create_time
= smbcli_pull_nttime(blob
->data
, 108);
636 data
->unix_info2
.file_flags
= IVAL(blob
->data
, 116);
637 data
->unix_info2
.flags_mask
= IVAL(blob
->data
, 120);
639 /* There is a 4 byte length field for this name. The length
640 * does not include the NULL terminator.
642 len
= smbcli_blob_pull_string(tree
->session
, mem_ctx
, blob
,
643 &data
->unix_info2
.name
,
644 8 + 116, /* offset to length */
645 8 + 116 + 4, /* offset to string */
648 if (ofs
!= 0 && ofs
< (8 + 116 + 4 + len
)) {
654 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
655 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
656 case RAW_SEARCH_DATA_NAME_INFO
:
657 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
658 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
659 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
: {
660 unsigned int str_flags
= STR_UNICODE
;
661 if (!(tree
->session
->transport
->negotiate
.capabilities
& CAP_UNICODE
)) {
662 str_flags
= STR_ASCII
;
665 status
= smb_raw_search_common(mem_ctx
, level
, blob
, data
, &ofs
, str_flags
);
666 if (!NT_STATUS_IS_OK(status
)) {
677 /****************************************************************************
678 Trans2 search backend - process output.
679 ****************************************************************************/
680 static NTSTATUS
smb_raw_t2search_backend(struct smbcli_tree
*tree
,
682 enum smb_search_data_level level
,
687 smbcli_search_callback callback
)
693 blob2
.data
= blob
->data
;
694 blob2
.length
= blob
->length
;
696 for (i
=0; i
< count
; i
++) {
697 union smb_search_data search_data
;
700 len
= parse_trans2_search(tree
, mem_ctx
, level
, flags
, &blob2
, &search_data
);
702 return NT_STATUS_INVALID_PARAMETER
;
705 /* the callback function can tell us that no more will
706 fit - in that case we stop, but it isn't an error */
707 if (!callback(private_data
, &search_data
)) {
721 /* Implements trans2findfirst2 and old search
723 _PUBLIC_ NTSTATUS
smb_raw_search_first(struct smbcli_tree
*tree
,
725 union smb_search_first
*io
, void *private_data
,
726 smbcli_search_callback callback
)
728 DATA_BLOB p_blob
= data_blob_null
, d_blob
= data_blob_null
;
731 switch (io
->generic
.level
) {
732 case RAW_SEARCH_SEARCH
:
733 case RAW_SEARCH_FFIRST
:
734 case RAW_SEARCH_FUNIQUE
:
735 return smb_raw_search_first_old(tree
, mem_ctx
, io
, private_data
, callback
);
737 case RAW_SEARCH_TRANS2
:
740 case RAW_SEARCH_SMB2
:
741 return NT_STATUS_INVALID_LEVEL
;
744 status
= smb_raw_search_first_blob(tree
, mem_ctx
,
745 io
, &p_blob
, &d_blob
);
746 if (!NT_STATUS_IS_OK(status
)) {
750 if (p_blob
.length
< 10) {
751 DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n",
752 (int)p_blob
.length
));
753 return NT_STATUS_INVALID_PARAMETER
;
756 /* process output data */
757 io
->t2ffirst
.out
.handle
= SVAL(p_blob
.data
, 0);
758 io
->t2ffirst
.out
.count
= SVAL(p_blob
.data
, 2);
759 io
->t2ffirst
.out
.end_of_search
= SVAL(p_blob
.data
, 4);
761 status
= smb_raw_t2search_backend(tree
, mem_ctx
,
762 io
->generic
.data_level
,
763 io
->t2ffirst
.in
.flags
, io
->t2ffirst
.out
.count
,
764 &d_blob
, private_data
, callback
);
769 /* Implements trans2findnext2 and old smbsearch
771 NTSTATUS
smb_raw_search_next(struct smbcli_tree
*tree
,
773 union smb_search_next
*io
, void *private_data
,
774 smbcli_search_callback callback
)
776 DATA_BLOB p_blob
= data_blob_null
, d_blob
= data_blob_null
;
779 switch (io
->generic
.level
) {
780 case RAW_SEARCH_SEARCH
:
781 case RAW_SEARCH_FFIRST
:
782 return smb_raw_search_next_old(tree
, mem_ctx
, io
, private_data
, callback
);
784 case RAW_SEARCH_FUNIQUE
:
785 return NT_STATUS_INVALID_LEVEL
;
787 case RAW_SEARCH_TRANS2
:
790 case RAW_SEARCH_SMB2
:
791 return NT_STATUS_INVALID_LEVEL
;
794 status
= smb_raw_search_next_blob(tree
, mem_ctx
,
795 io
, &p_blob
, &d_blob
);
796 if (!NT_STATUS_IS_OK(status
)) {
800 if (p_blob
.length
!= 8) {
801 DEBUG(1,("smb_raw_search_next: parms wrong size %d != expected_param_size\n",
802 (int)p_blob
.length
));
803 return NT_STATUS_INVALID_PARAMETER
;
806 /* process output data */
807 io
->t2fnext
.out
.count
= SVAL(p_blob
.data
, 0);
808 io
->t2fnext
.out
.end_of_search
= SVAL(p_blob
.data
, 2);
810 status
= smb_raw_t2search_backend(tree
, mem_ctx
,
811 io
->generic
.data_level
,
812 io
->t2fnext
.in
.flags
, io
->t2fnext
.out
.count
,
813 &d_blob
, private_data
, callback
);
819 Implements trans2findclose2
821 NTSTATUS
smb_raw_search_close(struct smbcli_tree
*tree
,
822 union smb_search_close
*io
)
824 struct smbcli_request
*req
;
826 if (io
->generic
.level
== RAW_FINDCLOSE_FCLOSE
) {
827 return smb_raw_search_close_old(tree
, io
);
830 req
= smbcli_request_setup(tree
, SMBfindclose
, 1, 0);
832 return NT_STATUS_NO_MEMORY
;
835 SSVAL(req
->out
.vwv
, VWV(0), io
->findclose
.in
.handle
);
837 if (smbcli_request_send(req
)) {
838 (void) smbcli_request_receive(req
);
841 return smbcli_request_destroy(req
);