libcli/smb: move smb2cli_set_info.c from source3 to the toplevel
[Samba/gebeck_regimport.git] / source3 / libsmb / smb2cli_query_info.c
blob366dc4a9604834a0ce9956692fbafb1f488e0571
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Stefan Metzmacher 2012
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.
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.
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/>.
20 #include "includes.h"
21 #include "client.h"
22 #include "async_smb.h"
23 #include "../libcli/smb/smbXcli_base.h"
24 #include "smb2cli.h"
25 #include "libsmb/proto.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "../librpc/ndr/libndr.h"
29 struct smb2cli_query_info_state {
30 uint8_t fixed[0x28];
31 uint8_t dyn_pad[1];
32 uint32_t max_output_length;
33 struct iovec *recv_iov;
34 DATA_BLOB out_output_buffer;
37 static void smb2cli_query_info_done(struct tevent_req *subreq);
39 struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx,
40 struct tevent_context *ev,
41 struct smbXcli_conn *conn,
42 uint32_t timeout_msec,
43 struct smbXcli_session *session,
44 uint32_t tcon_id,
45 uint8_t in_info_type,
46 uint8_t in_file_info_class,
47 uint32_t in_max_output_length,
48 const DATA_BLOB *in_input_buffer,
49 uint32_t in_additional_info,
50 uint32_t in_flags,
51 uint64_t in_fid_persistent,
52 uint64_t in_fid_volatile)
54 struct tevent_req *req, *subreq;
55 struct smb2cli_query_info_state *state;
56 uint8_t *fixed;
57 uint8_t *dyn;
58 size_t dyn_len;
59 uint16_t input_buffer_offset = 0;
60 uint32_t input_buffer_length = 0;
62 req = tevent_req_create(mem_ctx, &state,
63 struct smb2cli_query_info_state);
64 if (req == NULL) {
65 return NULL;
67 state->max_output_length = in_max_output_length;
69 if (in_input_buffer) {
70 input_buffer_offset = SMB2_HDR_BODY+0x28;
71 input_buffer_length = in_input_buffer->length;
74 fixed = state->fixed;
76 SSVAL(fixed, 0x00, 0x29);
77 SCVAL(fixed, 0x02, in_info_type);
78 SCVAL(fixed, 0x03, in_file_info_class); /* reserved */
79 SIVAL(fixed, 0x04, in_max_output_length);
80 SSVAL(fixed, 0x08, input_buffer_offset);
81 SSVAL(fixed, 0x0A, 0); /* reserved */
82 SIVAL(fixed, 0x0C, input_buffer_length);
83 SIVAL(fixed, 0x10, in_additional_info);
84 SIVAL(fixed, 0x14, in_flags);
85 SBVAL(fixed, 0x18, in_fid_persistent);
86 SBVAL(fixed, 0x20, in_fid_volatile);
88 if (input_buffer_length > 0) {
89 dyn = in_input_buffer->data;
90 dyn_len = in_input_buffer->length;
91 } else {
92 dyn = state->dyn_pad;
93 dyn_len = sizeof(state->dyn_pad);
96 subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_GETINFO,
97 0, 0, /* flags */
98 timeout_msec,
99 0xFEFF, /* pid */
100 tcon_id,
101 session,
102 state->fixed, sizeof(state->fixed),
103 dyn, dyn_len);
104 if (tevent_req_nomem(subreq, req)) {
105 return tevent_req_post(req, ev);
107 tevent_req_set_callback(subreq, smb2cli_query_info_done, req);
108 return req;
111 static void smb2cli_query_info_done(struct tevent_req *subreq)
113 struct tevent_req *req =
114 tevent_req_callback_data(subreq,
115 struct tevent_req);
116 struct smb2cli_query_info_state *state =
117 tevent_req_data(req,
118 struct smb2cli_query_info_state);
119 NTSTATUS status;
120 struct iovec *iov;
121 uint8_t *fixed;
122 uint8_t *dyn;
123 size_t dyn_len;
124 uint32_t dyn_ofs = SMB2_HDR_BODY + 0x08;
125 uint32_t output_buffer_offset;
126 uint32_t output_buffer_length;
127 static const struct smb2cli_req_expected_response expected[] = {
129 .status = NT_STATUS_OK,
130 .body_size = 0x09
133 .status = STATUS_BUFFER_OVERFLOW,
134 .body_size = 0x09
138 status = smb2cli_req_recv(subreq, state, &iov,
139 expected, ARRAY_SIZE(expected));
140 if (tevent_req_nterror(req, status)) {
141 return;
144 state->recv_iov = iov;
145 fixed = (uint8_t *)iov[1].iov_base;
146 dyn = (uint8_t *)iov[2].iov_base;
147 dyn_len = iov[2].iov_len;
149 output_buffer_offset = SVAL(fixed, 0x02);
150 output_buffer_length = IVAL(fixed, 0x04);
152 if ((output_buffer_offset > 0) && (output_buffer_length > 0)) {
153 if (output_buffer_offset != dyn_ofs) {
154 tevent_req_nterror(
155 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
156 return;
159 if (output_buffer_length < dyn_len) {
160 tevent_req_nterror(
161 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
162 return;
165 if (output_buffer_length > state->max_output_length) {
166 tevent_req_nterror(
167 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
168 return;
171 state->out_output_buffer.data = dyn;
172 state->out_output_buffer.length = output_buffer_length;
175 tevent_req_done(req);
178 NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
179 TALLOC_CTX *mem_ctx,
180 DATA_BLOB *out_output_buffer)
182 struct smb2cli_query_info_state *state =
183 tevent_req_data(req,
184 struct smb2cli_query_info_state);
185 NTSTATUS status;
187 if (tevent_req_is_nterror(req, &status)) {
188 tevent_req_received(req);
189 return status;
192 talloc_steal(mem_ctx, state->recv_iov);
193 if (out_output_buffer) {
194 *out_output_buffer = state->out_output_buffer;
197 tevent_req_received(req);
198 return NT_STATUS_OK;
201 NTSTATUS smb2cli_query_info(struct smbXcli_conn *conn,
202 uint32_t timeout_msec,
203 struct smbXcli_session *session,
204 uint32_t tcon_id,
205 uint8_t in_info_type,
206 uint8_t in_file_info_class,
207 uint32_t in_max_output_length,
208 const DATA_BLOB *in_input_buffer,
209 uint32_t in_additional_info,
210 uint32_t in_flags,
211 uint64_t in_fid_persistent,
212 uint64_t in_fid_volatile,
213 TALLOC_CTX *mem_ctx,
214 DATA_BLOB *out_output_buffer)
216 TALLOC_CTX *frame = talloc_stackframe();
217 struct tevent_context *ev;
218 struct tevent_req *req;
219 NTSTATUS status = NT_STATUS_NO_MEMORY;
221 if (smbXcli_conn_has_async_calls(conn)) {
223 * Can't use sync call while an async call is in flight
225 status = NT_STATUS_INVALID_PARAMETER_MIX;
226 goto fail;
228 ev = tevent_context_init(frame);
229 if (ev == NULL) {
230 goto fail;
232 req = smb2cli_query_info_send(frame, ev,
233 conn, timeout_msec,
234 session, tcon_id,
235 in_info_type,
236 in_file_info_class,
237 in_max_output_length,
238 in_input_buffer,
239 in_additional_info,
240 in_flags,
241 in_fid_persistent,
242 in_fid_volatile);
243 if (req == NULL) {
244 goto fail;
246 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
247 goto fail;
249 status = smb2cli_query_info_recv(req, mem_ctx,
250 out_output_buffer);
251 fail:
252 TALLOC_FREE(frame);
253 return status;