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"
24 /****************************************************************************
25 Old style search backend - process output.
26 ****************************************************************************/
27 static void smb_raw_search_backend(struct smbcli_request *req,
31 smbcli_search_callback callback)
34 union smb_search_data search_data;
38 if (req->in.data_size < 3 + count*43) {
39 req->status = NT_STATUS_INVALID_PARAMETER;
45 for (i=0; i < count; i++) {
48 search_data.search.id.reserved = CVAL(p, 0);
49 memcpy(search_data.search.id.name, p+1, 11);
50 search_data.search.id.handle = CVAL(p, 12);
51 search_data.search.id.server_cookie = IVAL(p, 13);
52 search_data.search.id.client_cookie = IVAL(p, 17);
53 search_data.search.attrib = CVAL(p, 21);
54 search_data.search.write_time = raw_pull_dos_date(req->transport,
56 search_data.search.size = IVAL(p, 26);
57 smbcli_req_pull_ascii(req, mem_ctx, &name, p+30, 13, STR_ASCII);
58 search_data.search.name = name;
59 if (!callback(private, &search_data)) {
66 /****************************************************************************
67 Old style search first.
68 ****************************************************************************/
69 static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
71 union smb_search_first *io, void *private,
72 smbcli_search_callback callback)
75 struct smbcli_request *req;
76 uint8_t op = SMBsearch;
78 if (io->generic.level == RAW_SEARCH_FFIRST) {
80 } else if (io->generic.level == RAW_SEARCH_FUNIQUE) {
84 req = smbcli_request_setup(tree, op, 2, 0);
86 return NT_STATUS_NO_MEMORY;
89 SSVAL(req->out.vwv, VWV(0), io->search_first.in.max_count);
90 SSVAL(req->out.vwv, VWV(1), io->search_first.in.search_attrib);
91 smbcli_req_append_ascii4(req, io->search_first.in.pattern, STR_TERMINATE);
92 smbcli_req_append_var_block(req, NULL, 0);
94 if (!smbcli_request_send(req) ||
95 !smbcli_request_receive(req)) {
96 return smbcli_request_destroy(req);
99 if (NT_STATUS_IS_OK(req->status)) {
100 io->search_first.out.count = SVAL(req->in.vwv, VWV(0));
101 smb_raw_search_backend(req, mem_ctx, io->search_first.out.count, private, callback);
104 return smbcli_request_destroy(req);
107 /****************************************************************************
108 Old style search next.
109 ****************************************************************************/
110 static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
112 union smb_search_next *io, void *private,
113 smbcli_search_callback callback)
116 struct smbcli_request *req;
117 uint8_t var_block[21];
118 uint8_t op = SMBsearch;
120 if (io->generic.level == RAW_SEARCH_FFIRST) {
124 req = smbcli_request_setup(tree, op, 2, 0);
126 return NT_STATUS_NO_MEMORY;
129 SSVAL(req->out.vwv, VWV(0), io->search_next.in.max_count);
130 SSVAL(req->out.vwv, VWV(1), io->search_next.in.search_attrib);
131 smbcli_req_append_ascii4(req, "", STR_TERMINATE);
133 SCVAL(var_block, 0, io->search_next.in.id.reserved);
134 memcpy(&var_block[1], io->search_next.in.id.name, 11);
135 SCVAL(var_block, 12, io->search_next.in.id.handle);
136 SIVAL(var_block, 13, io->search_next.in.id.server_cookie);
137 SIVAL(var_block, 17, io->search_next.in.id.client_cookie);
139 smbcli_req_append_var_block(req, var_block, 21);
141 if (!smbcli_request_send(req) ||
142 !smbcli_request_receive(req)) {
143 return smbcli_request_destroy(req);
146 if (NT_STATUS_IS_OK(req->status)) {
147 io->search_next.out.count = SVAL(req->in.vwv, VWV(0));
148 smb_raw_search_backend(req, mem_ctx, io->search_next.out.count, private, callback);
151 return smbcli_request_destroy(req);
155 /****************************************************************************
156 Old style search next.
157 ****************************************************************************/
158 static NTSTATUS smb_raw_search_close_old(struct smbcli_tree *tree,
159 union smb_search_close *io)
161 struct smbcli_request *req;
162 uint8_t var_block[21];
164 req = smbcli_request_setup(tree, SMBfclose, 2, 0);
166 return NT_STATUS_NO_MEMORY;
169 SSVAL(req->out.vwv, VWV(0), io->fclose.in.max_count);
170 SSVAL(req->out.vwv, VWV(1), io->fclose.in.search_attrib);
171 smbcli_req_append_ascii4(req, "", STR_TERMINATE);
173 SCVAL(var_block, 0, io->fclose.in.id.reserved);
174 memcpy(&var_block[1], io->fclose.in.id.name, 11);
175 SCVAL(var_block, 12, io->fclose.in.id.handle);
176 SIVAL(var_block, 13, io->fclose.in.id.server_cookie);
177 SIVAL(var_block, 17, io->fclose.in.id.client_cookie);
179 smbcli_req_append_var_block(req, var_block, 21);
181 if (!smbcli_request_send(req) ||
182 !smbcli_request_receive(req)) {
183 return smbcli_request_destroy(req);
186 return smbcli_request_destroy(req);
191 /****************************************************************************
192 Very raw search first - returns param/data blobs.
193 ****************************************************************************/
194 static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree,
195 TALLOC_CTX *mem_ctx, /* used to allocate output blobs */
196 union smb_search_first *io,
197 DATA_BLOB *out_param_blob,
198 DATA_BLOB *out_data_blob)
200 struct smb_trans2 tp;
201 uint16_t setup = TRANSACT2_FINDFIRST;
207 tp.in.setup_count = 1;
208 tp.in.data = data_blob(NULL, 0);
209 tp.in.max_param = 10;
210 tp.in.max_data = 0xFFFF;
211 tp.in.setup = &setup;
213 if (io->t2ffirst.level != RAW_SEARCH_TRANS2) {
214 return NT_STATUS_INVALID_LEVEL;
217 if (io->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
218 return NT_STATUS_INVALID_LEVEL;
221 if (io->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
222 if (!ea_push_name_list(mem_ctx,
224 io->t2ffirst.in.num_names,
225 io->t2ffirst.in.ea_names)) {
226 return NT_STATUS_NO_MEMORY;
230 tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
231 if (!tp.in.params.data) {
232 return NT_STATUS_NO_MEMORY;
235 SSVAL(tp.in.params.data, 0, io->t2ffirst.in.search_attrib);
236 SSVAL(tp.in.params.data, 2, io->t2ffirst.in.max_count);
237 SSVAL(tp.in.params.data, 4, io->t2ffirst.in.flags);
238 SSVAL(tp.in.params.data, 6, io->t2ffirst.data_level);
239 SIVAL(tp.in.params.data, 8, io->t2ffirst.in.storage_type);
241 smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
242 io->t2ffirst.in.pattern, STR_TERMINATE);
244 status = smb_raw_trans2(tree, mem_ctx, &tp);
245 if (!NT_STATUS_IS_OK(status)) {
249 out_param_blob->length = tp.out.params.length;
250 out_param_blob->data = tp.out.params.data;
251 out_data_blob->length = tp.out.data.length;
252 out_data_blob->data = tp.out.data.data;
258 /****************************************************************************
259 Very raw search first - returns param/data blobs.
260 Used in CIFS-on-CIFS NTVFS.
261 ****************************************************************************/
262 static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree,
264 union smb_search_next *io,
265 DATA_BLOB *out_param_blob,
266 DATA_BLOB *out_data_blob)
268 struct smb_trans2 tp;
269 uint16_t setup = TRANSACT2_FINDNEXT;
275 tp.in.setup_count = 1;
276 tp.in.data = data_blob(NULL, 0);
277 tp.in.max_param = 10;
278 tp.in.max_data = 0xFFFF;
279 tp.in.setup = &setup;
281 if (io->t2fnext.level != RAW_SEARCH_TRANS2) {
282 return NT_STATUS_INVALID_LEVEL;
285 if (io->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
286 return NT_STATUS_INVALID_LEVEL;
289 if (io->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
290 if (!ea_push_name_list(mem_ctx,
292 io->t2fnext.in.num_names,
293 io->t2fnext.in.ea_names)) {
294 return NT_STATUS_NO_MEMORY;
298 tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
299 if (!tp.in.params.data) {
300 return NT_STATUS_NO_MEMORY;
303 SSVAL(tp.in.params.data, 0, io->t2fnext.in.handle);
304 SSVAL(tp.in.params.data, 2, io->t2fnext.in.max_count);
305 SSVAL(tp.in.params.data, 4, io->t2fnext.data_level);
306 SIVAL(tp.in.params.data, 6, io->t2fnext.in.resume_key);
307 SSVAL(tp.in.params.data, 10, io->t2fnext.in.flags);
309 smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
310 io->t2fnext.in.last_name,
313 status = smb_raw_trans2(tree, mem_ctx, &tp);
314 if (!NT_STATUS_IS_OK(status)) {
318 out_param_blob->length = tp.out.params.length;
319 out_param_blob->data = tp.out.params.data;
320 out_data_blob->length = tp.out.data.length;
321 out_data_blob->data = tp.out.data.data;
328 parse the wire search formats that are in common between SMB and
331 NTSTATUS smb_raw_search_common(TALLOC_CTX *mem_ctx,
332 enum smb_search_data_level level,
333 const DATA_BLOB *blob,
334 union smb_search_data *data,
340 if (blob->length < 4) {
341 return NT_STATUS_INFO_LENGTH_MISMATCH;
344 *next_ofs = IVAL(blob->data, 0);
345 if (*next_ofs != 0) {
352 case RAW_SEARCH_DATA_DIRECTORY_INFO:
353 if (blen < 65) return NT_STATUS_INFO_LENGTH_MISMATCH;
354 data->directory_info.file_index = IVAL(blob->data, 4);
355 data->directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
356 data->directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
357 data->directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
358 data->directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
359 data->directory_info.size = BVAL(blob->data, 40);
360 data->directory_info.alloc_size = BVAL(blob->data, 48);
361 data->directory_info.attrib = IVAL(blob->data, 56);
362 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
363 &data->directory_info.name,
365 if (*next_ofs != 0 && *next_ofs < 64+len) {
366 return NT_STATUS_INFO_LENGTH_MISMATCH;
370 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
371 if (blen < 69) return NT_STATUS_INFO_LENGTH_MISMATCH;
372 data->full_directory_info.file_index = IVAL(blob->data, 4);
373 data->full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
374 data->full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
375 data->full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
376 data->full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
377 data->full_directory_info.size = BVAL(blob->data, 40);
378 data->full_directory_info.alloc_size = BVAL(blob->data, 48);
379 data->full_directory_info.attrib = IVAL(blob->data, 56);
380 data->full_directory_info.ea_size = IVAL(blob->data, 64);
381 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
382 &data->full_directory_info.name,
384 if (*next_ofs != 0 && *next_ofs < 68+len) {
385 return NT_STATUS_INFO_LENGTH_MISMATCH;
389 case RAW_SEARCH_DATA_NAME_INFO:
390 if (blen < 13) return NT_STATUS_INFO_LENGTH_MISMATCH;
391 data->name_info.file_index = IVAL(blob->data, 4);
392 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
393 &data->name_info.name,
395 if (*next_ofs != 0 && *next_ofs < 12+len) {
396 return NT_STATUS_INFO_LENGTH_MISMATCH;
401 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
402 if (blen < 95) return NT_STATUS_INFO_LENGTH_MISMATCH;
403 data->both_directory_info.file_index = IVAL(blob->data, 4);
404 data->both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
405 data->both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
406 data->both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
407 data->both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
408 data->both_directory_info.size = BVAL(blob->data, 40);
409 data->both_directory_info.alloc_size = BVAL(blob->data, 48);
410 data->both_directory_info.attrib = IVAL(blob->data, 56);
411 data->both_directory_info.ea_size = IVAL(blob->data, 64);
412 smbcli_blob_pull_string(NULL, mem_ctx, blob,
413 &data->both_directory_info.short_name,
414 68, 70, STR_LEN8BIT | STR_UNICODE);
415 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
416 &data->both_directory_info.name,
418 if (*next_ofs != 0 && *next_ofs < 94+len) {
419 return NT_STATUS_INFO_LENGTH_MISMATCH;
424 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
425 if (blen < 81) return NT_STATUS_INFO_LENGTH_MISMATCH;
426 data->id_full_directory_info.file_index = IVAL(blob->data, 4);
427 data->id_full_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
428 data->id_full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
429 data->id_full_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
430 data->id_full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
431 data->id_full_directory_info.size = BVAL(blob->data, 40);
432 data->id_full_directory_info.alloc_size = BVAL(blob->data, 48);
433 data->id_full_directory_info.attrib = IVAL(blob->data, 56);
434 data->id_full_directory_info.ea_size = IVAL(blob->data, 64);
435 data->id_full_directory_info.file_id = BVAL(blob->data, 72);
436 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
437 &data->id_full_directory_info.name,
439 if (*next_ofs != 0 && *next_ofs < 80+len) {
440 return NT_STATUS_INFO_LENGTH_MISMATCH;
444 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
445 if (blen < 105) return NT_STATUS_INFO_LENGTH_MISMATCH;
446 data->id_both_directory_info.file_index = IVAL(blob->data, 4);
447 data->id_both_directory_info.create_time = smbcli_pull_nttime(blob->data, 8);
448 data->id_both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
449 data->id_both_directory_info.write_time = smbcli_pull_nttime(blob->data, 24);
450 data->id_both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
451 data->id_both_directory_info.size = BVAL(blob->data, 40);
452 data->id_both_directory_info.alloc_size = BVAL(blob->data, 48);
453 data->id_both_directory_info.attrib = SVAL(blob->data, 56);
454 data->id_both_directory_info.ea_size = IVAL(blob->data, 64);
455 smbcli_blob_pull_string(NULL, mem_ctx, blob,
456 &data->id_both_directory_info.short_name,
457 68, 70, STR_LEN8BIT | STR_UNICODE);
458 data->id_both_directory_info.file_id = BVAL(blob->data, 96);
459 len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
460 &data->id_both_directory_info.name,
462 if (*next_ofs != 0 && *next_ofs < 104+len) {
463 return NT_STATUS_INFO_LENGTH_MISMATCH;
472 return NT_STATUS_INVALID_INFO_CLASS;
477 parse a trans2 search response.
478 Return the number of bytes consumed
479 return 0 for success with end of list
480 return -1 for a parse error
482 static int parse_trans2_search(struct smbcli_tree *tree,
484 enum smb_search_data_level level,
487 union smb_search_data *data)
495 case RAW_SEARCH_DATA_GENERIC:
496 case RAW_SEARCH_DATA_SEARCH:
497 /* handled elsewhere */
500 case RAW_SEARCH_DATA_STANDARD:
501 if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
502 if (blob->length < 4) return -1;
503 data->standard.resume_key = IVAL(blob->data, 0);
507 if (blob->length < 24) return -1;
508 data->standard.create_time = raw_pull_dos_date2(tree->session->transport,
510 data->standard.access_time = raw_pull_dos_date2(tree->session->transport,
512 data->standard.write_time = raw_pull_dos_date2(tree->session->transport,
514 data->standard.size = IVAL(blob->data, 12);
515 data->standard.alloc_size = IVAL(blob->data, 16);
516 data->standard.attrib = SVAL(blob->data, 20);
517 len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
518 &data->standard.name,
519 22, 23, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
522 case RAW_SEARCH_DATA_EA_SIZE:
523 if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
524 if (blob->length < 4) return -1;
525 data->ea_size.resume_key = IVAL(blob->data, 0);
529 if (blob->length < 28) return -1;
530 data->ea_size.create_time = raw_pull_dos_date2(tree->session->transport,
532 data->ea_size.access_time = raw_pull_dos_date2(tree->session->transport,
534 data->ea_size.write_time = raw_pull_dos_date2(tree->session->transport,
536 data->ea_size.size = IVAL(blob->data, 12);
537 data->ea_size.alloc_size = IVAL(blob->data, 16);
538 data->ea_size.attrib = SVAL(blob->data, 20);
539 data->ea_size.ea_size = IVAL(blob->data, 22);
540 len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
542 26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN);
545 case RAW_SEARCH_DATA_EA_LIST:
546 if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
547 if (blob->length < 4) return -1;
548 data->ea_list.resume_key = IVAL(blob->data, 0);
552 if (blob->length < 28) return -1;
553 data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport,
555 data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport,
557 data->ea_list.write_time = raw_pull_dos_date2(tree->session->transport,
559 data->ea_list.size = IVAL(blob->data, 12);
560 data->ea_list.alloc_size = IVAL(blob->data, 16);
561 data->ea_list.attrib = SVAL(blob->data, 20);
562 ea_size = IVAL(blob->data, 22);
563 if (ea_size > 0xFFFF) {
566 eablob.data = blob->data + 22;
567 eablob.length = ea_size;
568 if (eablob.length > blob->length - 24) {
571 status = ea_pull_list(&eablob, mem_ctx,
572 &data->ea_list.eas.num_eas,
573 &data->ea_list.eas.eas);
574 if (!NT_STATUS_IS_OK(status)) {
577 len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
579 22+ea_size, 23+ea_size,
580 STR_LEN8BIT | STR_NOALIGN);
581 return len + ea_size + 23 + 1;
583 case RAW_SEARCH_DATA_UNIX_INFO:
584 if (blob->length < 109) return -1;
585 ofs = IVAL(blob->data, 0);
586 data->unix_info.file_index = IVAL(blob->data, 4);
587 data->unix_info.size = BVAL(blob->data, 8);
588 data->unix_info.alloc_size = BVAL(blob->data, 16);
589 data->unix_info.status_change_time = smbcli_pull_nttime(blob->data, 24);
590 data->unix_info.access_time = smbcli_pull_nttime(blob->data, 32);
591 data->unix_info.change_time = smbcli_pull_nttime(blob->data, 40);
592 data->unix_info.uid = IVAL(blob->data, 48);
593 data->unix_info.gid = IVAL(blob->data, 56);
594 data->unix_info.file_type = IVAL(blob->data, 64);
595 data->unix_info.dev_major = BVAL(blob->data, 68);
596 data->unix_info.dev_minor = BVAL(blob->data, 76);
597 data->unix_info.unique_id = BVAL(blob->data, 84);
598 data->unix_info.permissions = IVAL(blob->data, 92);
599 data->unix_info.nlink = IVAL(blob->data, 100);
600 /* There is no length field for this name but we know it's null terminated. */
601 len = smbcli_blob_pull_unix_string(tree->session, mem_ctx, blob,
602 &data->unix_info.name, 108, 0);
603 if (ofs != 0 && ofs < 108+len) {
608 case RAW_SEARCH_DATA_UNIX_INFO2:
609 /* 8 - size of ofs + file_index
610 * 116 - size of unix_info2
611 * 4 - size of name length
612 * 2 - "." is the shortest name
614 if (blob->length < (116 + 8 + 4 + 2)) {
618 ofs = IVAL(blob->data, 0);
619 data->unix_info2.file_index = IVAL(blob->data, 4);
620 data->unix_info2.end_of_file = BVAL(blob->data, 8);
621 data->unix_info2.num_bytes = BVAL(blob->data, 16);
622 data->unix_info2.status_change_time = smbcli_pull_nttime(blob->data, 24);
623 data->unix_info2.access_time = smbcli_pull_nttime(blob->data, 32);
624 data->unix_info2.change_time = smbcli_pull_nttime(blob->data, 40);
625 data->unix_info2.uid = IVAL(blob->data, 48);
626 data->unix_info2.gid = IVAL(blob->data, 56);
627 data->unix_info2.file_type = IVAL(blob->data, 64);
628 data->unix_info2.dev_major = BVAL(blob->data, 68);
629 data->unix_info2.dev_minor = BVAL(blob->data, 76);
630 data->unix_info2.unique_id = BVAL(blob->data, 84);
631 data->unix_info2.permissions = IVAL(blob->data, 92);
632 data->unix_info2.nlink = IVAL(blob->data, 100);
633 data->unix_info2.create_time = smbcli_pull_nttime(blob->data, 108);
634 data->unix_info2.file_flags = IVAL(blob->data, 116);
635 data->unix_info2.flags_mask = IVAL(blob->data, 120);
637 /* There is a 4 byte length field for this name. The length
638 * does not include the NULL terminator.
640 len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
641 &data->unix_info2.name,
642 8 + 116, /* offset to length */
643 8 + 116 + 4, /* offset to string */
646 if (ofs != 0 && ofs < (8 + 116 + 4 + len)) {
652 case RAW_SEARCH_DATA_DIRECTORY_INFO:
653 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
654 case RAW_SEARCH_DATA_NAME_INFO:
655 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
656 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
657 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: {
658 uint_t str_flags = STR_UNICODE;
659 if (!(tree->session->transport->negotiate.capabilities & CAP_UNICODE)) {
660 str_flags = STR_ASCII;
663 status = smb_raw_search_common(mem_ctx, level, blob, data, &ofs, str_flags);
664 if (!NT_STATUS_IS_OK(status)) {
675 /****************************************************************************
676 Trans2 search backend - process output.
677 ****************************************************************************/
678 static NTSTATUS smb_raw_t2search_backend(struct smbcli_tree *tree,
680 enum smb_search_data_level level,
685 smbcli_search_callback callback)
691 blob2.data = blob->data;
692 blob2.length = blob->length;
694 for (i=0; i < count; i++) {
695 union smb_search_data search_data;
698 len = parse_trans2_search(tree, mem_ctx, level, flags, &blob2, &search_data);
700 return NT_STATUS_INVALID_PARAMETER;
703 /* the callback function can tell us that no more will
704 fit - in that case we stop, but it isn't an error */
705 if (!callback(private, &search_data)) {
719 /* Implements trans2findfirst2 and old search
721 NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
723 union smb_search_first *io, void *private,
724 smbcli_search_callback callback)
726 DATA_BLOB p_blob, d_blob;
729 switch (io->generic.level) {
730 case RAW_SEARCH_SEARCH:
731 case RAW_SEARCH_FFIRST:
732 case RAW_SEARCH_FUNIQUE:
733 return smb_raw_search_first_old(tree, mem_ctx, io, private, callback);
735 case RAW_SEARCH_TRANS2:
738 case RAW_SEARCH_SMB2:
739 return NT_STATUS_INVALID_LEVEL;
742 status = smb_raw_search_first_blob(tree, mem_ctx,
743 io, &p_blob, &d_blob);
744 if (!NT_STATUS_IS_OK(status)) {
748 if (p_blob.length < 10) {
749 DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n",
750 (int)p_blob.length));
751 return NT_STATUS_INVALID_PARAMETER;
754 /* process output data */
755 io->t2ffirst.out.handle = SVAL(p_blob.data, 0);
756 io->t2ffirst.out.count = SVAL(p_blob.data, 2);
757 io->t2ffirst.out.end_of_search = SVAL(p_blob.data, 4);
759 status = smb_raw_t2search_backend(tree, mem_ctx,
760 io->generic.data_level,
761 io->t2ffirst.in.flags, io->t2ffirst.out.count,
762 &d_blob, private, callback);
767 /* Implements trans2findnext2 and old smbsearch
769 NTSTATUS smb_raw_search_next(struct smbcli_tree *tree,
771 union smb_search_next *io, void *private,
772 smbcli_search_callback callback)
774 DATA_BLOB p_blob, d_blob;
777 switch (io->generic.level) {
778 case RAW_SEARCH_SEARCH:
779 case RAW_SEARCH_FFIRST:
780 return smb_raw_search_next_old(tree, mem_ctx, io, private, callback);
782 case RAW_SEARCH_FUNIQUE:
783 return NT_STATUS_INVALID_LEVEL;
785 case RAW_SEARCH_TRANS2:
788 case RAW_SEARCH_SMB2:
789 return NT_STATUS_INVALID_LEVEL;
792 status = smb_raw_search_next_blob(tree, mem_ctx,
793 io, &p_blob, &d_blob);
794 if (!NT_STATUS_IS_OK(status)) {
798 if (p_blob.length != 8) {
799 DEBUG(1,("smb_raw_search_next: parms wrong size %d != expected_param_size\n",
800 (int)p_blob.length));
801 return NT_STATUS_INVALID_PARAMETER;
804 /* process output data */
805 io->t2fnext.out.count = SVAL(p_blob.data, 0);
806 io->t2fnext.out.end_of_search = SVAL(p_blob.data, 2);
808 status = smb_raw_t2search_backend(tree, mem_ctx,
809 io->generic.data_level,
810 io->t2fnext.in.flags, io->t2fnext.out.count,
811 &d_blob, private, callback);
817 Implements trans2findclose2
819 NTSTATUS smb_raw_search_close(struct smbcli_tree *tree,
820 union smb_search_close *io)
822 struct smbcli_request *req;
824 if (io->generic.level == RAW_FINDCLOSE_FCLOSE) {
825 return smb_raw_search_close_old(tree, io);
828 req = smbcli_request_setup(tree, SMBfindclose, 1, 0);
830 return NT_STATUS_NO_MEMORY;
833 SSVAL(req->out.vwv, VWV(0), io->findclose.in.handle);
835 if (smbcli_request_send(req)) {
836 (void) smbcli_request_receive(req);
839 return smbcli_request_destroy(req);