root/source4/libcli/raw/rawsearch.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smb_raw_search_backend
  2. smb_raw_search_first_old
  3. smb_raw_search_next_old
  4. smb_raw_search_close_old
  5. smb_raw_search_first_blob
  6. smb_raw_search_next_blob
  7. smb_raw_search_common
  8. parse_trans2_search
  9. smb_raw_t2search_backend
  10. smb_raw_search_first
  11. smb_raw_search_next
  12. smb_raw_search_close

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

/* [<][>][^][v][top][bottom][index][help] */