Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/libcli/raw/rawsearch.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   client directory search routines
4
   Copyright (C) James Myers 2003 <myersjj@samba.org>
5
   Copyright (C) James Peach 2007
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
*/
20
21
#include "includes.h"
22
#include "libcli/raw/libcliraw.h"
23
#include "libcli/raw/raw_proto.h"
24
25
/****************************************************************************
26
 Old style search backend - process output.
27
****************************************************************************/
28
static void smb_raw_search_backend(struct smbcli_request *req,
29
           TALLOC_CTX *mem_ctx,
30
           uint16_t count,
31
           void *private_data,
32
           smbcli_search_callback callback)
33
34
0
{
35
0
  union smb_search_data search_data;
36
0
  int i;
37
0
  uint8_t *p;
38
39
0
  if (req->in.data_size < 3 + count*43) {
40
0
    req->status = NT_STATUS_INVALID_PARAMETER;
41
0
    return;
42
0
  }
43
44
0
  p = req->in.data + 3;
45
46
0
  for (i=0; i < count; i++) {
47
0
    char *name;
48
49
0
    search_data.search.id.reserved      = CVAL(p, 0);
50
0
    memcpy(search_data.search.id.name,    p+1, 11);
51
0
    search_data.search.id.handle        = CVAL(p, 12);
52
0
    search_data.search.id.server_cookie = IVAL(p, 13);
53
0
    search_data.search.id.client_cookie = IVAL(p, 17);
54
0
    search_data.search.attrib           = CVAL(p, 21);
55
0
    search_data.search.write_time       = raw_pull_dos_date(req->transport,
56
0
                  p + 22);
57
0
    search_data.search.size             = IVAL(p, 26);
58
0
    smbcli_req_pull_ascii(&req->in.bufinfo, mem_ctx, &name, p+30, 13, STR_ASCII);
59
0
    search_data.search.name = name;
60
0
    if (!callback(private_data, &search_data)) {
61
0
      break;
62
0
    }
63
0
    p += 43;
64
0
  }
65
0
}
66
67
/****************************************************************************
68
 Old style search first.
69
****************************************************************************/
70
static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
71
           TALLOC_CTX *mem_ctx,
72
           union smb_search_first *io, void *private_data,
73
           smbcli_search_callback callback)
74
75
0
{
76
0
  struct smbcli_request *req;
77
0
  uint8_t op = SMBsearch;
78
79
0
  if (io->generic.level == RAW_SEARCH_FFIRST) {
80
0
    op = SMBffirst;
81
0
  } else if (io->generic.level == RAW_SEARCH_FUNIQUE) {
82
0
    op = SMBfunique;
83
0
  }
84
85
0
  req = smbcli_request_setup(tree, op, 2, 0);
86
0
  if (!req) {
87
0
    return NT_STATUS_NO_MEMORY;
88
0
  }
89
90
0
  SSVAL(req->out.vwv, VWV(0), io->search_first.in.max_count);
91
0
  SSVAL(req->out.vwv, VWV(1), io->search_first.in.search_attrib);
92
0
  smbcli_req_append_ascii4(req, io->search_first.in.pattern, STR_TERMINATE);
93
0
  smbcli_req_append_var_block(req, NULL, 0);
94
95
0
  if (!smbcli_request_send(req) ||
96
0
      !smbcli_request_receive(req)) {
97
0
    return smbcli_request_destroy(req);
98
0
  }
99
100
0
  if (NT_STATUS_IS_OK(req->status)) {
101
0
    io->search_first.out.count = SVAL(req->in.vwv, VWV(0));
102
0
    smb_raw_search_backend(req, mem_ctx, io->search_first.out.count, private_data, callback);
103
0
  }
104
105
0
  return smbcli_request_destroy(req);
106
0
}
107
108
/****************************************************************************
109
 Old style search next.
110
****************************************************************************/
111
static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
112
          TALLOC_CTX *mem_ctx,
113
          union smb_search_next *io, void *private_data,
114
          smbcli_search_callback callback)
115
116
0
{
117
0
  struct smbcli_request *req;
118
0
  uint8_t var_block[21];
119
0
  uint8_t op = SMBsearch;
120
121
0
  if (io->generic.level == RAW_SEARCH_FFIRST) {
122
0
    op = SMBffirst;
123
0
  }
124
125
0
  req = smbcli_request_setup(tree, op, 2, 0);
126
0
  if (!req) {
127
0
    return NT_STATUS_NO_MEMORY;
128
0
  }
129
130
0
  SSVAL(req->out.vwv, VWV(0), io->search_next.in.max_count);
131
0
  SSVAL(req->out.vwv, VWV(1), io->search_next.in.search_attrib);
132
0
  smbcli_req_append_ascii4(req, "", STR_TERMINATE);
133
134
0
  SCVAL(var_block,  0, io->search_next.in.id.reserved);
135
0
  memcpy(&var_block[1], io->search_next.in.id.name, 11);
136
0
  SCVAL(var_block, 12, io->search_next.in.id.handle);
137
0
  SIVAL(var_block, 13, io->search_next.in.id.server_cookie);
138
0
  SIVAL(var_block, 17, io->search_next.in.id.client_cookie);
139
140
0
  smbcli_req_append_var_block(req, var_block, 21);
141
142
0
  if (!smbcli_request_send(req) ||
143
0
      !smbcli_request_receive(req)) {
144
0
    return smbcli_request_destroy(req);
145
0
  }
146
147
0
  if (NT_STATUS_IS_OK(req->status)) {
148
0
    io->search_next.out.count = SVAL(req->in.vwv, VWV(0));
149
0
    smb_raw_search_backend(req, mem_ctx, io->search_next.out.count, private_data, callback);
150
0
  }
151
152
0
  return smbcli_request_destroy(req);
153
0
}
154
155
156
/****************************************************************************
157
 Old style search next.
158
****************************************************************************/
159
static NTSTATUS smb_raw_search_close_old(struct smbcli_tree *tree,
160
           union smb_search_close *io)
161
0
{
162
0
  struct smbcli_request *req;
163
0
  uint8_t var_block[21];
164
165
0
  req = smbcli_request_setup(tree, SMBfclose, 2, 0);
166
0
  if (!req) {
167
0
    return NT_STATUS_NO_MEMORY;
168
0
  }
169
170
0
  SSVAL(req->out.vwv, VWV(0), io->fclose.in.max_count);
171
0
  SSVAL(req->out.vwv, VWV(1), io->fclose.in.search_attrib);
172
0
  smbcli_req_append_ascii4(req, "", STR_TERMINATE);
173
174
0
  SCVAL(var_block,  0, io->fclose.in.id.reserved);
175
0
  memcpy(&var_block[1], io->fclose.in.id.name, 11);
176
0
  SCVAL(var_block, 12, io->fclose.in.id.handle);
177
0
  SIVAL(var_block, 13, io->fclose.in.id.server_cookie);
178
0
  SIVAL(var_block, 17, io->fclose.in.id.client_cookie);
179
180
0
  smbcli_req_append_var_block(req, var_block, 21);
181
182
0
  if (!smbcli_request_send(req) ||
183
0
      !smbcli_request_receive(req)) {
184
0
    return smbcli_request_destroy(req);
185
0
  }
186
187
0
  return smbcli_request_destroy(req);
188
0
}
189
190
191
192
/****************************************************************************
193
 Very raw search first - returns param/data blobs.
194
****************************************************************************/
195
static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree,
196
            TALLOC_CTX *mem_ctx,  /* used to allocate output blobs */
197
            union smb_search_first *io,
198
            DATA_BLOB *out_param_blob,
199
            DATA_BLOB *out_data_blob)
200
0
{
201
0
  struct smb_trans2 tp;
202
0
  uint16_t setup = TRANSACT2_FINDFIRST;
203
0
  NTSTATUS status;
204
205
0
  tp.in.max_setup = 0;
206
0
  tp.in.flags = 0;
207
0
  tp.in.timeout = 0;
208
0
  tp.in.setup_count = 1;
209
0
  tp.in.data = data_blob(NULL, 0);
210
0
  tp.in.max_param = 10;
211
0
  tp.in.max_data = 0xFFFF;
212
0
  tp.in.setup = &setup;
213
214
0
  if (io->t2ffirst.level != RAW_SEARCH_TRANS2) {
215
0
    return NT_STATUS_INVALID_LEVEL;
216
0
  }
217
218
0
  if (io->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
219
0
    return NT_STATUS_INVALID_LEVEL;
220
0
  }
221
222
0
  if (io->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
223
0
    if (!ea_push_name_list(mem_ctx,
224
0
               &tp.in.data,
225
0
               io->t2ffirst.in.num_names,
226
0
               io->t2ffirst.in.ea_names)) {
227
0
      return NT_STATUS_NO_MEMORY;
228
0
    }
229
0
  }
230
231
0
  tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
232
0
  if (!tp.in.params.data) {
233
0
    return NT_STATUS_NO_MEMORY;
234
0
  }
235
236
0
  SSVAL(tp.in.params.data, 0, io->t2ffirst.in.search_attrib);
237
0
  SSVAL(tp.in.params.data, 2, io->t2ffirst.in.max_count);
238
0
  SSVAL(tp.in.params.data, 4, io->t2ffirst.in.flags);
239
0
  SSVAL(tp.in.params.data, 6, io->t2ffirst.data_level);
240
0
  SIVAL(tp.in.params.data, 8, io->t2ffirst.in.storage_type);
241
242
0
  smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
243
0
          io->t2ffirst.in.pattern, STR_TERMINATE);
244
245
0
  status = smb_raw_trans2(tree, mem_ctx, &tp);
246
0
  if (!NT_STATUS_IS_OK(status)) {
247
0
    return status;
248
0
  }
249
250
0
  out_param_blob->length = tp.out.params.length;
251
0
  out_param_blob->data = tp.out.params.data;
252
0
  out_data_blob->length = tp.out.data.length;
253
0
  out_data_blob->data = tp.out.data.data;
254
255
0
  return NT_STATUS_OK;
256
0
}
257
258
259
/****************************************************************************
260
 Very raw search first - returns param/data blobs.
261
 Used in CIFS-on-CIFS NTVFS.
262
****************************************************************************/
263
static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree,
264
           TALLOC_CTX *mem_ctx,
265
           union smb_search_next *io,
266
           DATA_BLOB *out_param_blob,
267
           DATA_BLOB *out_data_blob)
268
0
{
269
0
  struct smb_trans2 tp;
270
0
  uint16_t setup = TRANSACT2_FINDNEXT;
271
0
  NTSTATUS status;
272
273
0
  tp.in.max_setup = 0;
274
0
  tp.in.flags = 0;
275
0
  tp.in.timeout = 0;
276
0
  tp.in.setup_count = 1;
277
0
  tp.in.data = data_blob(NULL, 0);
278
0
  tp.in.max_param = 10;
279
0
  tp.in.max_data = 0xFFFF;
280
0
  tp.in.setup = &setup;
281
282
0
  if (io->t2fnext.level != RAW_SEARCH_TRANS2) {
283
0
    return NT_STATUS_INVALID_LEVEL;
284
0
  }
285
286
0
  if (io->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
287
0
    return NT_STATUS_INVALID_LEVEL;
288
0
  }
289
290
0
  if (io->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
291
0
    if (!ea_push_name_list(mem_ctx,
292
0
               &tp.in.data,
293
0
               io->t2fnext.in.num_names,
294
0
               io->t2fnext.in.ea_names)) {
295
0
      return NT_STATUS_NO_MEMORY;
296
0
    }
297
0
  }
298
299
0
  tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
300
0
  if (!tp.in.params.data) {
301
0
    return NT_STATUS_NO_MEMORY;
302
0
  }
303
304
0
  SSVAL(tp.in.params.data, 0, io->t2fnext.in.handle);
305
0
  SSVAL(tp.in.params.data, 2, io->t2fnext.in.max_count);
306
0
  SSVAL(tp.in.params.data, 4, io->t2fnext.data_level);
307
0
  SIVAL(tp.in.params.data, 6, io->t2fnext.in.resume_key);
308
0
  SSVAL(tp.in.params.data, 10, io->t2fnext.in.flags);
309
310
0
  smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
311
0
             io->t2fnext.in.last_name,
312
0
             STR_TERMINATE);
313
314
0
  status = smb_raw_trans2(tree, mem_ctx, &tp);
315
0
  if (!NT_STATUS_IS_OK(status)) {
316
0
    return status;
317
0
  }
318
319
0
  out_param_blob->length = tp.out.params.length;
320
0
  out_param_blob->data = tp.out.params.data;
321
0
  out_data_blob->length = tp.out.data.length;
322
0
  out_data_blob->data = tp.out.data.data;
323
324
0
  return NT_STATUS_OK;
325
0
}
326
327
328
/*
329
  parse the wire search formats that are in common between SMB and
330
  SMB2
331
*/
332
NTSTATUS smb_raw_search_common(TALLOC_CTX *mem_ctx,
333
             enum smb_search_data_level level,
334
             const DATA_BLOB *blob,
335
             union smb_search_data *data,
336
             unsigned int *next_ofs,
337
             unsigned int str_flags)
338
0
{
339
0
  unsigned int len, blen;
340
341
0
  if (blob->length < 4) {
342
0
    return NT_STATUS_INFO_LENGTH_MISMATCH;
343
0
  }
344
345
0
  *next_ofs = IVAL(blob->data, 0);
346
0
  if (*next_ofs != 0) {
347
0
    blen = *next_ofs;
348
0
  } else {
349
0
    blen = blob->length;
350
0
  }
351
352
0
  switch (level) {
353
0
  case RAW_SEARCH_DATA_DIRECTORY_INFO:
354
0
    if (blen < 65) return NT_STATUS_INFO_LENGTH_MISMATCH;
355
0
    data->directory_info.file_index  = IVAL(blob->data,             4);
356
0
    data->directory_info.create_time = smbcli_pull_nttime(blob->data,  8);
357
0
    data->directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
358
0
    data->directory_info.write_time  = smbcli_pull_nttime(blob->data, 24);
359
0
    data->directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
360
0
    data->directory_info.size        = BVAL(blob->data,            40);
361
0
    data->directory_info.alloc_size  = BVAL(blob->data,            48);
362
0
    data->directory_info.attrib      = IVAL(blob->data,            56);
363
0
    len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
364
0
                &data->directory_info.name,
365
0
                60, 64, str_flags);
366
0
    if (*next_ofs != 0 && *next_ofs < 64+len) {
367
0
      return NT_STATUS_INFO_LENGTH_MISMATCH;
368
0
    }
369
0
    return NT_STATUS_OK;
370
371
0
  case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
372
0
    if (blen < 69) return NT_STATUS_INFO_LENGTH_MISMATCH;
373
0
    data->full_directory_info.file_index  = IVAL(blob->data,                4);
374
0
    data->full_directory_info.create_time = smbcli_pull_nttime(blob->data,  8);
375
0
    data->full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
376
0
    data->full_directory_info.write_time  = smbcli_pull_nttime(blob->data, 24);
377
0
    data->full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
378
0
    data->full_directory_info.size        = BVAL(blob->data,               40);
379
0
    data->full_directory_info.alloc_size  = BVAL(blob->data,               48);
380
0
    data->full_directory_info.attrib      = IVAL(blob->data,               56);
381
0
    data->full_directory_info.ea_size     = IVAL(blob->data,               64);
382
0
    len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
383
0
                &data->full_directory_info.name,
384
0
                60, 68, str_flags);
385
0
    if (*next_ofs != 0 && *next_ofs < 68+len) {
386
0
      return NT_STATUS_INFO_LENGTH_MISMATCH;
387
0
    }
388
0
    return NT_STATUS_OK;
389
390
0
  case RAW_SEARCH_DATA_NAME_INFO:
391
0
    if (blen < 13) return NT_STATUS_INFO_LENGTH_MISMATCH;
392
0
    data->name_info.file_index  = IVAL(blob->data, 4);
393
0
    len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
394
0
                &data->name_info.name,
395
0
                8, 12, str_flags);
396
0
    if (*next_ofs != 0 && *next_ofs < 12+len) {
397
0
      return NT_STATUS_INFO_LENGTH_MISMATCH;
398
0
    }
399
0
    return NT_STATUS_OK;
400
401
402
0
  case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
403
0
    if (blen < 95) return NT_STATUS_INFO_LENGTH_MISMATCH;
404
0
    data->both_directory_info.file_index  = IVAL(blob->data,                4);
405
0
    data->both_directory_info.create_time = smbcli_pull_nttime(blob->data,  8);
406
0
    data->both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
407
0
    data->both_directory_info.write_time  = smbcli_pull_nttime(blob->data, 24);
408
0
    data->both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
409
0
    data->both_directory_info.size        = BVAL(blob->data,               40);
410
0
    data->both_directory_info.alloc_size  = BVAL(blob->data,               48);
411
0
    data->both_directory_info.attrib      = IVAL(blob->data,               56);
412
0
    data->both_directory_info.ea_size     = IVAL(blob->data,               64);
413
0
    smbcli_blob_pull_string(NULL, mem_ctx, blob,
414
0
          &data->both_directory_info.short_name,
415
0
          68, 70, STR_LEN8BIT | STR_UNICODE);
416
0
    len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
417
0
                &data->both_directory_info.name,
418
0
                60, 94, str_flags);
419
0
    if (*next_ofs != 0 && *next_ofs < 94+len) {
420
0
      return NT_STATUS_INFO_LENGTH_MISMATCH;
421
0
    }
422
0
    return NT_STATUS_OK;
423
424
425
0
  case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
426
0
    if (blen < 81) return NT_STATUS_INFO_LENGTH_MISMATCH;
427
0
    data->id_full_directory_info.file_index  = IVAL(blob->data,             4);
428
0
    data->id_full_directory_info.create_time = smbcli_pull_nttime(blob->data,  8);
429
0
    data->id_full_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
430
0
    data->id_full_directory_info.write_time  = smbcli_pull_nttime(blob->data, 24);
431
0
    data->id_full_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
432
0
    data->id_full_directory_info.size        = BVAL(blob->data,            40);
433
0
    data->id_full_directory_info.alloc_size  = BVAL(blob->data,            48);
434
0
    data->id_full_directory_info.attrib      = IVAL(blob->data,            56);
435
0
    data->id_full_directory_info.ea_size     = IVAL(blob->data,            64);
436
0
    data->id_full_directory_info.file_id     = BVAL(blob->data,            72);
437
0
    len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
438
0
                &data->id_full_directory_info.name,
439
0
                60, 80, str_flags);
440
0
    if (*next_ofs != 0 && *next_ofs < 80+len) {
441
0
      return NT_STATUS_INFO_LENGTH_MISMATCH;
442
0
    }
443
0
    return NT_STATUS_OK;
444
445
0
  case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
446
0
    if (blen < 105) return NT_STATUS_INFO_LENGTH_MISMATCH;
447
0
    data->id_both_directory_info.file_index  = IVAL(blob->data,             4);
448
0
    data->id_both_directory_info.create_time = smbcli_pull_nttime(blob->data,  8);
449
0
    data->id_both_directory_info.access_time = smbcli_pull_nttime(blob->data, 16);
450
0
    data->id_both_directory_info.write_time  = smbcli_pull_nttime(blob->data, 24);
451
0
    data->id_both_directory_info.change_time = smbcli_pull_nttime(blob->data, 32);
452
0
    data->id_both_directory_info.size        = BVAL(blob->data,            40);
453
0
    data->id_both_directory_info.alloc_size  = BVAL(blob->data,            48);
454
0
    data->id_both_directory_info.attrib      = SVAL(blob->data,            56);
455
0
    data->id_both_directory_info.ea_size     = IVAL(blob->data,            64);
456
0
    smbcli_blob_pull_string(NULL, mem_ctx, blob,
457
0
             &data->id_both_directory_info.short_name,
458
0
             68, 70, STR_LEN8BIT | STR_UNICODE);
459
0
    memcpy(data->id_both_directory_info.short_name_buf, blob->data + 70, 24);
460
0
    data->id_both_directory_info.file_id     = BVAL(blob->data,            96);
461
0
    len = smbcli_blob_pull_string(NULL, mem_ctx, blob,
462
0
                &data->id_both_directory_info.name,
463
0
                60, 104, str_flags);
464
0
    if (*next_ofs != 0 && *next_ofs < 104+len) {
465
0
      return NT_STATUS_INFO_LENGTH_MISMATCH;
466
0
    }
467
0
    return NT_STATUS_OK;
468
469
0
  default:
470
0
    break;
471
0
  }
472
473
  /* invalid level */
474
0
  return NT_STATUS_INVALID_INFO_CLASS;
475
0
}
476
477
478
/*
479
  parse a trans2 search response.
480
  Return the number of bytes consumed
481
  return 0 for success with end of list
482
  return -1 for a parse error
483
*/
484
static int parse_trans2_search(struct smbcli_tree *tree,
485
             TALLOC_CTX *mem_ctx,
486
             enum smb_search_data_level level,
487
             uint16_t flags,
488
             DATA_BLOB *blob,
489
             union smb_search_data *data)
490
0
{
491
0
  unsigned int len, ofs;
492
0
  uint32_t ea_size;
493
0
  DATA_BLOB eablob;
494
0
  NTSTATUS status;
495
496
0
  switch (level) {
497
0
  case RAW_SEARCH_DATA_GENERIC:
498
0
  case RAW_SEARCH_DATA_SEARCH:
499
    /* handled elsewhere */
500
0
    return -1;
501
502
0
  case RAW_SEARCH_DATA_STANDARD:
503
0
    if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
504
0
      if (blob->length < 4) return -1;
505
0
      data->standard.resume_key = IVAL(blob->data, 0);
506
0
      blob->data += 4;
507
0
      blob->length -= 4;
508
0
    }
509
0
    if (blob->length < 24) return -1;
510
0
    data->standard.create_time = raw_pull_dos_date2(tree->session->transport,
511
0
                blob->data + 0);
512
0
    data->standard.access_time = raw_pull_dos_date2(tree->session->transport,
513
0
                blob->data + 4);
514
0
    data->standard.write_time  = raw_pull_dos_date2(tree->session->transport,
515
0
                blob->data + 8);
516
0
    data->standard.size        = IVAL(blob->data, 12);
517
0
    data->standard.alloc_size  = IVAL(blob->data, 16);
518
0
    data->standard.attrib      = SVAL(blob->data, 20);
519
0
    len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
520
0
             &data->standard.name,
521
0
             22, 23, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
522
0
    return len + 23;
523
524
0
  case RAW_SEARCH_DATA_EA_SIZE:
525
0
    if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
526
0
      if (blob->length < 4) return -1;
527
0
      data->ea_size.resume_key = IVAL(blob->data, 0);
528
0
      blob->data += 4;
529
0
      blob->length -= 4;
530
0
    }
531
0
    if (blob->length < 28) return -1;
532
0
    data->ea_size.create_time = raw_pull_dos_date2(tree->session->transport,
533
0
                     blob->data + 0);
534
0
    data->ea_size.access_time = raw_pull_dos_date2(tree->session->transport,
535
0
                     blob->data + 4);
536
0
    data->ea_size.write_time  = raw_pull_dos_date2(tree->session->transport,
537
0
                     blob->data + 8);
538
0
    data->ea_size.size        = IVAL(blob->data, 12);
539
0
    data->ea_size.alloc_size  = IVAL(blob->data, 16);
540
0
    data->ea_size.attrib      = SVAL(blob->data, 20);
541
0
    data->ea_size.ea_size     = IVAL(blob->data, 22);
542
0
    len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
543
0
             &data->ea_size.name,
544
0
             26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN);
545
0
    return len + 27 + 1;
546
547
0
  case RAW_SEARCH_DATA_EA_LIST:
548
0
    if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
549
0
      if (blob->length < 4) return -1;
550
0
      data->ea_list.resume_key = IVAL(blob->data, 0);
551
0
      blob->data += 4;
552
0
      blob->length -= 4;
553
0
    }
554
0
    if (blob->length < 28) return -1;
555
0
    data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport,
556
0
                     blob->data + 0);
557
0
    data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport,
558
0
                     blob->data + 4);
559
0
    data->ea_list.write_time  = raw_pull_dos_date2(tree->session->transport,
560
0
                     blob->data + 8);
561
0
    data->ea_list.size        = IVAL(blob->data, 12);
562
0
    data->ea_list.alloc_size  = IVAL(blob->data, 16);
563
0
    data->ea_list.attrib      = SVAL(blob->data, 20);
564
0
    ea_size                   = IVAL(blob->data, 22);
565
0
    if (ea_size > 0xFFFF) {
566
0
      return -1;
567
0
    }
568
0
    eablob.data = blob->data + 22;
569
0
    eablob.length = ea_size;
570
0
    if (eablob.length > blob->length - 24) {
571
0
      return -1;
572
0
    }
573
0
    status = ea_pull_list(&eablob, mem_ctx,
574
0
              &data->ea_list.eas.num_eas,
575
0
              &data->ea_list.eas.eas);
576
0
    if (!NT_STATUS_IS_OK(status)) {
577
0
      return -1;
578
0
    }
579
0
    len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
580
0
                &data->ea_list.name,
581
0
                22+ea_size, 23+ea_size,
582
0
                STR_LEN8BIT | STR_NOALIGN);
583
0
    return len + ea_size + 23 + 1;
584
585
0
  case RAW_SEARCH_DATA_UNIX_INFO:
586
0
    if (blob->length < 109) return -1;
587
0
    ofs                                  = IVAL(blob->data,             0);
588
0
    data->unix_info.file_index           = IVAL(blob->data,             4);
589
0
    data->unix_info.size                 = BVAL(blob->data,             8);
590
0
    data->unix_info.alloc_size           = BVAL(blob->data,            16);
591
0
    data->unix_info.status_change_time   = smbcli_pull_nttime(blob->data, 24);
592
0
    data->unix_info.access_time          = smbcli_pull_nttime(blob->data, 32);
593
0
    data->unix_info.change_time          = smbcli_pull_nttime(blob->data, 40);
594
0
    data->unix_info.uid                  = IVAL(blob->data,            48);
595
0
    data->unix_info.gid                  = IVAL(blob->data,            56);
596
0
    data->unix_info.file_type            = IVAL(blob->data,            64);
597
0
    data->unix_info.dev_major            = BVAL(blob->data,            68);
598
0
    data->unix_info.dev_minor            = BVAL(blob->data,            76);
599
0
    data->unix_info.unique_id            = BVAL(blob->data,            84);
600
0
    data->unix_info.permissions          = IVAL(blob->data,            92);
601
0
    data->unix_info.nlink                = IVAL(blob->data,           100);
602
    /* There is no length field for this name but we know it's null terminated. */
603
0
    len = smbcli_blob_pull_unix_string(tree->session, mem_ctx, blob,
604
0
             &data->unix_info.name, 108, 0);
605
0
    if (ofs != 0 && ofs < 108+len) {
606
0
      return -1;
607
0
    }
608
0
    return ofs;
609
610
0
  case RAW_SEARCH_DATA_UNIX_INFO2:
611
    /*   8 - size of ofs + file_index
612
     * 116 - size of unix_info2
613
     *   4 - size of name length
614
     *   2 - "." is the shortest name
615
     */
616
0
    if (blob->length < (116 + 8 + 4 + 2)) {
617
0
      return -1;
618
0
    }
619
620
0
    ofs                                 = IVAL(blob->data,   0);
621
0
    data->unix_info2.file_index         = IVAL(blob->data,   4);
622
0
    data->unix_info2.end_of_file        = BVAL(blob->data,   8);
623
0
    data->unix_info2.num_bytes          = BVAL(blob->data,  16);
624
0
    data->unix_info2.status_change_time = smbcli_pull_nttime(blob->data, 24);
625
0
    data->unix_info2.access_time        = smbcli_pull_nttime(blob->data, 32);
626
0
    data->unix_info2.change_time        = smbcli_pull_nttime(blob->data, 40);
627
0
    data->unix_info2.uid                = IVAL(blob->data,  48);
628
0
    data->unix_info2.gid                = IVAL(blob->data,  56);
629
0
    data->unix_info2.file_type          = IVAL(blob->data,  64);
630
0
    data->unix_info2.dev_major          = BVAL(blob->data,  68);
631
0
    data->unix_info2.dev_minor          = BVAL(blob->data,  76);
632
0
    data->unix_info2.unique_id          = BVAL(blob->data,  84);
633
0
    data->unix_info2.permissions        = IVAL(blob->data,  92);
634
0
    data->unix_info2.nlink              = IVAL(blob->data, 100);
635
0
    data->unix_info2.create_time      = smbcli_pull_nttime(blob->data, 108);
636
0
    data->unix_info2.file_flags     = IVAL(blob->data, 116);
637
0
    data->unix_info2.flags_mask     = IVAL(blob->data, 120);
638
639
    /* There is a 4 byte length field for this name. The length
640
     * does not include the NULL terminator.
641
     */
642
0
    len = smbcli_blob_pull_string(tree->session, mem_ctx, blob,
643
0
               &data->unix_info2.name,
644
0
               8 + 116, /* offset to length */
645
0
               8 + 116 + 4, /* offset to string */
646
0
               0);
647
648
0
    if (ofs != 0 && ofs < (8 + 116 + 4 + len)) {
649
0
      return -1;
650
0
    }
651
652
0
    return ofs;
653
654
0
    case RAW_SEARCH_DATA_DIRECTORY_INFO:
655
0
    case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
656
0
    case RAW_SEARCH_DATA_NAME_INFO:
657
0
    case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
658
0
    case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
659
0
    case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: {
660
0
      unsigned int str_flags = STR_UNICODE;
661
0
      if (!(tree->session->transport->negotiate.capabilities & CAP_UNICODE)) {
662
0
        str_flags = STR_ASCII;
663
0
      }
664
665
0
    status = smb_raw_search_common(mem_ctx, level, blob, data, &ofs, str_flags);
666
0
    if (!NT_STATUS_IS_OK(status)) {
667
0
      return -1;
668
0
    }
669
0
    return ofs;
670
0
  }
671
0
  }
672
673
  /* invalid level */
674
0
  return -1;
675
0
}
676
677
/****************************************************************************
678
 Trans2 search backend - process output.
679
****************************************************************************/
680
static NTSTATUS smb_raw_t2search_backend(struct smbcli_tree *tree,
681
           TALLOC_CTX *mem_ctx,
682
           enum smb_search_data_level level,
683
           uint16_t flags,
684
           int16_t count,
685
           DATA_BLOB *blob,
686
           void *private_data,
687
           smbcli_search_callback callback)
688
689
0
{
690
0
  int i;
691
0
  DATA_BLOB blob2;
692
693
0
  blob2.data = blob->data;
694
0
  blob2.length = blob->length;
695
696
0
  for (i=0; i < count; i++) {
697
0
    union smb_search_data search_data;
698
0
    unsigned int len;
699
700
0
    len = parse_trans2_search(tree, mem_ctx, level, flags, &blob2, &search_data);
701
0
    if (len == -1) {
702
0
      return NT_STATUS_INVALID_PARAMETER;
703
0
    }
704
705
    /* the callback function can tell us that no more will
706
       fit - in that case we stop, but it isn't an error */
707
0
    if (!callback(private_data, &search_data)) {
708
0
      break;
709
0
    }
710
711
0
    if (len == 0) break;
712
713
0
    blob2.data += len;
714
0
    blob2.length -= len;
715
0
  }
716
717
0
  return NT_STATUS_OK;
718
0
}
719
720
721
/* Implements trans2findfirst2 and old search
722
 */
723
_PUBLIC_ NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
724
            TALLOC_CTX *mem_ctx,
725
            union smb_search_first *io, void *private_data,
726
            smbcli_search_callback callback)
727
0
{
728
0
  DATA_BLOB p_blob = data_blob_null, d_blob = data_blob_null;
729
0
  NTSTATUS status;
730
731
0
  switch (io->generic.level) {
732
0
  case RAW_SEARCH_SEARCH:
733
0
  case RAW_SEARCH_FFIRST:
734
0
  case RAW_SEARCH_FUNIQUE:
735
0
    return smb_raw_search_first_old(tree, mem_ctx, io, private_data, callback);
736
737
0
  case RAW_SEARCH_TRANS2:
738
0
    break;
739
740
0
  case RAW_SEARCH_SMB2:
741
0
    return NT_STATUS_INVALID_LEVEL;
742
0
  }
743
744
0
  status = smb_raw_search_first_blob(tree, mem_ctx,
745
0
             io, &p_blob, &d_blob);
746
0
  if (!NT_STATUS_IS_OK(status)) {
747
0
    return status;
748
0
  }
749
750
0
  if (p_blob.length < 10) {
751
0
    DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n",
752
0
      (int)p_blob.length));
753
0
    return NT_STATUS_INVALID_PARAMETER;
754
0
  }
755
756
  /* process output data */
757
0
  io->t2ffirst.out.handle = SVAL(p_blob.data, 0);
758
0
  io->t2ffirst.out.count = SVAL(p_blob.data, 2);
759
0
  io->t2ffirst.out.end_of_search = SVAL(p_blob.data, 4);
760
761
0
  status = smb_raw_t2search_backend(tree, mem_ctx,
762
0
            io->generic.data_level,
763
0
            io->t2ffirst.in.flags, io->t2ffirst.out.count,
764
0
            &d_blob, private_data, callback);
765
766
0
  return status;
767
0
}
768
769
/* Implements trans2findnext2 and old smbsearch
770
 */
771
NTSTATUS smb_raw_search_next(struct smbcli_tree *tree,
772
           TALLOC_CTX *mem_ctx,
773
           union smb_search_next *io, void *private_data,
774
           smbcli_search_callback callback)
775
0
{
776
0
  DATA_BLOB p_blob = data_blob_null, d_blob = data_blob_null;
777
0
  NTSTATUS status;
778
779
0
  switch (io->generic.level) {
780
0
  case RAW_SEARCH_SEARCH:
781
0
  case RAW_SEARCH_FFIRST:
782
0
    return smb_raw_search_next_old(tree, mem_ctx, io, private_data, callback);
783
784
0
  case RAW_SEARCH_FUNIQUE:
785
0
    return NT_STATUS_INVALID_LEVEL;
786
787
0
  case RAW_SEARCH_TRANS2:
788
0
    break;
789
790
0
  case RAW_SEARCH_SMB2:
791
0
    return NT_STATUS_INVALID_LEVEL;
792
0
  }
793
794
0
  status = smb_raw_search_next_blob(tree, mem_ctx,
795
0
            io, &p_blob, &d_blob);
796
0
  if (!NT_STATUS_IS_OK(status)) {
797
0
    return status;
798
0
  }
799
800
0
  if (p_blob.length != 8) {
801
0
    DEBUG(1,("smb_raw_search_next: parms wrong size %d != expected_param_size\n",
802
0
      (int)p_blob.length));
803
0
    return NT_STATUS_INVALID_PARAMETER;
804
0
  }
805
806
  /* process output data */
807
0
  io->t2fnext.out.count = SVAL(p_blob.data, 0);
808
0
  io->t2fnext.out.end_of_search = SVAL(p_blob.data, 2);
809
810
0
  status = smb_raw_t2search_backend(tree, mem_ctx,
811
0
            io->generic.data_level,
812
0
            io->t2fnext.in.flags, io->t2fnext.out.count,
813
0
            &d_blob, private_data, callback);
814
815
0
  return status;
816
0
}
817
818
/*
819
   Implements trans2findclose2
820
 */
821
NTSTATUS smb_raw_search_close(struct smbcli_tree *tree,
822
            union smb_search_close *io)
823
0
{
824
0
  struct smbcli_request *req;
825
826
0
  if (io->generic.level == RAW_FINDCLOSE_FCLOSE) {
827
0
    return smb_raw_search_close_old(tree, io);
828
0
  }
829
830
0
  req = smbcli_request_setup(tree, SMBfindclose, 1, 0);
831
0
  if (!req) {
832
0
    return NT_STATUS_NO_MEMORY;
833
0
  }
834
835
0
  SSVAL(req->out.vwv, VWV(0), io->findclose.in.handle);
836
837
0
  if (smbcli_request_send(req)) {
838
0
    (void) smbcli_request_receive(req);
839
0
  }
840
841
0
  return smbcli_request_destroy(req);
842
0
}