Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : SMB2 Find 4 : Copyright (C) Andrew Tridgell 2003 5 : Copyright (c) Stefan Metzmacher 2006 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 : This file handles the parsing of transact2 requests 22 : */ 23 : 24 : #include "includes.h" 25 : #include "libcli/smb2/smb2.h" 26 : #include "libcli/smb2/smb2_calls.h" 27 : #include "smb_server/smb_server.h" 28 : #include "smb_server/smb2/smb2_server.h" 29 : #include "ntvfs/ntvfs.h" 30 : 31 : 32 : /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */ 33 : struct smb2srv_find_state { 34 : struct smb2srv_request *req; 35 : struct smb2_find *info; 36 : union smb_search_first *ff; 37 : union smb_search_next *fn; 38 : uint32_t last_entry_offset; 39 : }; 40 : 41 : /* callback function for SMB2 Find */ 42 67046 : static bool smb2srv_find_callback(void *private_data, const union smb_search_data *file) 43 : { 44 67046 : struct smb2srv_find_state *state = talloc_get_type(private_data, struct smb2srv_find_state); 45 67046 : struct smb2_find *info = state->info; 46 0 : uint32_t old_length; 47 0 : NTSTATUS status; 48 : 49 67046 : old_length = info->out.blob.length; 50 : 51 67046 : status = smbsrv_push_passthru_search(state, &info->out.blob, info->data_level, file, STR_UNICODE); 52 67046 : if (!NT_STATUS_IS_OK(status) || 53 67046 : info->out.blob.length > info->in.max_response_size) { 54 : /* restore the old length and tell the backend to stop */ 55 0 : smbsrv_blob_grow_data(state, &info->out.blob, old_length); 56 0 : return false; 57 : } 58 : 59 67046 : state->last_entry_offset = old_length; 60 : 61 67046 : return true; 62 : } 63 : 64 906 : static void smb2srv_find_send(struct ntvfs_request *ntvfs) 65 : { 66 0 : struct smb2srv_request *req; 67 0 : struct smb2srv_find_state *state; 68 : 69 906 : SMB2SRV_CHECK_ASYNC_STATUS(state, struct smb2srv_find_state); 70 467 : SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, true, state->info->out.blob.length)); 71 : 72 467 : if (state->info->out.blob.length > 0) { 73 467 : SIVAL(state->info->out.blob.data + state->last_entry_offset, 0, 0); 74 : } 75 : 76 467 : SMB2SRV_CHECK(smb2_push_o16s32_blob(&req->out, 0x02, state->info->out.blob)); 77 : 78 467 : smb2srv_send_reply(req); 79 : } 80 : 81 906 : static NTSTATUS smb2srv_find_backend(struct smb2srv_find_state *state) 82 : { 83 906 : struct smb2_find *info = state->info; 84 : 85 906 : switch (info->in.level) { 86 2 : case SMB2_FIND_DIRECTORY_INFO: 87 2 : info->data_level = RAW_SEARCH_DATA_DIRECTORY_INFO; 88 2 : break; 89 : 90 0 : case SMB2_FIND_FULL_DIRECTORY_INFO: 91 0 : info->data_level = RAW_SEARCH_DATA_FULL_DIRECTORY_INFO; 92 0 : break; 93 : 94 3 : case SMB2_FIND_BOTH_DIRECTORY_INFO: 95 3 : info->data_level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO; 96 3 : break; 97 : 98 271 : case SMB2_FIND_NAME_INFO: 99 271 : info->data_level = RAW_SEARCH_DATA_NAME_INFO; 100 271 : break; 101 : 102 630 : case SMB2_FIND_ID_BOTH_DIRECTORY_INFO: 103 630 : info->data_level = RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO; 104 630 : break; 105 : 106 0 : case SMB2_FIND_ID_FULL_DIRECTORY_INFO: 107 0 : info->data_level = RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO; 108 0 : break; 109 : 110 0 : default: 111 0 : return NT_STATUS_FOOBAR; 112 : } 113 : 114 906 : if (info->in.continue_flags & SMB2_CONTINUE_FLAG_REOPEN) { 115 0 : state->ff = talloc(state, union smb_search_first); 116 0 : NT_STATUS_HAVE_NO_MEMORY(state->ff); 117 : 118 0 : state->ff->smb2 = *info; 119 0 : state->info = &state->ff->smb2; 120 0 : ZERO_STRUCT(state->ff->smb2.out); 121 : 122 0 : return ntvfs_search_first(state->req->ntvfs, state->ff, state, smb2srv_find_callback); 123 : } else { 124 906 : state->fn = talloc(state, union smb_search_next); 125 906 : NT_STATUS_HAVE_NO_MEMORY(state->fn); 126 : 127 906 : state->fn->smb2 = *info; 128 906 : state->info = &state->fn->smb2; 129 906 : ZERO_STRUCT(state->fn->smb2.out); 130 : 131 906 : return ntvfs_search_next(state->req->ntvfs, state->fn, state, smb2srv_find_callback); 132 : } 133 : } 134 : 135 906 : void smb2srv_find_recv(struct smb2srv_request *req) 136 : { 137 0 : struct smb2srv_find_state *state; 138 0 : struct smb2_find *info; 139 : 140 906 : SMB2SRV_CHECK_BODY_SIZE(req, 0x20, true); 141 906 : SMB2SRV_TALLOC_IO_PTR(info, struct smb2_find); 142 : /* this overwrites req->io_ptr !*/ 143 906 : SMB2SRV_TALLOC_IO_PTR(state, struct smb2srv_find_state); 144 906 : state->req = req; 145 906 : state->info = info; 146 906 : state->ff = NULL; 147 906 : state->fn = NULL; 148 906 : state->last_entry_offset= 0; 149 906 : SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_find_send, NTVFS_ASYNC_STATE_MAY_ASYNC); 150 : 151 906 : info->level = RAW_SEARCH_SMB2; 152 906 : info->data_level = RAW_SEARCH_DATA_GENERIC;/* will be overwritten later */ 153 906 : info->in.level = CVAL(req->in.body, 0x02); 154 906 : info->in.continue_flags = CVAL(req->in.body, 0x03); 155 906 : info->in.file_index = IVAL(req->in.body, 0x04); 156 906 : info->in.file.ntvfs = smb2srv_pull_handle(req, req->in.body, 0x08); 157 906 : SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, info, req->in.body+0x18, &info->in.pattern)); 158 906 : info->in.max_response_size = IVAL(req->in.body, 0x1C); 159 : 160 : /* the VFS backend does not yet handle NULL patterns */ 161 906 : if (info->in.pattern == NULL) { 162 0 : info->in.pattern = ""; 163 : } 164 : 165 906 : SMB2SRV_CHECK_FILE_HANDLE(info->in.file.ntvfs); 166 906 : SMB2SRV_CALL_NTVFS_BACKEND(smb2srv_find_backend(state)); 167 : }