Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : client directory list routines
4 : Copyright (C) Andrew Tridgell 1994-1998
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "libsmb/libsmb.h"
22 : #include "../lib/util/tevent_ntstatus.h"
23 : #include "async_smb.h"
24 : #include "trans2.h"
25 : #include "../libcli/smb/smbXcli_base.h"
26 :
27 : /****************************************************************************
28 : Check if a returned directory name is safe.
29 : ****************************************************************************/
30 :
31 90997 : static NTSTATUS is_bad_name(bool windows_names, const char *name)
32 : {
33 90997 : const char *bad_name_p = NULL;
34 :
35 90997 : bad_name_p = strchr(name, '/');
36 90997 : if (bad_name_p != NULL) {
37 : /*
38 : * Windows and POSIX names can't have '/'.
39 : * Server is attacking us.
40 : */
41 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
42 : }
43 90997 : if (windows_names) {
44 90861 : bad_name_p = strchr(name, '\\');
45 90861 : if (bad_name_p != NULL) {
46 : /*
47 : * Windows names can't have '\\'.
48 : * Server is attacking us.
49 : */
50 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
51 : }
52 : }
53 90997 : return NT_STATUS_OK;
54 : }
55 :
56 : /****************************************************************************
57 : Check if a returned directory name is safe. Disconnect if server is
58 : sending bad names.
59 : ****************************************************************************/
60 :
61 64794 : NTSTATUS is_bad_finfo_name(const struct cli_state *cli,
62 : const struct file_info *finfo)
63 : {
64 64794 : NTSTATUS status = NT_STATUS_OK;
65 64794 : bool windows_names = true;
66 :
67 64794 : if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
68 136 : windows_names = false;
69 : }
70 64794 : if (finfo->name != NULL) {
71 64794 : status = is_bad_name(windows_names, finfo->name);
72 64794 : if (!NT_STATUS_IS_OK(status)) {
73 0 : DBG_ERR("bad finfo->name\n");
74 0 : return status;
75 : }
76 : }
77 64794 : if (finfo->short_name != NULL) {
78 26203 : status = is_bad_name(windows_names, finfo->short_name);
79 26203 : if (!NT_STATUS_IS_OK(status)) {
80 0 : DBG_ERR("bad finfo->short_name\n");
81 0 : return status;
82 : }
83 : }
84 64794 : return NT_STATUS_OK;
85 : }
86 :
87 : /****************************************************************************
88 : Calculate a safe next_entry_offset.
89 : ****************************************************************************/
90 :
91 9245 : static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
92 : {
93 9245 : size_t next_entry_offset = (size_t)IVAL(base,0);
94 :
95 9245 : if (next_entry_offset == 0 ||
96 9245 : base + next_entry_offset < base ||
97 9245 : base + next_entry_offset > pdata_end) {
98 0 : next_entry_offset = pdata_end - base;
99 : }
100 9245 : return next_entry_offset;
101 : }
102 :
103 : /****************************************************************************
104 : Interpret a long filename structure - this is mostly guesses at the moment.
105 : The length of the structure is returned
106 : The structure of a long filename depends on the info level.
107 : SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
108 : by NT and SMB_FIND_EA_SIZE is used by OS/2
109 : ****************************************************************************/
110 :
111 9245 : static size_t interpret_long_filename(TALLOC_CTX *ctx,
112 : struct cli_state *cli,
113 : int level,
114 : const char *base_ptr,
115 : uint16_t recv_flags2,
116 : const char *p,
117 : const char *pdata_end,
118 : struct file_info *finfo,
119 : uint32_t *p_resume_key,
120 : DATA_BLOB *p_last_name_raw)
121 : {
122 0 : int len;
123 0 : size_t ret;
124 9245 : const char *base = p;
125 :
126 9245 : data_blob_free(p_last_name_raw);
127 :
128 9245 : if (p_resume_key) {
129 9245 : *p_resume_key = 0;
130 : }
131 9245 : ZERO_STRUCTP(finfo);
132 :
133 9245 : switch (level) {
134 0 : case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
135 : /* these dates are converted to GMT by
136 : make_unix_date */
137 0 : if (pdata_end - base < 27) {
138 0 : return pdata_end - base;
139 : }
140 : /*
141 : * What we're returning here as ctime_ts is
142 : * actually the server create time.
143 : */
144 0 : finfo->btime_ts = convert_time_t_to_timespec(
145 0 : make_unix_date2(p+4,
146 : smb1cli_conn_server_time_zone(
147 : cli->conn)));
148 0 : finfo->ctime_ts = convert_time_t_to_timespec(
149 0 : make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
150 0 : finfo->atime_ts = convert_time_t_to_timespec(
151 0 : make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
152 0 : finfo->mtime_ts = convert_time_t_to_timespec(
153 0 : make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
154 0 : finfo->size = IVAL(p,16);
155 0 : finfo->attr = SVAL(p,24);
156 0 : len = CVAL(p, 26);
157 0 : p += 27;
158 0 : if (recv_flags2 & FLAGS2_UNICODE_STRINGS) {
159 0 : p += ucs2_align(base_ptr, p, STR_UNICODE);
160 : }
161 :
162 : /* We can safely use len here (which is required by OS/2)
163 : * and the NAS-BASIC server instead of +2 or +1 as the
164 : * STR_TERMINATE flag below is
165 : * actually used as the length calculation.
166 : * The len is merely an upper bound.
167 : * Due to the explicit 2 byte null termination
168 : * in cli_receive_trans/cli_receive_nt_trans
169 : * we know this is safe. JRA + kukks
170 : */
171 :
172 0 : if (p + len > pdata_end) {
173 0 : return pdata_end - base;
174 : }
175 :
176 : /* the len+2 below looks strange but it is
177 : important to cope with the differences
178 : between win2000 and win9x for this call
179 : (tridge) */
180 0 : ret = pull_string_talloc(ctx,
181 : base_ptr,
182 : recv_flags2,
183 : &finfo->name,
184 : p,
185 0 : len+2,
186 : STR_TERMINATE);
187 0 : if (ret == (size_t)-1) {
188 0 : return pdata_end - base;
189 : }
190 0 : p += ret;
191 0 : return PTR_DIFF(p, base);
192 :
193 0 : case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
194 : /* these dates are converted to GMT by
195 : make_unix_date */
196 0 : if (pdata_end - base < 31) {
197 0 : return pdata_end - base;
198 : }
199 : /*
200 : * What we're returning here as ctime_ts is
201 : * actually the server create time.
202 : */
203 0 : finfo->btime_ts = convert_time_t_to_timespec(
204 0 : make_unix_date2(p+4,
205 : smb1cli_conn_server_time_zone(
206 : cli->conn)));
207 0 : finfo->ctime_ts = convert_time_t_to_timespec(
208 0 : make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
209 0 : finfo->atime_ts = convert_time_t_to_timespec(
210 0 : make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
211 0 : finfo->mtime_ts = convert_time_t_to_timespec(
212 0 : make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
213 0 : finfo->size = IVAL(p,16);
214 0 : finfo->attr = SVAL(p,24);
215 0 : len = CVAL(p, 30);
216 0 : p += 31;
217 : /* check for unisys! */
218 0 : if (p + len + 1 > pdata_end) {
219 0 : return pdata_end - base;
220 : }
221 0 : ret = pull_string_talloc(ctx,
222 : base_ptr,
223 : recv_flags2,
224 : &finfo->name,
225 : p,
226 : len,
227 : STR_NOALIGN);
228 0 : if (ret == (size_t)-1) {
229 0 : return pdata_end - base;
230 : }
231 0 : p += ret;
232 0 : return PTR_DIFF(p, base) + 1;
233 :
234 9245 : case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
235 : {
236 0 : size_t namelen, slen;
237 :
238 9245 : if (pdata_end - base < 94) {
239 0 : return pdata_end - base;
240 : }
241 :
242 9245 : p += 4; /* next entry offset */
243 :
244 9245 : if (p_resume_key) {
245 9245 : *p_resume_key = IVAL(p,0);
246 : }
247 9245 : p += 4; /* fileindex */
248 :
249 : /* Offset zero is "create time", not "change time". */
250 9245 : p += 8;
251 9245 : finfo->atime_ts = interpret_long_date(BVAL(p, 0));
252 9245 : p += 8;
253 9245 : finfo->mtime_ts = interpret_long_date(BVAL(p, 0));
254 9245 : p += 8;
255 9245 : finfo->ctime_ts = interpret_long_date(BVAL(p, 0));
256 9245 : p += 8;
257 9245 : finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
258 9245 : p += 8;
259 9245 : p += 8; /* alloc size */
260 9245 : finfo->attr = IVAL(p,0);
261 9245 : p += 4;
262 9245 : namelen = IVAL(p,0);
263 9245 : p += 4;
264 9245 : p += 4; /* EA size */
265 9245 : slen = CVAL(p, 0);
266 9245 : if (slen > 24) {
267 : /* Bad short name length. */
268 0 : return pdata_end - base;
269 : }
270 9245 : p += 2;
271 9245 : ret = pull_string_talloc(ctx,
272 : base_ptr,
273 : recv_flags2,
274 : &finfo->short_name,
275 : p,
276 : slen,
277 : STR_UNICODE);
278 9245 : if (ret == (size_t)-1) {
279 0 : return pdata_end - base;
280 : }
281 9245 : p += 24; /* short name? */
282 9245 : if (p + namelen < p || p + namelen > pdata_end) {
283 0 : return pdata_end - base;
284 : }
285 9245 : ret = pull_string_talloc(ctx,
286 : base_ptr,
287 : recv_flags2,
288 : &finfo->name,
289 : p,
290 : namelen,
291 : 0);
292 9245 : if (ret == (size_t)-1) {
293 0 : return pdata_end - base;
294 : }
295 :
296 : /* To be robust in the face of unicode conversion failures
297 : we need to copy the raw bytes of the last name seen here.
298 : Namelen doesn't include the terminating unicode null, so
299 : copy it here. */
300 :
301 9245 : if (p_last_name_raw) {
302 9245 : *p_last_name_raw = data_blob(NULL, namelen+2);
303 9245 : memcpy(p_last_name_raw->data, p, namelen);
304 9245 : SSVAL(p_last_name_raw->data, namelen, 0);
305 : }
306 9245 : return calc_next_entry_offset(base, pdata_end);
307 : }
308 : }
309 :
310 0 : DEBUG(1,("Unknown long filename format %d\n",level));
311 0 : return calc_next_entry_offset(base, pdata_end);
312 : }
313 :
314 : /****************************************************************************
315 : Interpret a short filename structure.
316 : The length of the structure is returned.
317 : ****************************************************************************/
318 :
319 131 : static bool interpret_short_filename(TALLOC_CTX *ctx,
320 : struct cli_state *cli,
321 : char *p,
322 : struct file_info *finfo)
323 : {
324 0 : size_t ret;
325 131 : ZERO_STRUCTP(finfo);
326 :
327 131 : finfo->attr = CVAL(p,21);
328 :
329 : /* We don't get birth time. */
330 131 : finfo->btime_ts.tv_sec = 0;
331 131 : finfo->btime_ts.tv_nsec = 0;
332 : /* this date is converted to GMT by make_unix_date */
333 131 : finfo->ctime_ts.tv_sec = make_unix_date(p+22, smb1cli_conn_server_time_zone(cli->conn));
334 131 : finfo->ctime_ts.tv_nsec = 0;
335 131 : finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
336 131 : finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
337 131 : finfo->size = IVAL(p,26);
338 131 : ret = pull_string_talloc(ctx,
339 : NULL,
340 : 0,
341 : &finfo->name,
342 131 : p+30,
343 : 12,
344 : STR_ASCII);
345 131 : if (ret == (size_t)-1) {
346 0 : return false;
347 : }
348 :
349 131 : if (finfo->name) {
350 131 : finfo->short_name = talloc_strdup(ctx, finfo->name);
351 131 : if (finfo->short_name == NULL) {
352 0 : return false;
353 : }
354 : }
355 131 : return true;
356 : }
357 :
358 : struct cli_list_old_state {
359 : struct tevent_context *ev;
360 : struct cli_state *cli;
361 : uint16_t vwv[2];
362 : char *mask;
363 : int num_asked;
364 : uint32_t attribute;
365 : uint8_t search_status[23];
366 : bool first;
367 : bool done;
368 : uint8_t *dirlist;
369 : };
370 :
371 : static void cli_list_old_done(struct tevent_req *subreq);
372 :
373 2 : static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
374 : struct tevent_context *ev,
375 : struct cli_state *cli,
376 : const char *mask,
377 : uint32_t attribute)
378 : {
379 0 : struct tevent_req *req, *subreq;
380 0 : struct cli_list_old_state *state;
381 0 : uint8_t *bytes;
382 0 : static const uint16_t zero = 0;
383 0 : uint32_t usable_space;
384 :
385 2 : req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
386 2 : if (req == NULL) {
387 0 : return NULL;
388 : }
389 2 : state->ev = ev;
390 2 : state->cli = cli;
391 2 : state->attribute = attribute;
392 2 : state->first = true;
393 2 : state->mask = talloc_strdup(state, mask);
394 2 : if (tevent_req_nomem(state->mask, req)) {
395 0 : return tevent_req_post(req, ev);
396 : }
397 2 : state->mask = smb1_dfs_share_path(state, cli, state->mask);
398 2 : if (tevent_req_nomem(state->mask, req)) {
399 0 : return tevent_req_post(req, ev);
400 : }
401 2 : usable_space = cli_state_available_size(cli, 100);
402 2 : state->num_asked = usable_space / DIR_STRUCT_SIZE;
403 :
404 2 : SSVAL(state->vwv + 0, 0, state->num_asked);
405 2 : SSVAL(state->vwv + 1, 0, state->attribute);
406 :
407 2 : bytes = talloc_array(state, uint8_t, 1);
408 2 : if (tevent_req_nomem(bytes, req)) {
409 0 : return tevent_req_post(req, ev);
410 : }
411 2 : bytes[0] = 4;
412 2 : bytes = smb_bytes_push_str(bytes,
413 2 : smbXcli_conn_use_unicode(cli->conn),
414 2 : state->mask,
415 2 : strlen(state->mask)+1,
416 : NULL);
417 :
418 2 : bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
419 2 : if (tevent_req_nomem(bytes, req)) {
420 0 : return tevent_req_post(req, ev);
421 : }
422 :
423 2 : subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch, 0, 0,
424 2 : 2, state->vwv, talloc_get_size(bytes), bytes);
425 2 : if (tevent_req_nomem(subreq, req)) {
426 0 : return tevent_req_post(req, ev);
427 : }
428 2 : tevent_req_set_callback(subreq, cli_list_old_done, req);
429 2 : return req;
430 : }
431 :
432 6 : static void cli_list_old_done(struct tevent_req *subreq)
433 : {
434 6 : struct tevent_req *req = tevent_req_callback_data(
435 : subreq, struct tevent_req);
436 6 : struct cli_list_old_state *state = tevent_req_data(
437 : req, struct cli_list_old_state);
438 0 : NTSTATUS status;
439 0 : uint8_t cmd;
440 0 : uint8_t wct;
441 0 : uint16_t *vwv;
442 0 : uint32_t num_bytes;
443 0 : uint8_t *bytes;
444 0 : uint16_t received;
445 0 : size_t dirlist_len;
446 0 : uint8_t *tmp;
447 :
448 6 : status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
449 : &bytes);
450 6 : if (!NT_STATUS_IS_OK(status)
451 0 : && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
452 0 : && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
453 0 : TALLOC_FREE(subreq);
454 0 : tevent_req_nterror(req, status);
455 0 : return;
456 : }
457 6 : if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
458 6 : || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
459 0 : received = 0;
460 : } else {
461 6 : if (wct < 1) {
462 0 : TALLOC_FREE(subreq);
463 0 : tevent_req_nterror(
464 : req, NT_STATUS_INVALID_NETWORK_RESPONSE);
465 0 : return;
466 : }
467 6 : received = SVAL(vwv + 0, 0);
468 : }
469 :
470 6 : if (received > 0) {
471 : /*
472 : * I don't think this can wrap. received is
473 : * initialized from a 16-bit value.
474 : */
475 2 : if (num_bytes < ((uint32_t)received * DIR_STRUCT_SIZE + 3)) {
476 0 : TALLOC_FREE(subreq);
477 0 : tevent_req_nterror(
478 : req, NT_STATUS_INVALID_NETWORK_RESPONSE);
479 0 : return;
480 : }
481 :
482 2 : dirlist_len = talloc_get_size(state->dirlist);
483 :
484 2 : tmp = talloc_realloc(
485 : state, state->dirlist, uint8_t,
486 : dirlist_len + received * DIR_STRUCT_SIZE);
487 2 : if (tevent_req_nomem(tmp, req)) {
488 0 : return;
489 : }
490 2 : state->dirlist = tmp;
491 2 : memcpy(state->dirlist + dirlist_len, bytes + 3,
492 2 : received * DIR_STRUCT_SIZE);
493 :
494 2 : SSVAL(state->search_status, 0, 21);
495 2 : memcpy(state->search_status + 2,
496 2 : bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
497 2 : cmd = SMBsearch;
498 : } else {
499 4 : if (state->first || state->done) {
500 2 : tevent_req_done(req);
501 2 : return;
502 : }
503 2 : state->done = true;
504 2 : state->num_asked = 0;
505 2 : cmd = SMBfclose;
506 : }
507 4 : TALLOC_FREE(subreq);
508 :
509 4 : state->first = false;
510 :
511 4 : SSVAL(state->vwv + 0, 0, state->num_asked);
512 4 : SSVAL(state->vwv + 1, 0, state->attribute);
513 :
514 4 : bytes = talloc_array(state, uint8_t, 1);
515 4 : if (tevent_req_nomem(bytes, req)) {
516 0 : return;
517 : }
518 4 : bytes[0] = 4;
519 4 : bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(state->cli->conn), "",
520 : 1, NULL);
521 4 : bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
522 : sizeof(state->search_status));
523 4 : if (tevent_req_nomem(bytes, req)) {
524 0 : return;
525 : }
526 8 : subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0, 0,
527 4 : 2, state->vwv, talloc_get_size(bytes), bytes);
528 4 : if (tevent_req_nomem(subreq, req)) {
529 0 : return;
530 : }
531 4 : tevent_req_set_callback(subreq, cli_list_old_done, req);
532 : }
533 :
534 4 : static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
535 : struct file_info **pfinfo)
536 : {
537 4 : struct cli_list_old_state *state = tevent_req_data(
538 : req, struct cli_list_old_state);
539 0 : NTSTATUS status;
540 0 : size_t i, num_received;
541 0 : struct file_info *finfo;
542 :
543 4 : if (tevent_req_is_nterror(req, &status)) {
544 0 : return status;
545 : }
546 :
547 4 : if (state->dirlist == NULL) {
548 2 : *pfinfo = NULL;
549 2 : return NT_STATUS_OK;
550 : }
551 :
552 2 : num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
553 :
554 2 : finfo = talloc_array(mem_ctx, struct file_info, num_received);
555 2 : if (finfo == NULL) {
556 0 : return NT_STATUS_NO_MEMORY;
557 : }
558 :
559 133 : for (i=0; i<num_received; i++) {
560 131 : if (!interpret_short_filename(
561 : finfo, state->cli,
562 131 : (char *)state->dirlist + i * DIR_STRUCT_SIZE,
563 131 : &finfo[i])) {
564 0 : TALLOC_FREE(finfo);
565 0 : return NT_STATUS_NO_MEMORY;
566 : }
567 131 : if (finfo->name == NULL) {
568 0 : TALLOC_FREE(finfo);
569 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
570 : }
571 131 : status = is_bad_finfo_name(state->cli, finfo);
572 131 : if (!NT_STATUS_IS_OK(status)) {
573 0 : smbXcli_conn_disconnect(state->cli->conn, status);
574 0 : TALLOC_FREE(finfo);
575 0 : return status;
576 : }
577 : }
578 2 : TALLOC_FREE(state->dirlist);
579 2 : *pfinfo = finfo;
580 2 : return NT_STATUS_OK;
581 : }
582 :
583 0 : NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
584 : uint32_t attribute,
585 : NTSTATUS (*fn)(struct file_info *,
586 : const char *, void *), void *state)
587 : {
588 0 : TALLOC_CTX *frame = talloc_stackframe();
589 0 : struct tevent_context *ev;
590 0 : struct tevent_req *req;
591 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
592 0 : struct file_info *finfo = NULL;
593 0 : size_t i, num_finfo;
594 :
595 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
596 : /*
597 : * Can't use sync call while an async call is in flight
598 : */
599 0 : status = NT_STATUS_INVALID_PARAMETER;
600 0 : goto fail;
601 : }
602 0 : ev = samba_tevent_context_init(frame);
603 0 : if (ev == NULL) {
604 0 : goto fail;
605 : }
606 0 : req = cli_list_old_send(frame, ev, cli, mask, attribute);
607 0 : if (req == NULL) {
608 0 : goto fail;
609 : }
610 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
611 0 : goto fail;
612 : }
613 0 : status = cli_list_old_recv(req, frame, &finfo);
614 0 : if (!NT_STATUS_IS_OK(status)) {
615 0 : goto fail;
616 : }
617 0 : num_finfo = talloc_array_length(finfo);
618 0 : for (i=0; i<num_finfo; i++) {
619 0 : status = fn(&finfo[i], mask, state);
620 0 : if (!NT_STATUS_IS_OK(status)) {
621 0 : goto fail;
622 : }
623 : }
624 0 : fail:
625 0 : TALLOC_FREE(frame);
626 0 : return status;
627 : }
628 :
629 : struct cli_list_trans_state {
630 : struct tevent_context *ev;
631 : struct cli_state *cli;
632 : char *mask;
633 : uint32_t attribute;
634 : uint16_t info_level;
635 :
636 : int loop_count;
637 : int total_received;
638 : uint16_t max_matches;
639 : bool first;
640 :
641 : int ff_eos;
642 : int ff_dir_handle;
643 :
644 : uint16_t setup[1];
645 : uint8_t *param;
646 :
647 : struct file_info *finfo;
648 : };
649 :
650 : static void cli_list_trans_done(struct tevent_req *subreq);
651 :
652 2225 : static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
653 : struct tevent_context *ev,
654 : struct cli_state *cli,
655 : const char *mask,
656 : uint32_t attribute,
657 : uint16_t info_level)
658 : {
659 0 : struct tevent_req *req, *subreq;
660 0 : struct cli_list_trans_state *state;
661 0 : size_t param_len;
662 2225 : uint16_t additional_flags2 = 0;
663 :
664 2225 : req = tevent_req_create(mem_ctx, &state,
665 : struct cli_list_trans_state);
666 2225 : if (req == NULL) {
667 0 : return NULL;
668 : }
669 2225 : state->ev = ev;
670 2225 : state->cli = cli;
671 2225 : state->mask = talloc_strdup(state, mask);
672 2225 : if (tevent_req_nomem(state->mask, req)) {
673 0 : return tevent_req_post(req, ev);
674 : }
675 2225 : state->mask = smb1_dfs_share_path(state, cli, state->mask);
676 2225 : if (tevent_req_nomem(state->mask, req)) {
677 0 : return tevent_req_post(req, ev);
678 : }
679 2225 : state->attribute = attribute;
680 2225 : state->info_level = info_level;
681 2225 : state->loop_count = 0;
682 2225 : state->first = true;
683 :
684 2225 : state->max_matches = 1366; /* Match W2k */
685 :
686 2225 : SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
687 :
688 2225 : state->param = talloc_array(state, uint8_t, 12);
689 2225 : if (tevent_req_nomem(state->param, req)) {
690 0 : return tevent_req_post(req, ev);
691 : }
692 :
693 2225 : SSVAL(state->param, 0, state->attribute);
694 2225 : SSVAL(state->param, 2, state->max_matches);
695 2225 : SSVAL(state->param, 4,
696 : FLAG_TRANS2_FIND_REQUIRE_RESUME
697 : |FLAG_TRANS2_FIND_CLOSE_IF_END
698 : |(cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0));
699 2225 : SSVAL(state->param, 6, state->info_level);
700 2225 : SIVAL(state->param, 8, 0);
701 :
702 2225 : state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
703 2225 : state->mask, strlen(state->mask)+1,
704 : NULL);
705 2225 : if (tevent_req_nomem(state->param, req)) {
706 0 : return tevent_req_post(req, ev);
707 : }
708 :
709 2225 : if (clistr_is_previous_version_path(state->mask)) {
710 68 : additional_flags2 = FLAGS2_REPARSE_PATH;
711 : }
712 :
713 2225 : param_len = talloc_get_size(state->param);
714 :
715 2225 : subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
716 : SMBtrans2, NULL, -1, 0, 0,
717 2225 : state->setup, 1, 0,
718 2225 : state->param, param_len, 10,
719 : NULL, 0, CLI_BUFFER_SIZE);
720 2225 : if (tevent_req_nomem(subreq, req)) {
721 0 : return tevent_req_post(req, ev);
722 : }
723 2225 : tevent_req_set_callback(subreq, cli_list_trans_done, req);
724 2225 : return req;
725 : }
726 :
727 2225 : static void cli_list_trans_done(struct tevent_req *subreq)
728 : {
729 2225 : struct tevent_req *req = tevent_req_callback_data(
730 : subreq, struct tevent_req);
731 2225 : struct cli_list_trans_state *state = tevent_req_data(
732 : req, struct cli_list_trans_state);
733 0 : NTSTATUS status;
734 0 : uint8_t *param;
735 0 : uint32_t num_param;
736 0 : uint8_t *data;
737 0 : char *data_end;
738 0 : uint32_t num_data;
739 0 : uint32_t min_param;
740 0 : struct file_info *tmp;
741 0 : size_t old_num_finfo;
742 0 : uint16_t recv_flags2;
743 0 : int ff_searchcount;
744 0 : bool ff_eos;
745 0 : char *p, *p2;
746 2225 : uint32_t resume_key = 0;
747 0 : int i;
748 0 : DATA_BLOB last_name_raw;
749 2225 : struct file_info *finfo = NULL;
750 0 : size_t param_len;
751 2225 : uint16_t additional_flags2 = 0;
752 :
753 2225 : min_param = (state->first ? 6 : 4);
754 :
755 2225 : status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
756 : NULL, 0, NULL,
757 : ¶m, min_param, &num_param,
758 : &data, 0, &num_data);
759 2225 : TALLOC_FREE(subreq);
760 2225 : if (!NT_STATUS_IS_OK(status)) {
761 : /*
762 : * TODO: retry, OS/2 nofiles
763 : */
764 350 : tevent_req_nterror(req, status);
765 2225 : return;
766 : }
767 :
768 1875 : if (state->first) {
769 1875 : state->ff_dir_handle = SVAL(param, 0);
770 1875 : ff_searchcount = SVAL(param, 2);
771 1875 : ff_eos = SVAL(param, 4) != 0;
772 : } else {
773 0 : ff_searchcount = SVAL(param, 0);
774 0 : ff_eos = SVAL(param, 2) != 0;
775 : }
776 :
777 1875 : old_num_finfo = talloc_array_length(state->finfo);
778 :
779 1875 : tmp = talloc_realloc(state, state->finfo, struct file_info,
780 : old_num_finfo + ff_searchcount);
781 1875 : if (tevent_req_nomem(tmp, req)) {
782 0 : return;
783 : }
784 1875 : state->finfo = tmp;
785 :
786 1875 : p2 = p = (char *)data;
787 1875 : data_end = (char *)data + num_data;
788 1875 : last_name_raw = data_blob_null;
789 :
790 11118 : for (i=0; i<ff_searchcount; i++) {
791 9245 : if (p2 >= data_end) {
792 0 : ff_eos = true;
793 0 : break;
794 : }
795 9245 : if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
796 9245 : && (i == ff_searchcount-1)) {
797 : /* Last entry - fixup the last offset length. */
798 1875 : SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
799 : }
800 :
801 9245 : data_blob_free(&last_name_raw);
802 :
803 9245 : finfo = &state->finfo[old_num_finfo + i];
804 :
805 18490 : p2 += interpret_long_filename(
806 9245 : state->finfo, /* Stick fname to the array as such */
807 9245 : state->cli, state->info_level,
808 : (char *)data, recv_flags2, p2,
809 : data_end, finfo, &resume_key, &last_name_raw);
810 :
811 9245 : if (finfo->name == NULL) {
812 2 : DEBUG(1, ("cli_list: Error: unable to parse name from "
813 : "info level %d\n", state->info_level));
814 2 : tevent_req_nterror(req,
815 : NT_STATUS_INVALID_NETWORK_RESPONSE);
816 2 : return;
817 : }
818 :
819 9243 : status = is_bad_finfo_name(state->cli, finfo);
820 9243 : if (!NT_STATUS_IS_OK(status)) {
821 0 : smbXcli_conn_disconnect(state->cli->conn, status);
822 0 : tevent_req_nterror(req, status);
823 0 : return;
824 : }
825 :
826 9243 : if (!state->first && (state->mask[0] != '\0') &&
827 0 : strcsequal(finfo->name, state->mask)) {
828 0 : DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
829 : "already been seen?\n", finfo->name));
830 0 : ff_eos = true;
831 0 : break;
832 : }
833 : }
834 :
835 1873 : if (ff_searchcount == 0) {
836 0 : ff_eos = true;
837 : }
838 :
839 1873 : TALLOC_FREE(param);
840 1873 : TALLOC_FREE(data);
841 :
842 : /*
843 : * Shrink state->finfo to the real length we received
844 : */
845 1873 : tmp = talloc_realloc(state, state->finfo, struct file_info,
846 : old_num_finfo + i);
847 1873 : if (tevent_req_nomem(tmp, req)) {
848 0 : return;
849 : }
850 1873 : state->finfo = tmp;
851 :
852 1873 : state->first = false;
853 :
854 1873 : if (ff_eos) {
855 1873 : data_blob_free(&last_name_raw);
856 1873 : tevent_req_done(req);
857 1873 : return;
858 : }
859 :
860 0 : TALLOC_FREE(state->mask);
861 0 : state->mask = talloc_strdup(state, finfo->name);
862 0 : if (tevent_req_nomem(state->mask, req)) {
863 0 : return;
864 : }
865 :
866 0 : SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
867 :
868 0 : param = talloc_realloc(state, state->param, uint8_t, 12);
869 0 : if (tevent_req_nomem(param, req)) {
870 0 : return;
871 : }
872 0 : state->param = param;
873 :
874 0 : SSVAL(param, 0, state->ff_dir_handle);
875 0 : SSVAL(param, 2, state->max_matches); /* max count */
876 0 : SSVAL(param, 4, state->info_level);
877 : /*
878 : * For W2K servers serving out FAT filesystems we *must* set
879 : * the resume key. If it's not FAT then it's returned as zero.
880 : */
881 0 : SIVAL(param, 6, resume_key); /* ff_resume_key */
882 : /*
883 : * NB. *DON'T* use continue here. If you do it seems that W2K
884 : * and brethren can miss filenames. Use last filename
885 : * continue instead. JRA
886 : */
887 0 : SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
888 : |FLAG_TRANS2_FIND_CLOSE_IF_END
889 : |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
890 0 : if (last_name_raw.length) {
891 0 : state->param = trans2_bytes_push_bytes(state->param,
892 0 : last_name_raw.data,
893 : last_name_raw.length);
894 0 : if (tevent_req_nomem(state->param, req)) {
895 0 : return;
896 : }
897 0 : data_blob_free(&last_name_raw);
898 : } else {
899 0 : state->param = trans2_bytes_push_str(state->param,
900 0 : smbXcli_conn_use_unicode(state->cli->conn),
901 0 : state->mask,
902 0 : strlen(state->mask)+1,
903 : NULL);
904 0 : if (tevent_req_nomem(state->param, req)) {
905 0 : return;
906 : }
907 : }
908 0 : param_len = talloc_get_size(state->param);
909 :
910 0 : if (clistr_is_previous_version_path(state->mask)) {
911 0 : additional_flags2 = FLAGS2_REPARSE_PATH;
912 : }
913 :
914 0 : subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
915 : SMBtrans2, NULL, -1, 0, 0,
916 0 : state->setup, 1, 0,
917 : state->param, param_len, 10,
918 : NULL, 0, CLI_BUFFER_SIZE);
919 0 : if (tevent_req_nomem(subreq, req)) {
920 0 : return;
921 : }
922 0 : tevent_req_set_callback(subreq, cli_list_trans_done, req);
923 : }
924 :
925 4098 : static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
926 : TALLOC_CTX *mem_ctx,
927 : struct file_info **finfo)
928 : {
929 4098 : struct cli_list_trans_state *state = tevent_req_data(
930 : req, struct cli_list_trans_state);
931 0 : NTSTATUS status;
932 :
933 4098 : if (tevent_req_is_nterror(req, &status)) {
934 352 : return status;
935 : }
936 3746 : *finfo = talloc_move(mem_ctx, &state->finfo);
937 3746 : return NT_STATUS_OK;
938 : }
939 :
940 0 : NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
941 : uint32_t attribute, int info_level,
942 : NTSTATUS (*fn)(
943 : struct file_info *finfo,
944 : const char *mask,
945 : void *private_data),
946 : void *private_data)
947 : {
948 0 : TALLOC_CTX *frame = talloc_stackframe();
949 0 : struct tevent_context *ev;
950 0 : struct tevent_req *req;
951 0 : int i, num_finfo;
952 0 : struct file_info *finfo = NULL;
953 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
954 :
955 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
956 : /*
957 : * Can't use sync call while an async call is in flight
958 : */
959 0 : status = NT_STATUS_INVALID_PARAMETER;
960 0 : goto fail;
961 : }
962 0 : ev = samba_tevent_context_init(frame);
963 0 : if (ev == NULL) {
964 0 : goto fail;
965 : }
966 0 : req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
967 0 : if (req == NULL) {
968 0 : goto fail;
969 : }
970 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
971 0 : goto fail;
972 : }
973 0 : status = cli_list_trans_recv(req, frame, &finfo);
974 0 : if (!NT_STATUS_IS_OK(status)) {
975 0 : goto fail;
976 : }
977 0 : num_finfo = talloc_array_length(finfo);
978 0 : for (i=0; i<num_finfo; i++) {
979 0 : status = fn(&finfo[i], mask, private_data);
980 0 : if (!NT_STATUS_IS_OK(status)) {
981 0 : goto fail;
982 : }
983 : }
984 0 : fail:
985 0 : TALLOC_FREE(frame);
986 0 : return status;
987 : }
988 :
989 : struct cli_list_state {
990 : struct tevent_context *ev;
991 : struct tevent_req *subreq;
992 : NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
993 : struct file_info **finfo);
994 : struct file_info *finfo;
995 : size_t num_received;
996 : };
997 :
998 : static void cli_list_done(struct tevent_req *subreq);
999 :
1000 10933 : struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
1001 : struct tevent_context *ev,
1002 : struct cli_state *cli,
1003 : const char *mask,
1004 : uint32_t attribute,
1005 : uint16_t info_level)
1006 : {
1007 10933 : struct tevent_req *req = NULL;
1008 0 : struct cli_list_state *state;
1009 10933 : enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
1010 :
1011 10933 : req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
1012 10933 : if (req == NULL) {
1013 0 : return NULL;
1014 : }
1015 10933 : state->ev = ev;
1016 :
1017 10933 : if (proto >= PROTOCOL_SMB2_02) {
1018 8706 : state->subreq = cli_smb2_list_send(state, ev, cli, mask,
1019 : info_level);
1020 8706 : state->recv_fn = cli_smb2_list_recv;
1021 2227 : } else if (proto >= PROTOCOL_LANMAN2) {
1022 2225 : state->subreq = cli_list_trans_send(
1023 : state, ev, cli, mask, attribute, info_level);
1024 2225 : state->recv_fn = cli_list_trans_recv;
1025 : } else {
1026 2 : state->subreq = cli_list_old_send(
1027 : state, ev, cli, mask, attribute);
1028 2 : state->recv_fn = cli_list_old_recv;
1029 : }
1030 10933 : if (tevent_req_nomem(state->subreq, req)) {
1031 0 : return tevent_req_post(req, ev);
1032 : }
1033 10933 : tevent_req_set_callback(state->subreq, cli_list_done, req);
1034 10933 : return req;
1035 : }
1036 :
1037 27556 : static void cli_list_done(struct tevent_req *subreq)
1038 : {
1039 27556 : struct tevent_req *req = tevent_req_callback_data(
1040 : subreq, struct tevent_req);
1041 27556 : struct cli_list_state *state = tevent_req_data(
1042 : req, struct cli_list_state);
1043 0 : NTSTATUS status;
1044 :
1045 27556 : SMB_ASSERT(subreq == state->subreq);
1046 :
1047 : /*
1048 : * We don't want to be called by the lowerlevel routines
1049 : * from within state->recv_fn()
1050 : */
1051 27556 : tevent_req_set_callback(subreq, NULL, NULL);
1052 :
1053 27556 : status = state->recv_fn(subreq, state, &state->finfo);
1054 27556 : if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
1055 : /* We'll get back here */
1056 8426 : tevent_req_set_callback(subreq, cli_list_done, req);
1057 8426 : return;
1058 : }
1059 :
1060 19130 : if (tevent_req_nterror(req, status)) {
1061 9056 : return;
1062 : }
1063 10074 : tevent_req_notify_callback(req);
1064 : }
1065 :
1066 85797 : NTSTATUS cli_list_recv(
1067 : struct tevent_req *req,
1068 : TALLOC_CTX *mem_ctx,
1069 : struct file_info **pfinfo)
1070 : {
1071 85797 : struct cli_list_state *state = tevent_req_data(
1072 : req, struct cli_list_state);
1073 0 : size_t num_results;
1074 85797 : struct file_info *finfo = NULL;
1075 0 : NTSTATUS status;
1076 0 : bool in_progress;
1077 :
1078 85797 : in_progress = tevent_req_is_in_progress(req);
1079 :
1080 85797 : if (!in_progress) {
1081 10933 : if (!tevent_req_is_nterror(req, &status)) {
1082 0 : status = NT_STATUS_NO_MORE_FILES;
1083 : }
1084 10933 : return status;
1085 : }
1086 :
1087 74864 : if (state->finfo == NULL) {
1088 57295 : status = state->recv_fn(state->subreq, state, &state->finfo);
1089 :
1090 57295 : if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
1091 8197 : tevent_req_set_callback(
1092 : state->subreq, cli_list_done, req);
1093 8197 : return NT_STATUS_RETRY;
1094 : }
1095 :
1096 49098 : if (NT_STATUS_IS_OK(status) && (state->finfo == NULL)) {
1097 1875 : status = NT_STATUS_NO_MORE_FILES;
1098 : }
1099 :
1100 49098 : if (tevent_req_nterror(req, status)) {
1101 1877 : return status;
1102 : }
1103 :
1104 47221 : state->num_received = 0;
1105 : }
1106 :
1107 64790 : num_results = talloc_array_length(state->finfo);
1108 :
1109 64790 : if (num_results == 1) {
1110 56110 : finfo = talloc_move(mem_ctx, &state->finfo);
1111 : } else {
1112 8680 : struct file_info *src_finfo =
1113 8680 : &state->finfo[state->num_received];
1114 :
1115 8680 : finfo = talloc(mem_ctx, struct file_info);
1116 8680 : if (finfo == NULL) {
1117 0 : return NT_STATUS_NO_MEMORY;
1118 : }
1119 8680 : *finfo = *src_finfo;
1120 8680 : finfo->name = talloc_move(finfo, &src_finfo->name);
1121 8680 : finfo->short_name = talloc_move(finfo, &src_finfo->short_name);
1122 : }
1123 :
1124 64790 : state->num_received += 1;
1125 :
1126 64790 : if (state->num_received == num_results) {
1127 57295 : TALLOC_FREE(state->finfo);
1128 : }
1129 :
1130 64790 : tevent_req_defer_callback(req, state->ev);
1131 64790 : tevent_req_notify_callback(req);
1132 :
1133 64790 : *pfinfo = finfo;
1134 64790 : return NT_STATUS_OK;
1135 : }
1136 :
1137 : struct cli_list_sync_state {
1138 : const char *mask;
1139 : uint32_t attribute;
1140 : NTSTATUS (*fn)(struct file_info *finfo,
1141 : const char *mask,
1142 : void *private_data);
1143 : void *private_data;
1144 : NTSTATUS status;
1145 : bool processed_file;
1146 : };
1147 :
1148 66002 : static void cli_list_sync_cb(struct tevent_req *subreq)
1149 : {
1150 0 : struct cli_list_sync_state *state =
1151 66002 : tevent_req_callback_data_void(subreq);
1152 0 : struct file_info *finfo;
1153 0 : bool ok;
1154 :
1155 66002 : state->status = cli_list_recv(subreq, talloc_tos(), &finfo);
1156 : /* No TALLOC_FREE(subreq), we get here more than once */
1157 :
1158 66002 : if (NT_STATUS_EQUAL(state->status, NT_STATUS_RETRY)) {
1159 : /*
1160 : * The lowlevel SMB call was rearmed, we'll get back
1161 : * here when it's done.
1162 : */
1163 4734 : state->status = NT_STATUS_OK;
1164 4734 : return;
1165 : }
1166 :
1167 61268 : if (!NT_STATUS_IS_OK(state->status)) {
1168 9345 : return;
1169 : }
1170 :
1171 51923 : ok = dir_check_ftype(finfo->attr, state->attribute);
1172 51923 : if (!ok) {
1173 : /*
1174 : * Only process if attributes match. On SMB1 server
1175 : * does this, so on SMB2 we need to emulate in the
1176 : * client.
1177 : *
1178 : * https://bugzilla.samba.org/show_bug.cgi?id=10260
1179 : */
1180 0 : return;
1181 : }
1182 :
1183 51923 : state->status = state->fn(finfo, state->mask, state->private_data);
1184 :
1185 51923 : state->processed_file = true;
1186 :
1187 51923 : TALLOC_FREE(finfo);
1188 : }
1189 :
1190 7468 : NTSTATUS cli_list(struct cli_state *cli,
1191 : const char *mask,
1192 : uint32_t attribute,
1193 : NTSTATUS (*fn)(struct file_info *finfo,
1194 : const char *mask,
1195 : void *private_data),
1196 : void *private_data)
1197 : {
1198 7468 : TALLOC_CTX *frame = NULL;
1199 7468 : struct cli_list_sync_state state = {
1200 : .mask = mask,
1201 : .attribute = attribute,
1202 : .fn = fn,
1203 : .private_data = private_data,
1204 : };
1205 0 : struct tevent_context *ev;
1206 0 : struct tevent_req *req;
1207 7468 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1208 0 : uint16_t info_level;
1209 7468 : enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
1210 :
1211 7468 : frame = talloc_stackframe();
1212 :
1213 7468 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1214 : /*
1215 : * Can't use sync call while an async call is in flight
1216 : */
1217 0 : status = NT_STATUS_INVALID_PARAMETER;
1218 0 : goto fail;
1219 : }
1220 7468 : ev = samba_tevent_context_init(frame);
1221 7468 : if (ev == NULL) {
1222 0 : goto fail;
1223 : }
1224 :
1225 7468 : if (proto >= PROTOCOL_SMB2_02) {
1226 5241 : info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
1227 : } else {
1228 2227 : info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
1229 : ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
1230 : }
1231 :
1232 7468 : req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
1233 7468 : if (req == NULL) {
1234 0 : goto fail;
1235 : }
1236 7468 : tevent_req_set_callback(req, cli_list_sync_cb, &state);
1237 :
1238 7468 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1239 0 : goto fail;
1240 : }
1241 :
1242 7468 : status = state.status;
1243 :
1244 7468 : if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
1245 6834 : status = NT_STATUS_OK;
1246 : }
1247 :
1248 7468 : if (NT_STATUS_IS_OK(status) && !state.processed_file) {
1249 225 : status = NT_STATUS_NO_SUCH_FILE;
1250 : }
1251 :
1252 7243 : fail:
1253 7468 : TALLOC_FREE(frame);
1254 7468 : return status;
1255 : }
|