| 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 | Calculate a safe next_entry_offset.
|
|---|
| 29 | ****************************************************************************/
|
|---|
| 30 |
|
|---|
| 31 | static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
|
|---|
| 32 | {
|
|---|
| 33 | size_t next_entry_offset = (size_t)IVAL(base,0);
|
|---|
| 34 |
|
|---|
| 35 | if (next_entry_offset == 0 ||
|
|---|
| 36 | base + next_entry_offset < base ||
|
|---|
| 37 | base + next_entry_offset > pdata_end) {
|
|---|
| 38 | next_entry_offset = pdata_end - base;
|
|---|
| 39 | }
|
|---|
| 40 | return next_entry_offset;
|
|---|
| 41 | }
|
|---|
| 42 |
|
|---|
| 43 | /****************************************************************************
|
|---|
| 44 | Interpret a long filename structure - this is mostly guesses at the moment.
|
|---|
| 45 | The length of the structure is returned
|
|---|
| 46 | The structure of a long filename depends on the info level.
|
|---|
| 47 | SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
|
|---|
| 48 | by NT and SMB_FIND_EA_SIZE is used by OS/2
|
|---|
| 49 | ****************************************************************************/
|
|---|
| 50 |
|
|---|
| 51 | static size_t interpret_long_filename(TALLOC_CTX *ctx,
|
|---|
| 52 | struct cli_state *cli,
|
|---|
| 53 | int level,
|
|---|
| 54 | const char *base_ptr,
|
|---|
| 55 | uint16_t recv_flags2,
|
|---|
| 56 | const char *p,
|
|---|
| 57 | const char *pdata_end,
|
|---|
| 58 | struct file_info *finfo,
|
|---|
| 59 | uint32_t *p_resume_key,
|
|---|
| 60 | DATA_BLOB *p_last_name_raw)
|
|---|
| 61 | {
|
|---|
| 62 | int len;
|
|---|
| 63 | size_t ret;
|
|---|
| 64 | const char *base = p;
|
|---|
| 65 |
|
|---|
| 66 | data_blob_free(p_last_name_raw);
|
|---|
| 67 |
|
|---|
| 68 | if (p_resume_key) {
|
|---|
| 69 | *p_resume_key = 0;
|
|---|
| 70 | }
|
|---|
| 71 | ZERO_STRUCTP(finfo);
|
|---|
| 72 |
|
|---|
| 73 | switch (level) {
|
|---|
| 74 | case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
|
|---|
| 75 | /* these dates are converted to GMT by
|
|---|
| 76 | make_unix_date */
|
|---|
| 77 | if (pdata_end - base < 27) {
|
|---|
| 78 | return pdata_end - base;
|
|---|
| 79 | }
|
|---|
| 80 | finfo->ctime_ts = convert_time_t_to_timespec(
|
|---|
| 81 | make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
|
|---|
| 82 | finfo->atime_ts = convert_time_t_to_timespec(
|
|---|
| 83 | make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
|
|---|
| 84 | finfo->mtime_ts = convert_time_t_to_timespec(
|
|---|
| 85 | make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
|
|---|
| 86 | finfo->size = IVAL(p,16);
|
|---|
| 87 | finfo->mode = CVAL(p,24);
|
|---|
| 88 | len = CVAL(p, 26);
|
|---|
| 89 | p += 27;
|
|---|
| 90 | if (recv_flags2 & FLAGS2_UNICODE_STRINGS) {
|
|---|
| 91 | p += ucs2_align(base_ptr, p, STR_UNICODE);
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | /* We can safely use len here (which is required by OS/2)
|
|---|
| 95 | * and the NAS-BASIC server instead of +2 or +1 as the
|
|---|
| 96 | * STR_TERMINATE flag below is
|
|---|
| 97 | * actually used as the length calculation.
|
|---|
| 98 | * The len is merely an upper bound.
|
|---|
| 99 | * Due to the explicit 2 byte null termination
|
|---|
| 100 | * in cli_receive_trans/cli_receive_nt_trans
|
|---|
| 101 | * we know this is safe. JRA + kukks
|
|---|
| 102 | */
|
|---|
| 103 |
|
|---|
| 104 | if (p + len > pdata_end) {
|
|---|
| 105 | return pdata_end - base;
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | /* the len+2 below looks strange but it is
|
|---|
| 109 | important to cope with the differences
|
|---|
| 110 | between win2000 and win9x for this call
|
|---|
| 111 | (tridge) */
|
|---|
| 112 | ret = clistr_pull_talloc(ctx,
|
|---|
| 113 | base_ptr,
|
|---|
| 114 | recv_flags2,
|
|---|
| 115 | &finfo->name,
|
|---|
| 116 | p,
|
|---|
| 117 | len+2,
|
|---|
| 118 | STR_TERMINATE);
|
|---|
| 119 | if (ret == (size_t)-1) {
|
|---|
| 120 | return pdata_end - base;
|
|---|
| 121 | }
|
|---|
| 122 | p += ret;
|
|---|
| 123 | return PTR_DIFF(p, base);
|
|---|
| 124 |
|
|---|
| 125 | case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
|
|---|
| 126 | /* these dates are converted to GMT by
|
|---|
| 127 | make_unix_date */
|
|---|
| 128 | if (pdata_end - base < 31) {
|
|---|
| 129 | return pdata_end - base;
|
|---|
| 130 | }
|
|---|
| 131 | finfo->ctime_ts = convert_time_t_to_timespec(
|
|---|
| 132 | make_unix_date2(p+4, smb1cli_conn_server_time_zone(cli->conn)));
|
|---|
| 133 | finfo->atime_ts = convert_time_t_to_timespec(
|
|---|
| 134 | make_unix_date2(p+8, smb1cli_conn_server_time_zone(cli->conn)));
|
|---|
| 135 | finfo->mtime_ts = convert_time_t_to_timespec(
|
|---|
| 136 | make_unix_date2(p+12, smb1cli_conn_server_time_zone(cli->conn)));
|
|---|
| 137 | finfo->size = IVAL(p,16);
|
|---|
| 138 | finfo->mode = CVAL(p,24);
|
|---|
| 139 | len = CVAL(p, 30);
|
|---|
| 140 | p += 31;
|
|---|
| 141 | /* check for unisys! */
|
|---|
| 142 | if (p + len + 1 > pdata_end) {
|
|---|
| 143 | return pdata_end - base;
|
|---|
| 144 | }
|
|---|
| 145 | ret = clistr_pull_talloc(ctx,
|
|---|
| 146 | base_ptr,
|
|---|
| 147 | recv_flags2,
|
|---|
| 148 | &finfo->name,
|
|---|
| 149 | p,
|
|---|
| 150 | len,
|
|---|
| 151 | STR_NOALIGN);
|
|---|
| 152 | if (ret == (size_t)-1) {
|
|---|
| 153 | return pdata_end - base;
|
|---|
| 154 | }
|
|---|
| 155 | p += ret;
|
|---|
| 156 | return PTR_DIFF(p, base) + 1;
|
|---|
| 157 |
|
|---|
| 158 | case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
|
|---|
| 159 | {
|
|---|
| 160 | size_t namelen, slen;
|
|---|
| 161 |
|
|---|
| 162 | if (pdata_end - base < 94) {
|
|---|
| 163 | return pdata_end - base;
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | p += 4; /* next entry offset */
|
|---|
| 167 |
|
|---|
| 168 | if (p_resume_key) {
|
|---|
| 169 | *p_resume_key = IVAL(p,0);
|
|---|
| 170 | }
|
|---|
| 171 | p += 4; /* fileindex */
|
|---|
| 172 |
|
|---|
| 173 | /* Offset zero is "create time", not "change time". */
|
|---|
| 174 | p += 8;
|
|---|
| 175 | finfo->atime_ts = interpret_long_date(p);
|
|---|
| 176 | p += 8;
|
|---|
| 177 | finfo->mtime_ts = interpret_long_date(p);
|
|---|
| 178 | p += 8;
|
|---|
| 179 | finfo->ctime_ts = interpret_long_date(p);
|
|---|
| 180 | p += 8;
|
|---|
| 181 | finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
|
|---|
| 182 | p += 8;
|
|---|
| 183 | p += 8; /* alloc size */
|
|---|
| 184 | finfo->mode = CVAL(p,0);
|
|---|
| 185 | p += 4;
|
|---|
| 186 | namelen = IVAL(p,0);
|
|---|
| 187 | p += 4;
|
|---|
| 188 | p += 4; /* EA size */
|
|---|
| 189 | slen = CVAL(p, 0);
|
|---|
| 190 | if (slen > 24) {
|
|---|
| 191 | /* Bad short name length. */
|
|---|
| 192 | return pdata_end - base;
|
|---|
| 193 | }
|
|---|
| 194 | p += 2;
|
|---|
| 195 | ret = clistr_pull_talloc(ctx,
|
|---|
| 196 | base_ptr,
|
|---|
| 197 | recv_flags2,
|
|---|
| 198 | &finfo->short_name,
|
|---|
| 199 | p,
|
|---|
| 200 | slen,
|
|---|
| 201 | STR_UNICODE);
|
|---|
| 202 | if (ret == (size_t)-1) {
|
|---|
| 203 | return pdata_end - base;
|
|---|
| 204 | }
|
|---|
| 205 | p += 24; /* short name? */
|
|---|
| 206 | if (p + namelen < p || p + namelen > pdata_end) {
|
|---|
| 207 | return pdata_end - base;
|
|---|
| 208 | }
|
|---|
| 209 | ret = clistr_pull_talloc(ctx,
|
|---|
| 210 | base_ptr,
|
|---|
| 211 | recv_flags2,
|
|---|
| 212 | &finfo->name,
|
|---|
| 213 | p,
|
|---|
| 214 | namelen,
|
|---|
| 215 | 0);
|
|---|
| 216 | if (ret == (size_t)-1) {
|
|---|
| 217 | return pdata_end - base;
|
|---|
| 218 | }
|
|---|
| 219 |
|
|---|
| 220 | /* To be robust in the face of unicode conversion failures
|
|---|
| 221 | we need to copy the raw bytes of the last name seen here.
|
|---|
| 222 | Namelen doesn't include the terminating unicode null, so
|
|---|
| 223 | copy it here. */
|
|---|
| 224 |
|
|---|
| 225 | if (p_last_name_raw) {
|
|---|
| 226 | *p_last_name_raw = data_blob(NULL, namelen+2);
|
|---|
| 227 | memcpy(p_last_name_raw->data, p, namelen);
|
|---|
| 228 | SSVAL(p_last_name_raw->data, namelen, 0);
|
|---|
| 229 | }
|
|---|
| 230 | return calc_next_entry_offset(base, pdata_end);
|
|---|
| 231 | }
|
|---|
| 232 | }
|
|---|
| 233 |
|
|---|
| 234 | DEBUG(1,("Unknown long filename format %d\n",level));
|
|---|
| 235 | return calc_next_entry_offset(base, pdata_end);
|
|---|
| 236 | }
|
|---|
| 237 |
|
|---|
| 238 | /****************************************************************************
|
|---|
| 239 | Interpret a short filename structure.
|
|---|
| 240 | The length of the structure is returned.
|
|---|
| 241 | ****************************************************************************/
|
|---|
| 242 |
|
|---|
| 243 | static bool interpret_short_filename(TALLOC_CTX *ctx,
|
|---|
| 244 | struct cli_state *cli,
|
|---|
| 245 | char *p,
|
|---|
| 246 | struct file_info *finfo)
|
|---|
| 247 | {
|
|---|
| 248 | size_t ret;
|
|---|
| 249 | ZERO_STRUCTP(finfo);
|
|---|
| 250 |
|
|---|
| 251 | finfo->mode = CVAL(p,21);
|
|---|
| 252 |
|
|---|
| 253 | /* this date is converted to GMT by make_unix_date */
|
|---|
| 254 | finfo->ctime_ts.tv_sec = make_unix_date(p+22, smb1cli_conn_server_time_zone(cli->conn));
|
|---|
| 255 | finfo->ctime_ts.tv_nsec = 0;
|
|---|
| 256 | finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
|
|---|
| 257 | finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
|
|---|
| 258 | finfo->size = IVAL(p,26);
|
|---|
| 259 | ret = clistr_pull_talloc(ctx,
|
|---|
| 260 | NULL,
|
|---|
| 261 | 0,
|
|---|
| 262 | &finfo->name,
|
|---|
| 263 | p+30,
|
|---|
| 264 | 12,
|
|---|
| 265 | STR_ASCII);
|
|---|
| 266 | if (ret == (size_t)-1) {
|
|---|
| 267 | return false;
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | if (finfo->name) {
|
|---|
| 271 | finfo->short_name = talloc_strdup(ctx, finfo->name);
|
|---|
| 272 | if (finfo->short_name == NULL) {
|
|---|
| 273 | return false;
|
|---|
| 274 | }
|
|---|
| 275 | }
|
|---|
| 276 | return true;
|
|---|
| 277 | }
|
|---|
| 278 |
|
|---|
| 279 | struct cli_list_old_state {
|
|---|
| 280 | struct tevent_context *ev;
|
|---|
| 281 | struct cli_state *cli;
|
|---|
| 282 | uint16_t vwv[2];
|
|---|
| 283 | char *mask;
|
|---|
| 284 | int num_asked;
|
|---|
| 285 | uint16_t attribute;
|
|---|
| 286 | uint8_t search_status[23];
|
|---|
| 287 | bool first;
|
|---|
| 288 | bool done;
|
|---|
| 289 | uint8_t *dirlist;
|
|---|
| 290 | };
|
|---|
| 291 |
|
|---|
| 292 | static void cli_list_old_done(struct tevent_req *subreq);
|
|---|
| 293 |
|
|---|
| 294 | static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
|
|---|
| 295 | struct tevent_context *ev,
|
|---|
| 296 | struct cli_state *cli,
|
|---|
| 297 | const char *mask,
|
|---|
| 298 | uint16_t attribute)
|
|---|
| 299 | {
|
|---|
| 300 | struct tevent_req *req, *subreq;
|
|---|
| 301 | struct cli_list_old_state *state;
|
|---|
| 302 | uint8_t *bytes;
|
|---|
| 303 | static const uint16_t zero = 0;
|
|---|
| 304 | uint32_t usable_space;
|
|---|
| 305 |
|
|---|
| 306 | req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
|
|---|
| 307 | if (req == NULL) {
|
|---|
| 308 | return NULL;
|
|---|
| 309 | }
|
|---|
| 310 | state->ev = ev;
|
|---|
| 311 | state->cli = cli;
|
|---|
| 312 | state->attribute = attribute;
|
|---|
| 313 | state->first = true;
|
|---|
| 314 | state->mask = talloc_strdup(state, mask);
|
|---|
| 315 | if (tevent_req_nomem(state->mask, req)) {
|
|---|
| 316 | return tevent_req_post(req, ev);
|
|---|
| 317 | }
|
|---|
| 318 | usable_space = cli_state_available_size(cli, 100);
|
|---|
| 319 | state->num_asked = usable_space / DIR_STRUCT_SIZE;
|
|---|
| 320 |
|
|---|
| 321 | SSVAL(state->vwv + 0, 0, state->num_asked);
|
|---|
| 322 | SSVAL(state->vwv + 1, 0, state->attribute);
|
|---|
| 323 |
|
|---|
| 324 | bytes = talloc_array(state, uint8_t, 1);
|
|---|
| 325 | if (tevent_req_nomem(bytes, req)) {
|
|---|
| 326 | return tevent_req_post(req, ev);
|
|---|
| 327 | }
|
|---|
| 328 | bytes[0] = 4;
|
|---|
| 329 | bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), mask,
|
|---|
| 330 | strlen(mask)+1, NULL);
|
|---|
| 331 |
|
|---|
| 332 | bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
|
|---|
| 333 | if (tevent_req_nomem(bytes, req)) {
|
|---|
| 334 | return tevent_req_post(req, ev);
|
|---|
| 335 | }
|
|---|
| 336 |
|
|---|
| 337 | subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch,
|
|---|
| 338 | 0, 2, state->vwv, talloc_get_size(bytes), bytes);
|
|---|
| 339 | if (tevent_req_nomem(subreq, req)) {
|
|---|
| 340 | return tevent_req_post(req, ev);
|
|---|
| 341 | }
|
|---|
| 342 | tevent_req_set_callback(subreq, cli_list_old_done, req);
|
|---|
| 343 | return req;
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | static void cli_list_old_done(struct tevent_req *subreq)
|
|---|
| 347 | {
|
|---|
| 348 | struct tevent_req *req = tevent_req_callback_data(
|
|---|
| 349 | subreq, struct tevent_req);
|
|---|
| 350 | struct cli_list_old_state *state = tevent_req_data(
|
|---|
| 351 | req, struct cli_list_old_state);
|
|---|
| 352 | NTSTATUS status;
|
|---|
| 353 | uint8_t cmd;
|
|---|
| 354 | uint8_t wct;
|
|---|
| 355 | uint16_t *vwv;
|
|---|
| 356 | uint32_t num_bytes;
|
|---|
| 357 | uint8_t *bytes;
|
|---|
| 358 | uint16_t received;
|
|---|
| 359 | size_t dirlist_len;
|
|---|
| 360 | uint8_t *tmp;
|
|---|
| 361 |
|
|---|
| 362 | status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
|
|---|
| 363 | &bytes);
|
|---|
| 364 | if (!NT_STATUS_IS_OK(status)
|
|---|
| 365 | && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
|
|---|
| 366 | && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
|
|---|
| 367 | TALLOC_FREE(subreq);
|
|---|
| 368 | tevent_req_nterror(req, status);
|
|---|
| 369 | return;
|
|---|
| 370 | }
|
|---|
| 371 | if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
|
|---|
| 372 | || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
|
|---|
| 373 | received = 0;
|
|---|
| 374 | } else {
|
|---|
| 375 | if (wct < 1) {
|
|---|
| 376 | TALLOC_FREE(subreq);
|
|---|
| 377 | tevent_req_nterror(
|
|---|
| 378 | req, NT_STATUS_INVALID_NETWORK_RESPONSE);
|
|---|
| 379 | return;
|
|---|
| 380 | }
|
|---|
| 381 | received = SVAL(vwv + 0, 0);
|
|---|
| 382 | }
|
|---|
| 383 |
|
|---|
| 384 | if (received > 0) {
|
|---|
| 385 | /*
|
|---|
| 386 | * I don't think this can wrap. received is
|
|---|
| 387 | * initialized from a 16-bit value.
|
|---|
| 388 | */
|
|---|
| 389 | if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) {
|
|---|
| 390 | TALLOC_FREE(subreq);
|
|---|
| 391 | tevent_req_nterror(
|
|---|
| 392 | req, NT_STATUS_INVALID_NETWORK_RESPONSE);
|
|---|
| 393 | return;
|
|---|
| 394 | }
|
|---|
| 395 |
|
|---|
| 396 | dirlist_len = talloc_get_size(state->dirlist);
|
|---|
| 397 |
|
|---|
| 398 | tmp = talloc_realloc(
|
|---|
| 399 | state, state->dirlist, uint8_t,
|
|---|
| 400 | dirlist_len + received * DIR_STRUCT_SIZE);
|
|---|
| 401 | if (tevent_req_nomem(tmp, req)) {
|
|---|
| 402 | return;
|
|---|
| 403 | }
|
|---|
| 404 | state->dirlist = tmp;
|
|---|
| 405 | memcpy(state->dirlist + dirlist_len, bytes + 3,
|
|---|
| 406 | received * DIR_STRUCT_SIZE);
|
|---|
| 407 |
|
|---|
| 408 | SSVAL(state->search_status, 0, 21);
|
|---|
| 409 | memcpy(state->search_status + 2,
|
|---|
| 410 | bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
|
|---|
| 411 | cmd = SMBsearch;
|
|---|
| 412 | } else {
|
|---|
| 413 | if (state->first || state->done) {
|
|---|
| 414 | tevent_req_done(req);
|
|---|
| 415 | return;
|
|---|
| 416 | }
|
|---|
| 417 | state->done = true;
|
|---|
| 418 | state->num_asked = 0;
|
|---|
| 419 | cmd = SMBfclose;
|
|---|
| 420 | }
|
|---|
| 421 | TALLOC_FREE(subreq);
|
|---|
| 422 |
|
|---|
| 423 | state->first = false;
|
|---|
| 424 |
|
|---|
| 425 | SSVAL(state->vwv + 0, 0, state->num_asked);
|
|---|
| 426 | SSVAL(state->vwv + 1, 0, state->attribute);
|
|---|
| 427 |
|
|---|
| 428 | bytes = talloc_array(state, uint8_t, 1);
|
|---|
| 429 | if (tevent_req_nomem(bytes, req)) {
|
|---|
| 430 | return;
|
|---|
| 431 | }
|
|---|
| 432 | bytes[0] = 4;
|
|---|
| 433 | bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(state->cli->conn), "",
|
|---|
| 434 | 1, NULL);
|
|---|
| 435 | bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
|
|---|
| 436 | sizeof(state->search_status));
|
|---|
| 437 | if (tevent_req_nomem(bytes, req)) {
|
|---|
| 438 | return;
|
|---|
| 439 | }
|
|---|
| 440 | subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0,
|
|---|
| 441 | 2, state->vwv, talloc_get_size(bytes), bytes);
|
|---|
| 442 | if (tevent_req_nomem(subreq, req)) {
|
|---|
| 443 | return;
|
|---|
| 444 | }
|
|---|
| 445 | tevent_req_set_callback(subreq, cli_list_old_done, req);
|
|---|
| 446 | }
|
|---|
| 447 |
|
|---|
| 448 | static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
|---|
| 449 | struct file_info **pfinfo)
|
|---|
| 450 | {
|
|---|
| 451 | struct cli_list_old_state *state = tevent_req_data(
|
|---|
| 452 | req, struct cli_list_old_state);
|
|---|
| 453 | NTSTATUS status;
|
|---|
| 454 | size_t i, num_received;
|
|---|
| 455 | struct file_info *finfo;
|
|---|
| 456 |
|
|---|
| 457 | if (tevent_req_is_nterror(req, &status)) {
|
|---|
| 458 | return status;
|
|---|
| 459 | }
|
|---|
| 460 |
|
|---|
| 461 | num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
|
|---|
| 462 |
|
|---|
| 463 | finfo = talloc_array(mem_ctx, struct file_info, num_received);
|
|---|
| 464 | if (finfo == NULL) {
|
|---|
| 465 | return NT_STATUS_NO_MEMORY;
|
|---|
| 466 | }
|
|---|
| 467 |
|
|---|
| 468 | for (i=0; i<num_received; i++) {
|
|---|
| 469 | if (!interpret_short_filename(
|
|---|
| 470 | finfo, state->cli,
|
|---|
| 471 | (char *)state->dirlist + i * DIR_STRUCT_SIZE,
|
|---|
| 472 | &finfo[i])) {
|
|---|
| 473 | TALLOC_FREE(finfo);
|
|---|
| 474 | return NT_STATUS_NO_MEMORY;
|
|---|
| 475 | }
|
|---|
| 476 | }
|
|---|
| 477 | *pfinfo = finfo;
|
|---|
| 478 | return NT_STATUS_OK;
|
|---|
| 479 | }
|
|---|
| 480 |
|
|---|
| 481 | NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
|
|---|
| 482 | uint16_t attribute,
|
|---|
| 483 | NTSTATUS (*fn)(const char *, struct file_info *,
|
|---|
| 484 | const char *, void *), void *state)
|
|---|
| 485 | {
|
|---|
| 486 | TALLOC_CTX *frame = talloc_stackframe();
|
|---|
| 487 | struct tevent_context *ev;
|
|---|
| 488 | struct tevent_req *req;
|
|---|
| 489 | NTSTATUS status = NT_STATUS_NO_MEMORY;
|
|---|
| 490 | struct file_info *finfo;
|
|---|
| 491 | size_t i, num_finfo;
|
|---|
| 492 |
|
|---|
| 493 | if (smbXcli_conn_has_async_calls(cli->conn)) {
|
|---|
| 494 | /*
|
|---|
| 495 | * Can't use sync call while an async call is in flight
|
|---|
| 496 | */
|
|---|
| 497 | status = NT_STATUS_INVALID_PARAMETER;
|
|---|
| 498 | goto fail;
|
|---|
| 499 | }
|
|---|
| 500 | ev = samba_tevent_context_init(frame);
|
|---|
| 501 | if (ev == NULL) {
|
|---|
| 502 | goto fail;
|
|---|
| 503 | }
|
|---|
| 504 | req = cli_list_old_send(frame, ev, cli, mask, attribute);
|
|---|
| 505 | if (req == NULL) {
|
|---|
| 506 | goto fail;
|
|---|
| 507 | }
|
|---|
| 508 | if (!tevent_req_poll_ntstatus(req, ev, &status)) {
|
|---|
| 509 | goto fail;
|
|---|
| 510 | }
|
|---|
| 511 | status = cli_list_old_recv(req, frame, &finfo);
|
|---|
| 512 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 513 | goto fail;
|
|---|
| 514 | }
|
|---|
| 515 | num_finfo = talloc_array_length(finfo);
|
|---|
| 516 | for (i=0; i<num_finfo; i++) {
|
|---|
| 517 | status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
|
|---|
| 518 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 519 | goto fail;
|
|---|
| 520 | }
|
|---|
| 521 | }
|
|---|
| 522 | fail:
|
|---|
| 523 | TALLOC_FREE(frame);
|
|---|
| 524 | return status;
|
|---|
| 525 | }
|
|---|
| 526 |
|
|---|
| 527 | struct cli_list_trans_state {
|
|---|
| 528 | struct tevent_context *ev;
|
|---|
| 529 | struct cli_state *cli;
|
|---|
| 530 | char *mask;
|
|---|
| 531 | uint16_t attribute;
|
|---|
| 532 | uint16_t info_level;
|
|---|
| 533 |
|
|---|
| 534 | int loop_count;
|
|---|
| 535 | int total_received;
|
|---|
| 536 | uint16_t max_matches;
|
|---|
| 537 | bool first;
|
|---|
| 538 |
|
|---|
| 539 | int ff_eos;
|
|---|
| 540 | int ff_dir_handle;
|
|---|
| 541 |
|
|---|
| 542 | uint16_t setup[1];
|
|---|
| 543 | uint8_t *param;
|
|---|
| 544 |
|
|---|
| 545 | struct file_info *finfo;
|
|---|
| 546 | };
|
|---|
| 547 |
|
|---|
| 548 | static void cli_list_trans_done(struct tevent_req *subreq);
|
|---|
| 549 |
|
|---|
| 550 | static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
|
|---|
| 551 | struct tevent_context *ev,
|
|---|
| 552 | struct cli_state *cli,
|
|---|
| 553 | const char *mask,
|
|---|
| 554 | uint16_t attribute,
|
|---|
| 555 | uint16_t info_level)
|
|---|
| 556 | {
|
|---|
| 557 | struct tevent_req *req, *subreq;
|
|---|
| 558 | struct cli_list_trans_state *state;
|
|---|
| 559 | size_t param_len;
|
|---|
| 560 |
|
|---|
| 561 | req = tevent_req_create(mem_ctx, &state,
|
|---|
| 562 | struct cli_list_trans_state);
|
|---|
| 563 | if (req == NULL) {
|
|---|
| 564 | return NULL;
|
|---|
| 565 | }
|
|---|
| 566 | state->ev = ev;
|
|---|
| 567 | state->cli = cli;
|
|---|
| 568 | state->mask = talloc_strdup(state, mask);
|
|---|
| 569 | if (tevent_req_nomem(state->mask, req)) {
|
|---|
| 570 | return tevent_req_post(req, ev);
|
|---|
| 571 | }
|
|---|
| 572 | state->attribute = attribute;
|
|---|
| 573 | state->info_level = info_level;
|
|---|
| 574 | state->loop_count = 0;
|
|---|
| 575 | state->first = true;
|
|---|
| 576 |
|
|---|
| 577 | state->max_matches = 1366; /* Match W2k */
|
|---|
| 578 |
|
|---|
| 579 | SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
|
|---|
| 580 |
|
|---|
| 581 | state->param = talloc_array(state, uint8_t, 12);
|
|---|
| 582 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 583 | return tevent_req_post(req, ev);
|
|---|
| 584 | }
|
|---|
| 585 |
|
|---|
| 586 | SSVAL(state->param, 0, state->attribute);
|
|---|
| 587 | SSVAL(state->param, 2, state->max_matches);
|
|---|
| 588 | SSVAL(state->param, 4,
|
|---|
| 589 | FLAG_TRANS2_FIND_REQUIRE_RESUME
|
|---|
| 590 | |FLAG_TRANS2_FIND_CLOSE_IF_END
|
|---|
| 591 | |(cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0));
|
|---|
| 592 | SSVAL(state->param, 6, state->info_level);
|
|---|
| 593 | SIVAL(state->param, 8, 0);
|
|---|
| 594 |
|
|---|
| 595 | state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
|
|---|
| 596 | state->mask, strlen(state->mask)+1,
|
|---|
| 597 | NULL);
|
|---|
| 598 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 599 | return tevent_req_post(req, ev);
|
|---|
| 600 | }
|
|---|
| 601 | param_len = talloc_get_size(state->param);
|
|---|
| 602 |
|
|---|
| 603 | subreq = cli_trans_send(state, state->ev, state->cli,
|
|---|
| 604 | SMBtrans2, NULL, -1, 0, 0,
|
|---|
| 605 | state->setup, 1, 0,
|
|---|
| 606 | state->param, param_len, 10,
|
|---|
| 607 | NULL, 0, CLI_BUFFER_SIZE);
|
|---|
| 608 | if (tevent_req_nomem(subreq, req)) {
|
|---|
| 609 | return tevent_req_post(req, ev);
|
|---|
| 610 | }
|
|---|
| 611 | tevent_req_set_callback(subreq, cli_list_trans_done, req);
|
|---|
| 612 | return req;
|
|---|
| 613 | }
|
|---|
| 614 |
|
|---|
| 615 | static void cli_list_trans_done(struct tevent_req *subreq)
|
|---|
| 616 | {
|
|---|
| 617 | struct tevent_req *req = tevent_req_callback_data(
|
|---|
| 618 | subreq, struct tevent_req);
|
|---|
| 619 | struct cli_list_trans_state *state = tevent_req_data(
|
|---|
| 620 | req, struct cli_list_trans_state);
|
|---|
| 621 | NTSTATUS status;
|
|---|
| 622 | uint8_t *param;
|
|---|
| 623 | uint32_t num_param;
|
|---|
| 624 | uint8_t *data;
|
|---|
| 625 | char *data_end;
|
|---|
| 626 | uint32_t num_data;
|
|---|
| 627 | uint32_t min_param;
|
|---|
| 628 | struct file_info *tmp;
|
|---|
| 629 | size_t old_num_finfo;
|
|---|
| 630 | uint16_t recv_flags2;
|
|---|
| 631 | int ff_searchcount;
|
|---|
| 632 | bool ff_eos;
|
|---|
| 633 | char *p, *p2;
|
|---|
| 634 | uint32_t resume_key = 0;
|
|---|
| 635 | int i;
|
|---|
| 636 | DATA_BLOB last_name_raw;
|
|---|
| 637 | struct file_info *finfo = NULL;
|
|---|
| 638 | size_t param_len;
|
|---|
| 639 |
|
|---|
| 640 | min_param = (state->first ? 6 : 4);
|
|---|
| 641 |
|
|---|
| 642 | status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
|
|---|
| 643 | NULL, 0, NULL,
|
|---|
| 644 | ¶m, min_param, &num_param,
|
|---|
| 645 | &data, 0, &num_data);
|
|---|
| 646 | TALLOC_FREE(subreq);
|
|---|
| 647 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 648 | /*
|
|---|
| 649 | * TODO: retry, OS/2 nofiles
|
|---|
| 650 | */
|
|---|
| 651 | tevent_req_nterror(req, status);
|
|---|
| 652 | return;
|
|---|
| 653 | }
|
|---|
| 654 |
|
|---|
| 655 | if (state->first) {
|
|---|
| 656 | state->ff_dir_handle = SVAL(param, 0);
|
|---|
| 657 | ff_searchcount = SVAL(param, 2);
|
|---|
| 658 | ff_eos = SVAL(param, 4) != 0;
|
|---|
| 659 | } else {
|
|---|
| 660 | ff_searchcount = SVAL(param, 0);
|
|---|
| 661 | ff_eos = SVAL(param, 2) != 0;
|
|---|
| 662 | }
|
|---|
| 663 |
|
|---|
| 664 | old_num_finfo = talloc_array_length(state->finfo);
|
|---|
| 665 |
|
|---|
| 666 | tmp = talloc_realloc(state, state->finfo, struct file_info,
|
|---|
| 667 | old_num_finfo + ff_searchcount);
|
|---|
| 668 | if (tevent_req_nomem(tmp, req)) {
|
|---|
| 669 | return;
|
|---|
| 670 | }
|
|---|
| 671 | state->finfo = tmp;
|
|---|
| 672 |
|
|---|
| 673 | p2 = p = (char *)data;
|
|---|
| 674 | data_end = (char *)data + num_data;
|
|---|
| 675 | last_name_raw = data_blob_null;
|
|---|
| 676 |
|
|---|
| 677 | for (i=0; i<ff_searchcount; i++) {
|
|---|
| 678 | if (p2 >= data_end) {
|
|---|
| 679 | ff_eos = true;
|
|---|
| 680 | break;
|
|---|
| 681 | }
|
|---|
| 682 | if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
|
|---|
| 683 | && (i == ff_searchcount-1)) {
|
|---|
| 684 | /* Last entry - fixup the last offset length. */
|
|---|
| 685 | SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
|
|---|
| 686 | }
|
|---|
| 687 |
|
|---|
| 688 | data_blob_free(&last_name_raw);
|
|---|
| 689 |
|
|---|
| 690 | finfo = &state->finfo[old_num_finfo + i];
|
|---|
| 691 |
|
|---|
| 692 | p2 += interpret_long_filename(
|
|---|
| 693 | state->finfo, /* Stick fname to the array as such */
|
|---|
| 694 | state->cli, state->info_level,
|
|---|
| 695 | (char *)data, recv_flags2, p2,
|
|---|
| 696 | data_end, finfo, &resume_key, &last_name_raw);
|
|---|
| 697 |
|
|---|
| 698 | if (finfo->name == NULL) {
|
|---|
| 699 | DEBUG(1, ("cli_list: Error: unable to parse name from "
|
|---|
| 700 | "info level %d\n", state->info_level));
|
|---|
| 701 | ff_eos = true;
|
|---|
| 702 | break;
|
|---|
| 703 | }
|
|---|
| 704 | if (!state->first && (state->mask[0] != '\0') &&
|
|---|
| 705 | strcsequal(finfo->name, state->mask)) {
|
|---|
| 706 | DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
|
|---|
| 707 | "already been seen?\n", finfo->name));
|
|---|
| 708 | ff_eos = true;
|
|---|
| 709 | break;
|
|---|
| 710 | }
|
|---|
| 711 | }
|
|---|
| 712 |
|
|---|
| 713 | if (ff_searchcount == 0) {
|
|---|
| 714 | ff_eos = true;
|
|---|
| 715 | }
|
|---|
| 716 |
|
|---|
| 717 | TALLOC_FREE(param);
|
|---|
| 718 | TALLOC_FREE(data);
|
|---|
| 719 |
|
|---|
| 720 | /*
|
|---|
| 721 | * Shrink state->finfo to the real length we received
|
|---|
| 722 | */
|
|---|
| 723 | tmp = talloc_realloc(state, state->finfo, struct file_info,
|
|---|
| 724 | old_num_finfo + i);
|
|---|
| 725 | if (tevent_req_nomem(tmp, req)) {
|
|---|
| 726 | return;
|
|---|
| 727 | }
|
|---|
| 728 | state->finfo = tmp;
|
|---|
| 729 |
|
|---|
| 730 | state->first = false;
|
|---|
| 731 |
|
|---|
| 732 | if (ff_eos) {
|
|---|
| 733 | data_blob_free(&last_name_raw);
|
|---|
| 734 | tevent_req_done(req);
|
|---|
| 735 | return;
|
|---|
| 736 | }
|
|---|
| 737 |
|
|---|
| 738 | TALLOC_FREE(state->mask);
|
|---|
| 739 | state->mask = talloc_strdup(state, finfo->name);
|
|---|
| 740 | if (tevent_req_nomem(state->mask, req)) {
|
|---|
| 741 | return;
|
|---|
| 742 | }
|
|---|
| 743 |
|
|---|
| 744 | SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
|
|---|
| 745 |
|
|---|
| 746 | param = talloc_realloc(state, state->param, uint8_t, 12);
|
|---|
| 747 | if (tevent_req_nomem(param, req)) {
|
|---|
| 748 | return;
|
|---|
| 749 | }
|
|---|
| 750 | state->param = param;
|
|---|
| 751 |
|
|---|
| 752 | SSVAL(param, 0, state->ff_dir_handle);
|
|---|
| 753 | SSVAL(param, 2, state->max_matches); /* max count */
|
|---|
| 754 | SSVAL(param, 4, state->info_level);
|
|---|
| 755 | /*
|
|---|
| 756 | * For W2K servers serving out FAT filesystems we *must* set
|
|---|
| 757 | * the resume key. If it's not FAT then it's returned as zero.
|
|---|
| 758 | */
|
|---|
| 759 | SIVAL(param, 6, resume_key); /* ff_resume_key */
|
|---|
| 760 | /*
|
|---|
| 761 | * NB. *DON'T* use continue here. If you do it seems that W2K
|
|---|
| 762 | * and bretheren can miss filenames. Use last filename
|
|---|
| 763 | * continue instead. JRA
|
|---|
| 764 | */
|
|---|
| 765 | SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
|
|---|
| 766 | |FLAG_TRANS2_FIND_CLOSE_IF_END
|
|---|
| 767 | |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
|
|---|
| 768 | if (last_name_raw.length) {
|
|---|
| 769 | state->param = trans2_bytes_push_bytes(state->param,
|
|---|
| 770 | last_name_raw.data,
|
|---|
| 771 | last_name_raw.length);
|
|---|
| 772 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 773 | return;
|
|---|
| 774 | }
|
|---|
| 775 | data_blob_free(&last_name_raw);
|
|---|
| 776 | } else {
|
|---|
| 777 | state->param = trans2_bytes_push_str(state->param,
|
|---|
| 778 | smbXcli_conn_use_unicode(state->cli->conn),
|
|---|
| 779 | state->mask,
|
|---|
| 780 | strlen(state->mask)+1,
|
|---|
| 781 | NULL);
|
|---|
| 782 | if (tevent_req_nomem(state->param, req)) {
|
|---|
| 783 | return;
|
|---|
| 784 | }
|
|---|
| 785 | }
|
|---|
| 786 | param_len = talloc_get_size(state->param);
|
|---|
| 787 |
|
|---|
| 788 | subreq = cli_trans_send(state, state->ev, state->cli,
|
|---|
| 789 | SMBtrans2, NULL, -1, 0, 0,
|
|---|
| 790 | state->setup, 1, 0,
|
|---|
| 791 | state->param, param_len, 10,
|
|---|
| 792 | NULL, 0, CLI_BUFFER_SIZE);
|
|---|
| 793 | if (tevent_req_nomem(subreq, req)) {
|
|---|
| 794 | return;
|
|---|
| 795 | }
|
|---|
| 796 | tevent_req_set_callback(subreq, cli_list_trans_done, req);
|
|---|
| 797 | }
|
|---|
| 798 |
|
|---|
| 799 | static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
|
|---|
| 800 | TALLOC_CTX *mem_ctx,
|
|---|
| 801 | struct file_info **finfo)
|
|---|
| 802 | {
|
|---|
| 803 | struct cli_list_trans_state *state = tevent_req_data(
|
|---|
| 804 | req, struct cli_list_trans_state);
|
|---|
| 805 | NTSTATUS status;
|
|---|
| 806 |
|
|---|
| 807 | if (tevent_req_is_nterror(req, &status)) {
|
|---|
| 808 | return status;
|
|---|
| 809 | }
|
|---|
| 810 | *finfo = talloc_move(mem_ctx, &state->finfo);
|
|---|
| 811 | return NT_STATUS_OK;
|
|---|
| 812 | }
|
|---|
| 813 |
|
|---|
| 814 | NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
|
|---|
| 815 | uint16_t attribute, int info_level,
|
|---|
| 816 | NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
|
|---|
| 817 | const char *mask, void *private_data),
|
|---|
| 818 | void *private_data)
|
|---|
| 819 | {
|
|---|
| 820 | TALLOC_CTX *frame = talloc_stackframe();
|
|---|
| 821 | struct tevent_context *ev;
|
|---|
| 822 | struct tevent_req *req;
|
|---|
| 823 | int i, num_finfo;
|
|---|
| 824 | struct file_info *finfo = NULL;
|
|---|
| 825 | NTSTATUS status = NT_STATUS_NO_MEMORY;
|
|---|
| 826 |
|
|---|
| 827 | if (smbXcli_conn_has_async_calls(cli->conn)) {
|
|---|
| 828 | /*
|
|---|
| 829 | * Can't use sync call while an async call is in flight
|
|---|
| 830 | */
|
|---|
| 831 | status = NT_STATUS_INVALID_PARAMETER;
|
|---|
| 832 | goto fail;
|
|---|
| 833 | }
|
|---|
| 834 | ev = samba_tevent_context_init(frame);
|
|---|
| 835 | if (ev == NULL) {
|
|---|
| 836 | goto fail;
|
|---|
| 837 | }
|
|---|
| 838 | req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
|
|---|
| 839 | if (req == NULL) {
|
|---|
| 840 | goto fail;
|
|---|
| 841 | }
|
|---|
| 842 | if (!tevent_req_poll_ntstatus(req, ev, &status)) {
|
|---|
| 843 | goto fail;
|
|---|
| 844 | }
|
|---|
| 845 | status = cli_list_trans_recv(req, frame, &finfo);
|
|---|
| 846 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 847 | goto fail;
|
|---|
| 848 | }
|
|---|
| 849 | num_finfo = talloc_array_length(finfo);
|
|---|
| 850 | for (i=0; i<num_finfo; i++) {
|
|---|
| 851 | status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
|
|---|
| 852 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 853 | goto fail;
|
|---|
| 854 | }
|
|---|
| 855 | }
|
|---|
| 856 | fail:
|
|---|
| 857 | TALLOC_FREE(frame);
|
|---|
| 858 | return status;
|
|---|
| 859 | }
|
|---|
| 860 |
|
|---|
| 861 | struct cli_list_state {
|
|---|
| 862 | NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
|---|
| 863 | struct file_info **finfo);
|
|---|
| 864 | struct file_info *finfo;
|
|---|
| 865 | };
|
|---|
| 866 |
|
|---|
| 867 | static void cli_list_done(struct tevent_req *subreq);
|
|---|
| 868 |
|
|---|
| 869 | struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
|
|---|
| 870 | struct tevent_context *ev,
|
|---|
| 871 | struct cli_state *cli,
|
|---|
| 872 | const char *mask,
|
|---|
| 873 | uint16_t attribute,
|
|---|
| 874 | uint16_t info_level)
|
|---|
| 875 | {
|
|---|
| 876 | struct tevent_req *req, *subreq;
|
|---|
| 877 | struct cli_list_state *state;
|
|---|
| 878 |
|
|---|
| 879 | req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
|
|---|
| 880 | if (req == NULL) {
|
|---|
| 881 | return NULL;
|
|---|
| 882 | }
|
|---|
| 883 |
|
|---|
| 884 | if (smbXcli_conn_protocol(cli->conn) <= PROTOCOL_LANMAN1) {
|
|---|
| 885 | subreq = cli_list_old_send(state, ev, cli, mask, attribute);
|
|---|
| 886 | state->recv_fn = cli_list_old_recv;
|
|---|
| 887 | } else {
|
|---|
| 888 | subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
|
|---|
| 889 | info_level);
|
|---|
| 890 | state->recv_fn = cli_list_trans_recv;
|
|---|
| 891 | }
|
|---|
| 892 | if (tevent_req_nomem(subreq, req)) {
|
|---|
| 893 | return tevent_req_post(req, ev);
|
|---|
| 894 | }
|
|---|
| 895 | tevent_req_set_callback(subreq, cli_list_done, req);
|
|---|
| 896 | return req;
|
|---|
| 897 | }
|
|---|
| 898 |
|
|---|
| 899 | static void cli_list_done(struct tevent_req *subreq)
|
|---|
| 900 | {
|
|---|
| 901 | struct tevent_req *req = tevent_req_callback_data(
|
|---|
| 902 | subreq, struct tevent_req);
|
|---|
| 903 | struct cli_list_state *state = tevent_req_data(
|
|---|
| 904 | req, struct cli_list_state);
|
|---|
| 905 | NTSTATUS status;
|
|---|
| 906 |
|
|---|
| 907 | status = state->recv_fn(subreq, state, &state->finfo);
|
|---|
| 908 | TALLOC_FREE(subreq);
|
|---|
| 909 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 910 | tevent_req_nterror(req, status);
|
|---|
| 911 | return;
|
|---|
| 912 | }
|
|---|
| 913 | tevent_req_done(req);
|
|---|
| 914 | }
|
|---|
| 915 |
|
|---|
| 916 | NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
|---|
| 917 | struct file_info **finfo, size_t *num_finfo)
|
|---|
| 918 | {
|
|---|
| 919 | struct cli_list_state *state = tevent_req_data(
|
|---|
| 920 | req, struct cli_list_state);
|
|---|
| 921 | NTSTATUS status;
|
|---|
| 922 |
|
|---|
| 923 | if (tevent_req_is_nterror(req, &status)) {
|
|---|
| 924 | return status;
|
|---|
| 925 | }
|
|---|
| 926 | *num_finfo = talloc_array_length(state->finfo);
|
|---|
| 927 | *finfo = talloc_move(mem_ctx, &state->finfo);
|
|---|
| 928 | return NT_STATUS_OK;
|
|---|
| 929 | }
|
|---|
| 930 |
|
|---|
| 931 | NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute,
|
|---|
| 932 | NTSTATUS (*fn)(const char *, struct file_info *, const char *,
|
|---|
| 933 | void *), void *state)
|
|---|
| 934 | {
|
|---|
| 935 | TALLOC_CTX *frame = NULL;
|
|---|
| 936 | struct tevent_context *ev;
|
|---|
| 937 | struct tevent_req *req;
|
|---|
| 938 | NTSTATUS status = NT_STATUS_NO_MEMORY;
|
|---|
| 939 | struct file_info *finfo;
|
|---|
| 940 | size_t i, num_finfo;
|
|---|
| 941 | uint16_t info_level;
|
|---|
| 942 |
|
|---|
| 943 | if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
|
|---|
| 944 | return cli_smb2_list(cli, mask, attribute, fn, state);
|
|---|
| 945 | }
|
|---|
| 946 |
|
|---|
| 947 | frame = talloc_stackframe();
|
|---|
| 948 |
|
|---|
| 949 | if (smbXcli_conn_has_async_calls(cli->conn)) {
|
|---|
| 950 | /*
|
|---|
| 951 | * Can't use sync call while an async call is in flight
|
|---|
| 952 | */
|
|---|
| 953 | status = NT_STATUS_INVALID_PARAMETER;
|
|---|
| 954 | goto fail;
|
|---|
| 955 | }
|
|---|
| 956 | ev = samba_tevent_context_init(frame);
|
|---|
| 957 | if (ev == NULL) {
|
|---|
| 958 | goto fail;
|
|---|
| 959 | }
|
|---|
| 960 |
|
|---|
| 961 | info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
|
|---|
| 962 | ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
|
|---|
| 963 |
|
|---|
| 964 | req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
|
|---|
| 965 | if (req == NULL) {
|
|---|
| 966 | goto fail;
|
|---|
| 967 | }
|
|---|
| 968 | if (!tevent_req_poll_ntstatus(req, ev, &status)) {
|
|---|
| 969 | goto fail;
|
|---|
| 970 | }
|
|---|
| 971 |
|
|---|
| 972 | status = cli_list_recv(req, frame, &finfo, &num_finfo);
|
|---|
| 973 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 974 | goto fail;
|
|---|
| 975 | }
|
|---|
| 976 |
|
|---|
| 977 | for (i=0; i<num_finfo; i++) {
|
|---|
| 978 | status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
|
|---|
| 979 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 980 | goto fail;
|
|---|
| 981 | }
|
|---|
| 982 | }
|
|---|
| 983 | fail:
|
|---|
| 984 | TALLOC_FREE(frame);
|
|---|
| 985 | return status;
|
|---|
| 986 | }
|
|---|