1/* 2 Unix SMB/CIFS implementation. 3 4 SMB2 client find calls 5 6 Copyright (C) Andrew Tridgell 2005 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "libcli/raw/libcliraw.h" 24#include "libcli/raw/raw_proto.h" 25#include "libcli/smb2/smb2.h" 26#include "libcli/smb2/smb2_calls.h" 27 28/* 29 send a find request 30*/ 31struct smb2_request *smb2_find_send(struct smb2_tree *tree, struct smb2_find *io) 32{ 33 struct smb2_request *req; 34 NTSTATUS status; 35 36 req = smb2_request_init_tree(tree, SMB2_OP_FIND, 0x20, true, 0); 37 if (req == NULL) return NULL; 38 39 SCVAL(req->out.body, 0x02, io->in.level); 40 SCVAL(req->out.body, 0x03, io->in.continue_flags); 41 SIVAL(req->out.body, 0x04, io->in.file_index); 42 smb2_push_handle(req->out.body+0x08, &io->in.file.handle); 43 44 status = smb2_push_o16s16_string(&req->out, 0x18, io->in.pattern); 45 if (!NT_STATUS_IS_OK(status)) { 46 talloc_free(req); 47 return NULL; 48 } 49 50 SIVAL(req->out.body, 0x1C, io->in.max_response_size); 51 52 smb2_transport_send(req); 53 54 return req; 55} 56 57 58/* 59 recv a find reply 60*/ 61NTSTATUS smb2_find_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, 62 struct smb2_find *io) 63{ 64 NTSTATUS status; 65 66 if (!smb2_request_receive(req) || 67 smb2_request_is_error(req)) { 68 return smb2_request_destroy(req); 69 } 70 71 SMB2_CHECK_PACKET_RECV(req, 0x08, true); 72 73 status = smb2_pull_o16s32_blob(&req->in, mem_ctx, 74 req->in.body+0x02, &io->out.blob); 75 if (!NT_STATUS_IS_OK(status)) { 76 return status; 77 } 78 79 return smb2_request_destroy(req); 80} 81 82/* 83 sync find request 84*/ 85NTSTATUS smb2_find(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, 86 struct smb2_find *io) 87{ 88 struct smb2_request *req = smb2_find_send(tree, io); 89 return smb2_find_recv(req, mem_ctx, io); 90} 91 92 93/* 94 a varient of smb2_find_recv that parses the resulting blob into 95 smb_search_data structures 96*/ 97NTSTATUS smb2_find_level_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, 98 uint8_t level, uint_t *count, 99 union smb_search_data **io) 100{ 101 struct smb2_find f; 102 NTSTATUS status; 103 DATA_BLOB b; 104 enum smb_search_data_level smb_level; 105 uint_t next_ofs=0; 106 107 switch (level) { 108 case SMB2_FIND_DIRECTORY_INFO: 109 smb_level = RAW_SEARCH_DATA_DIRECTORY_INFO; 110 break; 111 case SMB2_FIND_FULL_DIRECTORY_INFO: 112 smb_level = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO; 113 break; 114 case SMB2_FIND_BOTH_DIRECTORY_INFO: 115 smb_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO; 116 break; 117 case SMB2_FIND_NAME_INFO: 118 smb_level = RAW_SEARCH_DATA_NAME_INFO; 119 break; 120 case SMB2_FIND_ID_FULL_DIRECTORY_INFO: 121 smb_level = RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO; 122 break; 123 case SMB2_FIND_ID_BOTH_DIRECTORY_INFO: 124 smb_level = RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO; 125 break; 126 default: 127 return NT_STATUS_INVALID_INFO_CLASS; 128 } 129 130 status = smb2_find_recv(req, mem_ctx, &f); 131 NT_STATUS_NOT_OK_RETURN(status); 132 133 b = f.out.blob; 134 *io = NULL; 135 *count = 0; 136 137 do { 138 union smb_search_data *io2; 139 140 io2 = talloc_realloc(mem_ctx, *io, union smb_search_data, (*count)+1); 141 if (io2 == NULL) { 142 data_blob_free(&f.out.blob); 143 talloc_free(*io); 144 return NT_STATUS_NO_MEMORY; 145 } 146 *io = io2; 147 148 status = smb_raw_search_common(*io, smb_level, &b, (*io) + (*count), 149 &next_ofs, STR_UNICODE); 150 151 if (NT_STATUS_IS_OK(status) && 152 next_ofs >= b.length) { 153 data_blob_free(&f.out.blob); 154 talloc_free(*io); 155 return NT_STATUS_INFO_LENGTH_MISMATCH; 156 } 157 158 (*count)++; 159 160 b = data_blob_const(b.data+next_ofs, b.length - next_ofs); 161 } while (NT_STATUS_IS_OK(status) && next_ofs != 0); 162 163 data_blob_free(&f.out.blob); 164 165 return NT_STATUS_OK; 166} 167 168/* 169 a varient of smb2_find that parses the resulting blob into 170 smb_search_data structures 171*/ 172NTSTATUS smb2_find_level(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, 173 struct smb2_find *f, 174 uint_t *count, union smb_search_data **io) 175{ 176 struct smb2_request *req; 177 178 req = smb2_find_send(tree, f); 179 return smb2_find_level_recv(req, mem_ctx, f->in.level, count, io); 180} 181