• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/libcli/raw/
1/*
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
6
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.
11
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.
16
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/>.
19*/
20
21#include "includes.h"
22#include "libcli/raw/libcliraw.h"
23#include "libcli/raw/raw_proto.h"
24
25/****************************************************************************
26 Old style search backend - process output.
27****************************************************************************/
28static void smb_raw_search_backend(struct smbcli_request *req,
29				   TALLOC_CTX *mem_ctx,
30				   uint16_t count,
31				   void *private_data,
32				   smbcli_search_callback callback)
33
34{
35	union smb_search_data search_data;
36	int i;
37	uint8_t *p;
38
39	if (req->in.data_size < 3 + count*43) {
40		req->status = NT_STATUS_INVALID_PARAMETER;
41		return;
42	}
43
44	p = req->in.data + 3;
45
46	for (i=0; i < count; i++) {
47		char *name;
48
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,
56									p + 22);
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)) {
61			break;
62		}
63		p += 43;
64	}
65}
66
67/****************************************************************************
68 Old style search first.
69****************************************************************************/
70static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
71					 TALLOC_CTX *mem_ctx,
72					 union smb_search_first *io, void *private_data,
73					 smbcli_search_callback callback)
74
75{
76	struct smbcli_request *req;
77	uint8_t op = SMBsearch;
78
79	if (io->generic.level == RAW_SEARCH_FFIRST) {
80		op = SMBffirst;
81	} else if (io->generic.level == RAW_SEARCH_FUNIQUE) {
82		op = SMBfunique;
83	}
84
85	req = smbcli_request_setup(tree, op, 2, 0);
86	if (!req) {
87		return NT_STATUS_NO_MEMORY;
88	}
89
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);
94
95	if (!smbcli_request_send(req) ||
96	    !smbcli_request_receive(req)) {
97		return smbcli_request_destroy(req);
98	}
99
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);
103	}
104
105	return smbcli_request_destroy(req);
106}
107
108/****************************************************************************
109 Old style search next.
110****************************************************************************/
111static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
112					TALLOC_CTX *mem_ctx,
113					union smb_search_next *io, void *private_data,
114					smbcli_search_callback callback)
115
116{
117	struct smbcli_request *req;
118	uint8_t var_block[21];
119	uint8_t op = SMBsearch;
120
121	if (io->generic.level == RAW_SEARCH_FFIRST) {
122		op = SMBffirst;
123	}
124
125	req = smbcli_request_setup(tree, op, 2, 0);
126	if (!req) {
127		return NT_STATUS_NO_MEMORY;
128	}
129
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);
133
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);
139
140	smbcli_req_append_var_block(req, var_block, 21);
141
142	if (!smbcli_request_send(req) ||
143	    !smbcli_request_receive(req)) {
144		return smbcli_request_destroy(req);
145	}
146
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);
150	}
151
152	return smbcli_request_destroy(req);
153}
154
155
156/****************************************************************************
157 Old style search next.
158****************************************************************************/
159static NTSTATUS smb_raw_search_close_old(struct smbcli_tree *tree,
160					 union smb_search_close *io)
161{
162	struct smbcli_request *req;
163	uint8_t var_block[21];
164
165	req = smbcli_request_setup(tree, SMBfclose, 2, 0);
166	if (!req) {
167		return NT_STATUS_NO_MEMORY;
168	}
169
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);
173
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);
179
180	smbcli_req_append_var_block(req, var_block, 21);
181
182	if (!smbcli_request_send(req) ||
183	    !smbcli_request_receive(req)) {
184		return smbcli_request_destroy(req);
185	}
186
187	return smbcli_request_destroy(req);
188}
189
190
191
192/****************************************************************************
193 Very raw search first - returns param/data blobs.
194****************************************************************************/
195static 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)
200{
201	struct smb_trans2 tp;
202	uint16_t setup = TRANSACT2_FINDFIRST;
203	NTSTATUS status;
204
205	tp.in.max_setup = 0;
206	tp.in.flags = 0;
207	tp.in.timeout = 0;
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;
213
214	if (io->t2ffirst.level != RAW_SEARCH_TRANS2) {
215		return NT_STATUS_INVALID_LEVEL;
216	}
217
218	if (io->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
219		return NT_STATUS_INVALID_LEVEL;
220	}
221
222	if (io->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
223		if (!ea_push_name_list(mem_ctx,
224				       &tp.in.data,
225				       io->t2ffirst.in.num_names,
226				       io->t2ffirst.in.ea_names)) {
227			return NT_STATUS_NO_MEMORY;
228		}
229	}
230
231	tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
232	if (!tp.in.params.data) {
233		return NT_STATUS_NO_MEMORY;
234	}
235
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);
241
242	smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
243				  io->t2ffirst.in.pattern, STR_TERMINATE);
244
245	status = smb_raw_trans2(tree, mem_ctx, &tp);
246	if (!NT_STATUS_IS_OK(status)) {
247		return status;
248	}
249
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;
254
255	return NT_STATUS_OK;
256}
257
258
259/****************************************************************************
260 Very raw search first - returns param/data blobs.
261 Used in CIFS-on-CIFS NTVFS.
262****************************************************************************/
263static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree,
264					 TALLOC_CTX *mem_ctx,
265					 union smb_search_next *io,
266					 DATA_BLOB *out_param_blob,
267					 DATA_BLOB *out_data_blob)
268{
269	struct smb_trans2 tp;
270	uint16_t setup = TRANSACT2_FINDNEXT;
271	NTSTATUS status;
272
273	tp.in.max_setup = 0;
274	tp.in.flags = 0;
275	tp.in.timeout = 0;
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;
281
282	if (io->t2fnext.level != RAW_SEARCH_TRANS2) {
283		return NT_STATUS_INVALID_LEVEL;
284	}
285
286	if (io->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
287		return NT_STATUS_INVALID_LEVEL;
288	}
289
290	if (io->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
291		if (!ea_push_name_list(mem_ctx,
292				       &tp.in.data,
293				       io->t2fnext.in.num_names,
294				       io->t2fnext.in.ea_names)) {
295			return NT_STATUS_NO_MEMORY;
296		}
297	}
298
299	tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
300	if (!tp.in.params.data) {
301		return NT_STATUS_NO_MEMORY;
302	}
303
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);
309
310	smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
311			       io->t2fnext.in.last_name,
312			       STR_TERMINATE);
313
314	status = smb_raw_trans2(tree, mem_ctx, &tp);
315	if (!NT_STATUS_IS_OK(status)) {
316		return status;
317	}
318
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;
323
324	return NT_STATUS_OK;
325}
326
327
328/*
329  parse the wire search formats that are in common between SMB and
330  SMB2
331*/
332NTSTATUS 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			       uint_t *next_ofs,
337			       uint_t str_flags)
338{
339	uint_t len, blen;
340
341	if (blob->length < 4) {
342		return NT_STATUS_INFO_LENGTH_MISMATCH;
343	}
344
345	*next_ofs = IVAL(blob->data, 0);
346	if (*next_ofs != 0) {
347		blen = *next_ofs;
348	} else {
349		blen = blob->length;
350	}
351
352	switch (level) {
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,
365					      60, 64, str_flags);
366		if (*next_ofs != 0 && *next_ofs < 64+len) {
367			return NT_STATUS_INFO_LENGTH_MISMATCH;
368		}
369		return NT_STATUS_OK;
370
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,
384					      60, 68, str_flags);
385		if (*next_ofs != 0 && *next_ofs < 68+len) {
386			return NT_STATUS_INFO_LENGTH_MISMATCH;
387		}
388		return NT_STATUS_OK;
389
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,
395					      8, 12, str_flags);
396		if (*next_ofs != 0 && *next_ofs < 12+len) {
397			return NT_STATUS_INFO_LENGTH_MISMATCH;
398		}
399		return NT_STATUS_OK;
400
401
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,
418					      60, 94, str_flags);
419		if (*next_ofs != 0 && *next_ofs < 94+len) {
420			return NT_STATUS_INFO_LENGTH_MISMATCH;
421		}
422		return NT_STATUS_OK;
423
424
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,
439					      60, 80, str_flags);
440		if (*next_ofs != 0 && *next_ofs < 80+len) {
441			return NT_STATUS_INFO_LENGTH_MISMATCH;
442		}
443		return NT_STATUS_OK;
444
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,
462					      60, 104, str_flags);
463		if (*next_ofs != 0 && *next_ofs < 104+len) {
464			return NT_STATUS_INFO_LENGTH_MISMATCH;
465		}
466		return NT_STATUS_OK;
467
468	default:
469		break;
470	}
471
472	/* invalid level */
473	return NT_STATUS_INVALID_INFO_CLASS;
474}
475
476
477/*
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
482*/
483static int parse_trans2_search(struct smbcli_tree *tree,
484			       TALLOC_CTX *mem_ctx,
485			       enum smb_search_data_level level,
486			       uint16_t flags,
487			       DATA_BLOB *blob,
488			       union smb_search_data *data)
489{
490	uint_t len, ofs;
491	uint32_t ea_size;
492	DATA_BLOB eablob;
493	NTSTATUS status;
494
495	switch (level) {
496	case RAW_SEARCH_DATA_GENERIC:
497	case RAW_SEARCH_DATA_SEARCH:
498		/* handled elsewhere */
499		return -1;
500
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);
505			blob->data += 4;
506			blob->length -= 4;
507		}
508		if (blob->length < 24) return -1;
509		data->standard.create_time = raw_pull_dos_date2(tree->session->transport,
510								blob->data + 0);
511		data->standard.access_time = raw_pull_dos_date2(tree->session->transport,
512								blob->data + 4);
513		data->standard.write_time  = raw_pull_dos_date2(tree->session->transport,
514								blob->data + 8);
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);
521		return len + 23;
522
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);
527			blob->data += 4;
528			blob->length -= 4;
529		}
530		if (blob->length < 28) return -1;
531		data->ea_size.create_time = raw_pull_dos_date2(tree->session->transport,
532							       blob->data + 0);
533		data->ea_size.access_time = raw_pull_dos_date2(tree->session->transport,
534							       blob->data + 4);
535		data->ea_size.write_time  = raw_pull_dos_date2(tree->session->transport,
536							       blob->data + 8);
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,
542					   &data->ea_size.name,
543					   26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN);
544		return len + 27 + 1;
545
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);
550			blob->data += 4;
551			blob->length -= 4;
552		}
553		if (blob->length < 28) return -1;
554		data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport,
555							       blob->data + 0);
556		data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport,
557							       blob->data + 4);
558		data->ea_list.write_time  = raw_pull_dos_date2(tree->session->transport,
559							       blob->data + 8);
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) {
565			return -1;
566		}
567		eablob.data = blob->data + 22;
568		eablob.length = ea_size;
569		if (eablob.length > blob->length - 24) {
570			return -1;
571		}
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)) {
576			return -1;
577		}
578		len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
579					      &data->ea_list.name,
580					      22+ea_size, 23+ea_size,
581					      STR_LEN8BIT | STR_NOALIGN);
582		return len + ea_size + 23 + 1;
583
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) {
605			return -1;
606		}
607		return ofs;
608
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
614		 */
615		if (blob->length < (116 + 8 + 4 + 2)) {
616			return -1;
617		}
618
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);
637
638		/* There is a 4 byte length field for this name. The length
639		 * does not include the NULL terminator.
640		 */
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 */
645				       0);
646
647		if (ofs != 0 && ofs < (8 + 116 + 4 + len)) {
648			return -1;
649		}
650
651		return ofs;
652
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			uint_t str_flags = STR_UNICODE;
660			if (!(tree->session->transport->negotiate.capabilities & CAP_UNICODE)) {
661				str_flags = STR_ASCII;
662			}
663
664		status = smb_raw_search_common(mem_ctx, level, blob, data, &ofs, str_flags);
665		if (!NT_STATUS_IS_OK(status)) {
666			return -1;
667		}
668		return ofs;
669	}
670	}
671
672	/* invalid level */
673	return -1;
674}
675
676/****************************************************************************
677 Trans2 search backend - process output.
678****************************************************************************/
679static NTSTATUS smb_raw_t2search_backend(struct smbcli_tree *tree,
680					 TALLOC_CTX *mem_ctx,
681					 enum smb_search_data_level level,
682					 uint16_t flags,
683					 int16_t count,
684					 DATA_BLOB *blob,
685					 void *private_data,
686					 smbcli_search_callback callback)
687
688{
689	int i;
690	DATA_BLOB blob2;
691
692	blob2.data = blob->data;
693	blob2.length = blob->length;
694
695	for (i=0; i < count; i++) {
696		union smb_search_data search_data;
697		uint_t len;
698
699		len = parse_trans2_search(tree, mem_ctx, level, flags, &blob2, &search_data);
700		if (len == -1) {
701			return NT_STATUS_INVALID_PARAMETER;
702		}
703
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)) {
707			break;
708		}
709
710		if (len == 0) break;
711
712		blob2.data += len;
713		blob2.length -= len;
714	}
715
716	return NT_STATUS_OK;
717}
718
719
720/* Implements trans2findfirst2 and old search
721 */
722_PUBLIC_ NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
723			      TALLOC_CTX *mem_ctx,
724			      union smb_search_first *io, void *private_data,
725			      smbcli_search_callback callback)
726{
727	DATA_BLOB p_blob, d_blob;
728	NTSTATUS status;
729
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);
735
736	case RAW_SEARCH_TRANS2:
737		break;
738
739	case RAW_SEARCH_SMB2:
740		return NT_STATUS_INVALID_LEVEL;
741	}
742
743	status = smb_raw_search_first_blob(tree, mem_ctx,
744					   io, &p_blob, &d_blob);
745	if (!NT_STATUS_IS_OK(status)) {
746		return status;
747	}
748
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;
753	}
754
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);
759
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);
764
765	return status;
766}
767
768/* Implements trans2findnext2 and old smbsearch
769 */
770NTSTATUS smb_raw_search_next(struct smbcli_tree *tree,
771			     TALLOC_CTX *mem_ctx,
772			     union smb_search_next *io, void *private_data,
773			     smbcli_search_callback callback)
774{
775	DATA_BLOB p_blob, d_blob;
776	NTSTATUS status;
777
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);
782
783	case RAW_SEARCH_FUNIQUE:
784		return NT_STATUS_INVALID_LEVEL;
785
786	case RAW_SEARCH_TRANS2:
787		break;
788
789	case RAW_SEARCH_SMB2:
790		return NT_STATUS_INVALID_LEVEL;
791	}
792
793	status = smb_raw_search_next_blob(tree, mem_ctx,
794					  io, &p_blob, &d_blob);
795	if (!NT_STATUS_IS_OK(status)) {
796		return status;
797	}
798
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;
803	}
804
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);
808
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);
813
814	return status;
815}
816
817/*
818   Implements trans2findclose2
819 */
820NTSTATUS smb_raw_search_close(struct smbcli_tree *tree,
821			      union smb_search_close *io)
822{
823	struct smbcli_request *req;
824
825	if (io->generic.level == RAW_FINDCLOSE_FCLOSE) {
826		return smb_raw_search_close_old(tree, io);
827	}
828
829	req = smbcli_request_setup(tree, SMBfindclose, 1, 0);
830	if (!req) {
831		return NT_STATUS_NO_MEMORY;
832	}
833
834	SSVAL(req->out.vwv, VWV(0), io->findclose.in.handle);
835
836	if (smbcli_request_send(req)) {
837		(void) smbcli_request_receive(req);
838	}
839
840	return smbcli_request_destroy(req);
841}
842