2 Unix SMB/CIFS implementation.
3 client directory list routines
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
25 #include "../libcli/smb/smbXcli_base.h"
27 /****************************************************************************
28 Check if a returned directory name is safe.
29 ****************************************************************************/
31 static NTSTATUS
is_bad_name(bool windows_names
, const char *name
)
33 const char *bad_name_p
= NULL
;
35 bad_name_p
= strchr(name
, '/');
36 if (bad_name_p
!= NULL
) {
38 * Windows and POSIX names can't have '/'.
39 * Server is attacking us.
41 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
44 bad_name_p
= strchr(name
, '\\');
45 if (bad_name_p
!= NULL
) {
47 * Windows names can't have '\\'.
48 * Server is attacking us.
50 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
56 /****************************************************************************
57 Check if a returned directory name is safe. Disconnect if server is
59 ****************************************************************************/
61 NTSTATUS
is_bad_finfo_name(const struct cli_state
*cli
,
62 const struct file_info
*finfo
)
64 NTSTATUS status
= NT_STATUS_OK
;
65 bool windows_names
= true;
67 if (cli
->requested_posix_capabilities
& CIFS_UNIX_POSIX_PATHNAMES_CAP
) {
68 windows_names
= false;
70 if (finfo
->name
!= NULL
) {
71 status
= is_bad_name(windows_names
, finfo
->name
);
72 if (!NT_STATUS_IS_OK(status
)) {
73 DBG_ERR("bad finfo->name\n");
77 if (finfo
->short_name
!= NULL
) {
78 status
= is_bad_name(windows_names
, finfo
->short_name
);
79 if (!NT_STATUS_IS_OK(status
)) {
80 DBG_ERR("bad finfo->short_name\n");
87 /****************************************************************************
88 Calculate a safe next_entry_offset.
89 ****************************************************************************/
91 static size_t calc_next_entry_offset(const char *base
, const char *pdata_end
)
93 size_t next_entry_offset
= (size_t)IVAL(base
,0);
95 if (next_entry_offset
== 0 ||
96 base
+ next_entry_offset
< base
||
97 base
+ next_entry_offset
> pdata_end
) {
98 next_entry_offset
= pdata_end
- base
;
100 return next_entry_offset
;
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 ****************************************************************************/
111 static size_t interpret_long_filename(TALLOC_CTX
*ctx
,
112 struct cli_state
*cli
,
114 const char *base_ptr
,
115 uint16_t recv_flags2
,
117 const char *pdata_end
,
118 struct file_info
*finfo
,
119 uint32_t *p_resume_key
,
120 DATA_BLOB
*p_last_name_raw
)
124 const char *base
= p
;
126 data_blob_free(p_last_name_raw
);
134 case SMB_FIND_INFO_STANDARD
: /* OS/2 understands this */
135 /* these dates are converted to GMT by
137 if (pdata_end
- base
< 27) {
138 return pdata_end
- base
;
141 * What we're returning here as ctime_ts is
142 * actually the server create time.
144 finfo
->btime_ts
= convert_time_t_to_timespec(
146 smb1cli_conn_server_time_zone(
148 finfo
->ctime_ts
= convert_time_t_to_timespec(
149 make_unix_date2(p
+4, smb1cli_conn_server_time_zone(cli
->conn
)));
150 finfo
->atime_ts
= convert_time_t_to_timespec(
151 make_unix_date2(p
+8, smb1cli_conn_server_time_zone(cli
->conn
)));
152 finfo
->mtime_ts
= convert_time_t_to_timespec(
153 make_unix_date2(p
+12, smb1cli_conn_server_time_zone(cli
->conn
)));
154 finfo
->size
= IVAL(p
,16);
155 finfo
->attr
= SVAL(p
,24);
158 if (recv_flags2
& FLAGS2_UNICODE_STRINGS
) {
159 p
+= ucs2_align(base_ptr
, p
, STR_UNICODE
);
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
172 if (p
+ len
> pdata_end
) {
173 return pdata_end
- base
;
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
180 ret
= pull_string_talloc(ctx
,
187 if (ret
== (size_t)-1) {
188 return pdata_end
- base
;
191 return PTR_DIFF(p
, base
);
193 case SMB_FIND_EA_SIZE
: /* this is what OS/2 uses mostly */
194 /* these dates are converted to GMT by
196 if (pdata_end
- base
< 31) {
197 return pdata_end
- base
;
200 * What we're returning here as ctime_ts is
201 * actually the server create time.
203 finfo
->btime_ts
= convert_time_t_to_timespec(
205 smb1cli_conn_server_time_zone(
207 finfo
->ctime_ts
= convert_time_t_to_timespec(
208 make_unix_date2(p
+4, smb1cli_conn_server_time_zone(cli
->conn
)));
209 finfo
->atime_ts
= convert_time_t_to_timespec(
210 make_unix_date2(p
+8, smb1cli_conn_server_time_zone(cli
->conn
)));
211 finfo
->mtime_ts
= convert_time_t_to_timespec(
212 make_unix_date2(p
+12, smb1cli_conn_server_time_zone(cli
->conn
)));
213 finfo
->size
= IVAL(p
,16);
214 finfo
->attr
= SVAL(p
,24);
217 /* check for unisys! */
218 if (p
+ len
+ 1 > pdata_end
) {
219 return pdata_end
- base
;
221 ret
= pull_string_talloc(ctx
,
228 if (ret
== (size_t)-1) {
229 return pdata_end
- base
;
232 return PTR_DIFF(p
, base
) + 1;
234 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO
: /* NT uses this, but also accepts 2 */
236 size_t namelen
, slen
;
238 if (pdata_end
- base
< 94) {
239 return pdata_end
- base
;
242 p
+= 4; /* next entry offset */
245 *p_resume_key
= IVAL(p
,0);
247 p
+= 4; /* fileindex */
249 /* Offset zero is "create time", not "change time". */
251 finfo
->atime_ts
= interpret_long_date(p
);
253 finfo
->mtime_ts
= interpret_long_date(p
);
255 finfo
->ctime_ts
= interpret_long_date(p
);
257 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(p
,0);
259 p
+= 8; /* alloc size */
260 finfo
->attr
= IVAL(p
,0);
264 p
+= 4; /* EA size */
267 /* Bad short name length. */
268 return pdata_end
- base
;
271 ret
= pull_string_talloc(ctx
,
278 if (ret
== (size_t)-1) {
279 return pdata_end
- base
;
281 p
+= 24; /* short name? */
282 if (p
+ namelen
< p
|| p
+ namelen
> pdata_end
) {
283 return pdata_end
- base
;
285 ret
= pull_string_talloc(ctx
,
292 if (ret
== (size_t)-1) {
293 return pdata_end
- base
;
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
301 if (p_last_name_raw
) {
302 *p_last_name_raw
= data_blob(NULL
, namelen
+2);
303 memcpy(p_last_name_raw
->data
, p
, namelen
);
304 SSVAL(p_last_name_raw
->data
, namelen
, 0);
306 return calc_next_entry_offset(base
, pdata_end
);
310 DEBUG(1,("Unknown long filename format %d\n",level
));
311 return calc_next_entry_offset(base
, pdata_end
);
314 /****************************************************************************
315 Interpret a short filename structure.
316 The length of the structure is returned.
317 ****************************************************************************/
319 static bool interpret_short_filename(TALLOC_CTX
*ctx
,
320 struct cli_state
*cli
,
322 struct file_info
*finfo
)
327 finfo
->attr
= CVAL(p
,21);
329 /* We don't get birth time. */
330 finfo
->btime_ts
.tv_sec
= 0;
331 finfo
->btime_ts
.tv_nsec
= 0;
332 /* this date is converted to GMT by make_unix_date */
333 finfo
->ctime_ts
.tv_sec
= make_unix_date(p
+22, smb1cli_conn_server_time_zone(cli
->conn
));
334 finfo
->ctime_ts
.tv_nsec
= 0;
335 finfo
->mtime_ts
.tv_sec
= finfo
->atime_ts
.tv_sec
= finfo
->ctime_ts
.tv_sec
;
336 finfo
->mtime_ts
.tv_nsec
= finfo
->atime_ts
.tv_nsec
= 0;
337 finfo
->size
= IVAL(p
,26);
338 ret
= pull_string_talloc(ctx
,
345 if (ret
== (size_t)-1) {
350 finfo
->short_name
= talloc_strdup(ctx
, finfo
->name
);
351 if (finfo
->short_name
== NULL
) {
358 struct cli_list_old_state
{
359 struct tevent_context
*ev
;
360 struct cli_state
*cli
;
365 uint8_t search_status
[23];
371 static void cli_list_old_done(struct tevent_req
*subreq
);
373 static struct tevent_req
*cli_list_old_send(TALLOC_CTX
*mem_ctx
,
374 struct tevent_context
*ev
,
375 struct cli_state
*cli
,
379 struct tevent_req
*req
, *subreq
;
380 struct cli_list_old_state
*state
;
382 static const uint16_t zero
= 0;
383 uint32_t usable_space
;
385 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_old_state
);
391 state
->attribute
= attribute
;
393 state
->mask
= talloc_strdup(state
, mask
);
394 if (tevent_req_nomem(state
->mask
, req
)) {
395 return tevent_req_post(req
, ev
);
397 state
->mask
= smb1_dfs_share_path(state
, cli
, state
->mask
);
398 if (tevent_req_nomem(state
->mask
, req
)) {
399 return tevent_req_post(req
, ev
);
401 usable_space
= cli_state_available_size(cli
, 100);
402 state
->num_asked
= usable_space
/ DIR_STRUCT_SIZE
;
404 SSVAL(state
->vwv
+ 0, 0, state
->num_asked
);
405 SSVAL(state
->vwv
+ 1, 0, state
->attribute
);
407 bytes
= talloc_array(state
, uint8_t, 1);
408 if (tevent_req_nomem(bytes
, req
)) {
409 return tevent_req_post(req
, ev
);
412 bytes
= smb_bytes_push_str(bytes
,
413 smbXcli_conn_use_unicode(cli
->conn
),
415 strlen(state
->mask
)+1,
418 bytes
= smb_bytes_push_bytes(bytes
, 5, (const uint8_t *)&zero
, 2);
419 if (tevent_req_nomem(bytes
, req
)) {
420 return tevent_req_post(req
, ev
);
423 subreq
= cli_smb_send(state
, state
->ev
, state
->cli
, SMBsearch
, 0, 0,
424 2, state
->vwv
, talloc_get_size(bytes
), bytes
);
425 if (tevent_req_nomem(subreq
, req
)) {
426 return tevent_req_post(req
, ev
);
428 tevent_req_set_callback(subreq
, cli_list_old_done
, req
);
432 static void cli_list_old_done(struct tevent_req
*subreq
)
434 struct tevent_req
*req
= tevent_req_callback_data(
435 subreq
, struct tevent_req
);
436 struct cli_list_old_state
*state
= tevent_req_data(
437 req
, struct cli_list_old_state
);
448 status
= cli_smb_recv(subreq
, state
, NULL
, 0, &wct
, &vwv
, &num_bytes
,
450 if (!NT_STATUS_IS_OK(status
)
451 && !NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
, ERRnofiles
))
452 && !NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
454 tevent_req_nterror(req
, status
);
457 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
, ERRnofiles
))
458 || NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
464 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
467 received
= SVAL(vwv
+ 0, 0);
472 * I don't think this can wrap. received is
473 * initialized from a 16-bit value.
475 if (num_bytes
< ((uint32_t)received
* DIR_STRUCT_SIZE
+ 3)) {
478 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
482 dirlist_len
= talloc_get_size(state
->dirlist
);
484 tmp
= talloc_realloc(
485 state
, state
->dirlist
, uint8_t,
486 dirlist_len
+ received
* DIR_STRUCT_SIZE
);
487 if (tevent_req_nomem(tmp
, req
)) {
490 state
->dirlist
= tmp
;
491 memcpy(state
->dirlist
+ dirlist_len
, bytes
+ 3,
492 received
* DIR_STRUCT_SIZE
);
494 SSVAL(state
->search_status
, 0, 21);
495 memcpy(state
->search_status
+ 2,
496 bytes
+ 3 + (received
-1)*DIR_STRUCT_SIZE
, 21);
499 if (state
->first
|| state
->done
) {
500 tevent_req_done(req
);
504 state
->num_asked
= 0;
509 state
->first
= false;
511 SSVAL(state
->vwv
+ 0, 0, state
->num_asked
);
512 SSVAL(state
->vwv
+ 1, 0, state
->attribute
);
514 bytes
= talloc_array(state
, uint8_t, 1);
515 if (tevent_req_nomem(bytes
, req
)) {
519 bytes
= smb_bytes_push_str(bytes
, smbXcli_conn_use_unicode(state
->cli
->conn
), "",
521 bytes
= smb_bytes_push_bytes(bytes
, 5, state
->search_status
,
522 sizeof(state
->search_status
));
523 if (tevent_req_nomem(bytes
, req
)) {
526 subreq
= cli_smb_send(state
, state
->ev
, state
->cli
, cmd
, 0, 0,
527 2, state
->vwv
, talloc_get_size(bytes
), bytes
);
528 if (tevent_req_nomem(subreq
, req
)) {
531 tevent_req_set_callback(subreq
, cli_list_old_done
, req
);
534 static NTSTATUS
cli_list_old_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
535 struct file_info
**pfinfo
)
537 struct cli_list_old_state
*state
= tevent_req_data(
538 req
, struct cli_list_old_state
);
540 size_t i
, num_received
;
541 struct file_info
*finfo
;
543 if (tevent_req_is_nterror(req
, &status
)) {
547 if (state
->dirlist
== NULL
) {
552 num_received
= talloc_array_length(state
->dirlist
) / DIR_STRUCT_SIZE
;
554 finfo
= talloc_array(mem_ctx
, struct file_info
, num_received
);
556 return NT_STATUS_NO_MEMORY
;
559 for (i
=0; i
<num_received
; i
++) {
560 if (!interpret_short_filename(
562 (char *)state
->dirlist
+ i
* DIR_STRUCT_SIZE
,
565 return NT_STATUS_NO_MEMORY
;
567 if (finfo
->name
== NULL
) {
569 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
571 status
= is_bad_finfo_name(state
->cli
, finfo
);
572 if (!NT_STATUS_IS_OK(status
)) {
573 smbXcli_conn_disconnect(state
->cli
->conn
, status
);
578 TALLOC_FREE(state
->dirlist
);
583 NTSTATUS
cli_list_old(struct cli_state
*cli
, const char *mask
,
585 NTSTATUS (*fn
)(struct file_info
*,
586 const char *, void *), void *state
)
588 TALLOC_CTX
*frame
= talloc_stackframe();
589 struct tevent_context
*ev
;
590 struct tevent_req
*req
;
591 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
592 struct file_info
*finfo
= NULL
;
595 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
597 * Can't use sync call while an async call is in flight
599 status
= NT_STATUS_INVALID_PARAMETER
;
602 ev
= samba_tevent_context_init(frame
);
606 req
= cli_list_old_send(frame
, ev
, cli
, mask
, attribute
);
610 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
613 status
= cli_list_old_recv(req
, frame
, &finfo
);
614 if (!NT_STATUS_IS_OK(status
)) {
617 num_finfo
= talloc_array_length(finfo
);
618 for (i
=0; i
<num_finfo
; i
++) {
619 status
= fn(&finfo
[i
], mask
, state
);
620 if (!NT_STATUS_IS_OK(status
)) {
629 struct cli_list_trans_state
{
630 struct tevent_context
*ev
;
631 struct cli_state
*cli
;
638 uint16_t max_matches
;
647 struct file_info
*finfo
;
650 static void cli_list_trans_done(struct tevent_req
*subreq
);
652 static struct tevent_req
*cli_list_trans_send(TALLOC_CTX
*mem_ctx
,
653 struct tevent_context
*ev
,
654 struct cli_state
*cli
,
659 struct tevent_req
*req
, *subreq
;
660 struct cli_list_trans_state
*state
;
662 uint16_t additional_flags2
= 0;
664 req
= tevent_req_create(mem_ctx
, &state
,
665 struct cli_list_trans_state
);
671 state
->mask
= talloc_strdup(state
, mask
);
672 if (tevent_req_nomem(state
->mask
, req
)) {
673 return tevent_req_post(req
, ev
);
675 state
->mask
= smb1_dfs_share_path(state
, cli
, state
->mask
);
676 if (tevent_req_nomem(state
->mask
, req
)) {
677 return tevent_req_post(req
, ev
);
679 state
->attribute
= attribute
;
680 state
->info_level
= info_level
;
681 state
->loop_count
= 0;
684 state
->max_matches
= 1366; /* Match W2k */
686 SSVAL(&state
->setup
[0], 0, TRANSACT2_FINDFIRST
);
688 state
->param
= talloc_array(state
, uint8_t, 12);
689 if (tevent_req_nomem(state
->param
, req
)) {
690 return tevent_req_post(req
, ev
);
693 SSVAL(state
->param
, 0, state
->attribute
);
694 SSVAL(state
->param
, 2, state
->max_matches
);
695 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 SSVAL(state
->param
, 6, state
->info_level
);
700 SIVAL(state
->param
, 8, 0);
702 state
->param
= trans2_bytes_push_str(state
->param
, smbXcli_conn_use_unicode(cli
->conn
),
703 state
->mask
, strlen(state
->mask
)+1,
705 if (tevent_req_nomem(state
->param
, req
)) {
706 return tevent_req_post(req
, ev
);
709 if (clistr_is_previous_version_path(state
->mask
)) {
710 additional_flags2
= FLAGS2_REPARSE_PATH
;
713 param_len
= talloc_get_size(state
->param
);
715 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
, additional_flags2
,
716 SMBtrans2
, NULL
, -1, 0, 0,
718 state
->param
, param_len
, 10,
719 NULL
, 0, CLI_BUFFER_SIZE
);
720 if (tevent_req_nomem(subreq
, req
)) {
721 return tevent_req_post(req
, ev
);
723 tevent_req_set_callback(subreq
, cli_list_trans_done
, req
);
727 static void cli_list_trans_done(struct tevent_req
*subreq
)
729 struct tevent_req
*req
= tevent_req_callback_data(
730 subreq
, struct tevent_req
);
731 struct cli_list_trans_state
*state
= tevent_req_data(
732 req
, struct cli_list_trans_state
);
740 struct file_info
*tmp
;
741 size_t old_num_finfo
;
742 uint16_t recv_flags2
;
746 uint32_t resume_key
= 0;
748 DATA_BLOB last_name_raw
;
749 struct file_info
*finfo
= NULL
;
751 uint16_t additional_flags2
= 0;
753 min_param
= (state
->first
? 6 : 4);
755 status
= cli_trans_recv(subreq
, talloc_tos(), &recv_flags2
,
757 ¶m
, min_param
, &num_param
,
758 &data
, 0, &num_data
);
760 if (!NT_STATUS_IS_OK(status
)) {
762 * TODO: retry, OS/2 nofiles
764 tevent_req_nterror(req
, status
);
769 state
->ff_dir_handle
= SVAL(param
, 0);
770 ff_searchcount
= SVAL(param
, 2);
771 ff_eos
= SVAL(param
, 4) != 0;
773 ff_searchcount
= SVAL(param
, 0);
774 ff_eos
= SVAL(param
, 2) != 0;
777 old_num_finfo
= talloc_array_length(state
->finfo
);
779 tmp
= talloc_realloc(state
, state
->finfo
, struct file_info
,
780 old_num_finfo
+ ff_searchcount
);
781 if (tevent_req_nomem(tmp
, req
)) {
786 p2
= p
= (char *)data
;
787 data_end
= (char *)data
+ num_data
;
788 last_name_raw
= data_blob_null
;
790 for (i
=0; i
<ff_searchcount
; i
++) {
791 if (p2
>= data_end
) {
795 if ((state
->info_level
== SMB_FIND_FILE_BOTH_DIRECTORY_INFO
)
796 && (i
== ff_searchcount
-1)) {
797 /* Last entry - fixup the last offset length. */
798 SIVAL(p2
, 0, PTR_DIFF((data
+ num_data
), p2
));
801 data_blob_free(&last_name_raw
);
803 finfo
= &state
->finfo
[old_num_finfo
+ i
];
805 p2
+= interpret_long_filename(
806 state
->finfo
, /* Stick fname to the array as such */
807 state
->cli
, state
->info_level
,
808 (char *)data
, recv_flags2
, p2
,
809 data_end
, finfo
, &resume_key
, &last_name_raw
);
811 if (finfo
->name
== NULL
) {
812 DEBUG(1, ("cli_list: Error: unable to parse name from "
813 "info level %d\n", state
->info_level
));
814 tevent_req_nterror(req
,
815 NT_STATUS_INVALID_NETWORK_RESPONSE
);
819 status
= is_bad_finfo_name(state
->cli
, finfo
);
820 if (!NT_STATUS_IS_OK(status
)) {
821 smbXcli_conn_disconnect(state
->cli
->conn
, status
);
822 tevent_req_nterror(req
, status
);
826 if (!state
->first
&& (state
->mask
[0] != '\0') &&
827 strcsequal(finfo
->name
, state
->mask
)) {
828 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
829 "already been seen?\n", finfo
->name
));
835 if (ff_searchcount
== 0) {
843 * Shrink state->finfo to the real length we received
845 tmp
= talloc_realloc(state
, state
->finfo
, struct file_info
,
847 if (tevent_req_nomem(tmp
, req
)) {
852 state
->first
= false;
855 data_blob_free(&last_name_raw
);
856 tevent_req_done(req
);
860 TALLOC_FREE(state
->mask
);
861 state
->mask
= talloc_strdup(state
, finfo
->name
);
862 if (tevent_req_nomem(state
->mask
, req
)) {
866 SSVAL(&state
->setup
[0], 0, TRANSACT2_FINDNEXT
);
868 param
= talloc_realloc(state
, state
->param
, uint8_t, 12);
869 if (tevent_req_nomem(param
, req
)) {
872 state
->param
= param
;
874 SSVAL(param
, 0, state
->ff_dir_handle
);
875 SSVAL(param
, 2, state
->max_matches
); /* max count */
876 SSVAL(param
, 4, state
->info_level
);
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.
881 SIVAL(param
, 6, resume_key
); /* ff_resume_key */
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
887 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 if (last_name_raw
.length
) {
891 state
->param
= trans2_bytes_push_bytes(state
->param
,
893 last_name_raw
.length
);
894 if (tevent_req_nomem(state
->param
, req
)) {
897 data_blob_free(&last_name_raw
);
899 state
->param
= trans2_bytes_push_str(state
->param
,
900 smbXcli_conn_use_unicode(state
->cli
->conn
),
902 strlen(state
->mask
)+1,
904 if (tevent_req_nomem(state
->param
, req
)) {
908 param_len
= talloc_get_size(state
->param
);
910 if (clistr_is_previous_version_path(state
->mask
)) {
911 additional_flags2
= FLAGS2_REPARSE_PATH
;
914 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
, additional_flags2
,
915 SMBtrans2
, NULL
, -1, 0, 0,
917 state
->param
, param_len
, 10,
918 NULL
, 0, CLI_BUFFER_SIZE
);
919 if (tevent_req_nomem(subreq
, req
)) {
922 tevent_req_set_callback(subreq
, cli_list_trans_done
, req
);
925 static NTSTATUS
cli_list_trans_recv(struct tevent_req
*req
,
927 struct file_info
**finfo
)
929 struct cli_list_trans_state
*state
= tevent_req_data(
930 req
, struct cli_list_trans_state
);
933 if (tevent_req_is_nterror(req
, &status
)) {
936 *finfo
= talloc_move(mem_ctx
, &state
->finfo
);
940 NTSTATUS
cli_list_trans(struct cli_state
*cli
, const char *mask
,
941 uint32_t attribute
, int info_level
,
943 struct file_info
*finfo
,
948 TALLOC_CTX
*frame
= talloc_stackframe();
949 struct tevent_context
*ev
;
950 struct tevent_req
*req
;
952 struct file_info
*finfo
= NULL
;
953 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
955 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
957 * Can't use sync call while an async call is in flight
959 status
= NT_STATUS_INVALID_PARAMETER
;
962 ev
= samba_tevent_context_init(frame
);
966 req
= cli_list_trans_send(frame
, ev
, cli
, mask
, attribute
, info_level
);
970 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
973 status
= cli_list_trans_recv(req
, frame
, &finfo
);
974 if (!NT_STATUS_IS_OK(status
)) {
977 num_finfo
= talloc_array_length(finfo
);
978 for (i
=0; i
<num_finfo
; i
++) {
979 status
= fn(&finfo
[i
], mask
, private_data
);
980 if (!NT_STATUS_IS_OK(status
)) {
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
;
998 static void cli_list_done(struct tevent_req
*subreq
);
1000 struct tevent_req
*cli_list_send(TALLOC_CTX
*mem_ctx
,
1001 struct tevent_context
*ev
,
1002 struct cli_state
*cli
,
1005 uint16_t info_level
,
1008 struct tevent_req
*req
= NULL
;
1009 struct cli_list_state
*state
;
1010 enum protocol_types proto
= smbXcli_conn_protocol(cli
->conn
);
1012 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_state
);
1018 if (proto
>= PROTOCOL_SMB2_02
) {
1019 state
->subreq
= cli_smb2_list_send(state
, ev
, cli
, mask
,
1021 state
->recv_fn
= cli_smb2_list_recv
;
1022 } else if (proto
>= PROTOCOL_LANMAN2
) {
1023 state
->subreq
= cli_list_trans_send(
1024 state
, ev
, cli
, mask
, attribute
, info_level
);
1025 state
->recv_fn
= cli_list_trans_recv
;
1027 state
->subreq
= cli_list_old_send(
1028 state
, ev
, cli
, mask
, attribute
);
1029 state
->recv_fn
= cli_list_old_recv
;
1031 if (tevent_req_nomem(state
->subreq
, req
)) {
1032 return tevent_req_post(req
, ev
);
1034 tevent_req_set_callback(state
->subreq
, cli_list_done
, req
);
1038 static void cli_list_done(struct tevent_req
*subreq
)
1040 struct tevent_req
*req
= tevent_req_callback_data(
1041 subreq
, struct tevent_req
);
1042 struct cli_list_state
*state
= tevent_req_data(
1043 req
, struct cli_list_state
);
1046 SMB_ASSERT(subreq
== state
->subreq
);
1049 * We don't want to be called by the lowerlevel routines
1050 * from within state->recv_fn()
1052 tevent_req_set_callback(subreq
, NULL
, NULL
);
1054 status
= state
->recv_fn(subreq
, state
, &state
->finfo
);
1055 if (NT_STATUS_EQUAL(status
, NT_STATUS_RETRY
)) {
1056 /* We'll get back here */
1057 tevent_req_set_callback(subreq
, cli_list_done
, req
);
1061 if (tevent_req_nterror(req
, status
)) {
1064 tevent_req_notify_callback(req
);
1067 NTSTATUS
cli_list_recv(
1068 struct tevent_req
*req
,
1069 TALLOC_CTX
*mem_ctx
,
1070 struct file_info
**pfinfo
)
1072 struct cli_list_state
*state
= tevent_req_data(
1073 req
, struct cli_list_state
);
1075 struct file_info
*finfo
= NULL
;
1079 in_progress
= tevent_req_is_in_progress(req
);
1082 if (!tevent_req_is_nterror(req
, &status
)) {
1083 status
= NT_STATUS_NO_MORE_FILES
;
1088 if (state
->finfo
== NULL
) {
1089 status
= state
->recv_fn(state
->subreq
, state
, &state
->finfo
);
1091 if (NT_STATUS_EQUAL(status
, NT_STATUS_RETRY
)) {
1092 tevent_req_set_callback(
1093 state
->subreq
, cli_list_done
, req
);
1094 return NT_STATUS_RETRY
;
1097 if (NT_STATUS_IS_OK(status
) && (state
->finfo
== NULL
)) {
1098 status
= NT_STATUS_NO_MORE_FILES
;
1101 if (tevent_req_nterror(req
, status
)) {
1105 state
->num_received
= 0;
1108 num_results
= talloc_array_length(state
->finfo
);
1110 if (num_results
== 1) {
1111 finfo
= talloc_move(mem_ctx
, &state
->finfo
);
1113 struct file_info
*src_finfo
=
1114 &state
->finfo
[state
->num_received
];
1116 finfo
= talloc(mem_ctx
, struct file_info
);
1117 if (finfo
== NULL
) {
1118 return NT_STATUS_NO_MEMORY
;
1120 *finfo
= *src_finfo
;
1121 finfo
->name
= talloc_move(finfo
, &src_finfo
->name
);
1122 finfo
->short_name
= talloc_move(finfo
, &src_finfo
->short_name
);
1125 state
->num_received
+= 1;
1127 if (state
->num_received
== num_results
) {
1128 TALLOC_FREE(state
->finfo
);
1131 tevent_req_defer_callback(req
, state
->ev
);
1132 tevent_req_notify_callback(req
);
1135 return NT_STATUS_OK
;
1138 struct cli_list_sync_state
{
1141 NTSTATUS (*fn
)(struct file_info
*finfo
,
1143 void *private_data
);
1146 bool processed_file
;
1149 static void cli_list_sync_cb(struct tevent_req
*subreq
)
1151 struct cli_list_sync_state
*state
=
1152 tevent_req_callback_data_void(subreq
);
1153 struct file_info
*finfo
;
1156 state
->status
= cli_list_recv(subreq
, talloc_tos(), &finfo
);
1157 /* No TALLOC_FREE(subreq), we get here more than once */
1159 if (NT_STATUS_EQUAL(state
->status
, NT_STATUS_RETRY
)) {
1161 * The lowlevel SMB call was rearmed, we'll get back
1162 * here when it's done.
1164 state
->status
= NT_STATUS_OK
;
1168 if (!NT_STATUS_IS_OK(state
->status
)) {
1172 ok
= dir_check_ftype(finfo
->attr
, state
->attribute
);
1175 * Only process if attributes match. On SMB1 server
1176 * does this, so on SMB2 we need to emulate in the
1179 * https://bugzilla.samba.org/show_bug.cgi?id=10260
1184 state
->status
= state
->fn(finfo
, state
->mask
, state
->private_data
);
1186 state
->processed_file
= true;
1191 NTSTATUS
cli_list(struct cli_state
*cli
,
1194 NTSTATUS (*fn
)(struct file_info
*finfo
,
1196 void *private_data
),
1199 TALLOC_CTX
*frame
= NULL
;
1200 struct cli_list_sync_state state
= {
1202 .attribute
= attribute
,
1204 .private_data
= private_data
,
1206 struct tevent_context
*ev
;
1207 struct tevent_req
*req
;
1208 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1209 uint16_t info_level
;
1210 enum protocol_types proto
= smbXcli_conn_protocol(cli
->conn
);
1212 frame
= talloc_stackframe();
1214 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1216 * Can't use sync call while an async call is in flight
1218 status
= NT_STATUS_INVALID_PARAMETER
;
1221 ev
= samba_tevent_context_init(frame
);
1226 if (proto
>= PROTOCOL_SMB2_02
) {
1227 info_level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
;
1229 info_level
= (smb1cli_conn_capabilities(cli
->conn
) & CAP_NT_SMBS
)
1230 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO
: SMB_FIND_INFO_STANDARD
;
1233 req
= cli_list_send(frame
, ev
, cli
, mask
, attribute
, info_level
, false);
1237 tevent_req_set_callback(req
, cli_list_sync_cb
, &state
);
1239 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1243 status
= state
.status
;
1245 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_FILES
)) {
1246 status
= NT_STATUS_OK
;
1249 if (NT_STATUS_IS_OK(status
) && !state
.processed_file
) {
1250 status
= NT_STATUS_NO_SUCH_FILE
;