Coverage Report

Created: 2025-07-23 07:04

/src/samba/libcli/smb/smb2cli_query_info.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Unix SMB/CIFS implementation.
3
   smb2 lib
4
   Copyright (C) Stefan Metzmacher 2012
5
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.
10
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.
15
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/>.
18
*/
19
20
#include "includes.h"
21
#include "system/network.h"
22
#include "lib/util/tevent_ntstatus.h"
23
#include "smb_common.h"
24
#include "smbXcli_base.h"
25
26
struct smb2cli_query_info_state {
27
  uint8_t fixed[0x28];
28
  uint8_t dyn_pad[1];
29
  uint32_t max_output_length;
30
  struct iovec *recv_iov;
31
  DATA_BLOB out_output_buffer;
32
  bool out_valid;
33
};
34
35
static void smb2cli_query_info_done(struct tevent_req *subreq);
36
37
struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx,
38
             struct tevent_context *ev,
39
             struct smbXcli_conn *conn,
40
             uint32_t timeout_msec,
41
             struct smbXcli_session *session,
42
             struct smbXcli_tcon *tcon,
43
             uint8_t in_info_type,
44
             uint8_t in_file_info_class,
45
             uint32_t in_max_output_length,
46
             const DATA_BLOB *in_input_buffer,
47
             uint32_t in_additional_info,
48
             uint32_t in_flags,
49
             uint64_t in_fid_persistent,
50
             uint64_t in_fid_volatile)
51
0
{
52
0
  struct tevent_req *req, *subreq;
53
0
  struct smb2cli_query_info_state *state;
54
0
  uint8_t *fixed;
55
0
  uint8_t *dyn;
56
0
  size_t dyn_len;
57
0
  uint16_t input_buffer_offset = 0;
58
0
  uint32_t input_buffer_length = 0;
59
60
0
  req = tevent_req_create(mem_ctx, &state,
61
0
        struct smb2cli_query_info_state);
62
0
  if (req == NULL) {
63
0
    return NULL;
64
0
  }
65
0
  state->max_output_length = in_max_output_length;
66
67
0
  if (in_input_buffer) {
68
0
    input_buffer_offset = SMB2_HDR_BODY+0x28;
69
0
    input_buffer_length = in_input_buffer->length;
70
0
  }
71
72
0
  fixed = state->fixed;
73
74
0
  SSVAL(fixed, 0x00, 0x29);
75
0
  SCVAL(fixed, 0x02, in_info_type);
76
0
  SCVAL(fixed, 0x03, in_file_info_class); /* reserved */
77
0
  SIVAL(fixed, 0x04, in_max_output_length);
78
0
  SSVAL(fixed, 0x08, input_buffer_offset);
79
0
  SSVAL(fixed, 0x0A, 0); /* reserved */
80
0
  SIVAL(fixed, 0x0C, input_buffer_length);
81
0
  SIVAL(fixed, 0x10, in_additional_info);
82
0
  SIVAL(fixed, 0x14, in_flags);
83
0
  SBVAL(fixed, 0x18, in_fid_persistent);
84
0
  SBVAL(fixed, 0x20, in_fid_volatile);
85
86
0
  if (input_buffer_length > 0) {
87
0
    dyn = in_input_buffer->data;
88
0
    dyn_len = in_input_buffer->length;
89
0
  } else {
90
0
    dyn = state->dyn_pad;
91
0
    dyn_len = sizeof(state->dyn_pad);
92
0
  }
93
94
0
  subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_GETINFO,
95
0
          0, 0, /* flags */
96
0
          timeout_msec,
97
0
          tcon,
98
0
          session,
99
0
          state->fixed, sizeof(state->fixed),
100
0
          dyn, dyn_len,
101
0
          in_max_output_length); /* max_dyn_len */
102
0
  if (tevent_req_nomem(subreq, req)) {
103
0
    return tevent_req_post(req, ev);
104
0
  }
105
0
  tevent_req_set_callback(subreq, smb2cli_query_info_done, req);
106
0
  return req;
107
0
}
108
109
static void smb2cli_query_info_done(struct tevent_req *subreq)
110
0
{
111
0
  struct tevent_req *req =
112
0
    tevent_req_callback_data(subreq,
113
0
    struct tevent_req);
114
0
  struct smb2cli_query_info_state *state =
115
0
    tevent_req_data(req,
116
0
    struct smb2cli_query_info_state);
117
0
  NTSTATUS status;
118
0
  struct iovec *iov;
119
0
  uint8_t *fixed;
120
0
  uint8_t *dyn;
121
0
  size_t dyn_len;
122
0
  uint32_t dyn_ofs = SMB2_HDR_BODY + 0x08;
123
0
  uint32_t output_buffer_offset;
124
0
  uint32_t output_buffer_length;
125
0
  static const struct smb2cli_req_expected_response expected[] = {
126
0
  {
127
0
    .status = NT_STATUS_OK,
128
0
    .body_size = 0x09
129
0
  },
130
0
  {
131
0
    .status = STATUS_BUFFER_OVERFLOW,
132
0
    .body_size = 0x09
133
0
  }
134
0
  };
135
136
0
  status = smb2cli_req_recv(subreq, state, &iov,
137
0
          expected, ARRAY_SIZE(expected));
138
0
  TALLOC_FREE(subreq);
139
0
  if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
140
    /* no error */
141
0
  } else {
142
0
    if (tevent_req_nterror(req, status)) {
143
0
      return;
144
0
    }
145
0
  }
146
147
0
  state->recv_iov = iov;
148
0
  fixed = (uint8_t *)iov[1].iov_base;
149
0
  dyn = (uint8_t *)iov[2].iov_base;
150
0
  dyn_len = iov[2].iov_len;
151
152
0
  output_buffer_offset = SVAL(fixed, 0x02);
153
0
  output_buffer_length = IVAL(fixed, 0x04);
154
155
0
  if ((output_buffer_offset > 0) && (output_buffer_length > 0)) {
156
0
    if (output_buffer_offset != dyn_ofs) {
157
0
      tevent_req_nterror(
158
0
        req, NT_STATUS_INVALID_NETWORK_RESPONSE);
159
0
      return;
160
0
    }
161
162
0
    if (output_buffer_length > dyn_len) {
163
0
      tevent_req_nterror(
164
0
        req, NT_STATUS_INVALID_NETWORK_RESPONSE);
165
0
      return;
166
0
    }
167
168
0
    if (output_buffer_length > state->max_output_length) {
169
0
      tevent_req_nterror(
170
0
        req, NT_STATUS_INVALID_NETWORK_RESPONSE);
171
0
      return;
172
0
    }
173
174
0
    state->out_output_buffer.data = dyn;
175
0
    state->out_output_buffer.length = output_buffer_length;
176
0
  }
177
178
0
  state->out_valid = true;
179
180
0
  if (tevent_req_nterror(req, status)) {
181
0
    return;
182
0
  }
183
184
0
  tevent_req_done(req);
185
0
}
186
187
NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
188
         TALLOC_CTX *mem_ctx,
189
         DATA_BLOB *out_output_buffer)
190
0
{
191
0
  struct smb2cli_query_info_state *state =
192
0
    tevent_req_data(req,
193
0
    struct smb2cli_query_info_state);
194
0
  NTSTATUS status = NT_STATUS_OK;
195
196
0
  if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
197
0
    if (out_output_buffer) {
198
0
      *out_output_buffer = data_blob_null;
199
0
    }
200
0
    tevent_req_received(req);
201
0
    return status;
202
0
  }
203
204
0
  talloc_steal(mem_ctx, state->recv_iov);
205
0
  if (out_output_buffer) {
206
0
    *out_output_buffer = state->out_output_buffer;
207
0
  }
208
209
0
  tevent_req_received(req);
210
0
  return status;
211
0
}
212
213
NTSTATUS smb2cli_query_info(struct smbXcli_conn *conn,
214
          uint32_t timeout_msec,
215
          struct smbXcli_session *session,
216
          struct smbXcli_tcon *tcon,
217
          uint8_t in_info_type,
218
          uint8_t in_file_info_class,
219
          uint32_t in_max_output_length,
220
          const DATA_BLOB *in_input_buffer,
221
          uint32_t in_additional_info,
222
          uint32_t in_flags,
223
          uint64_t in_fid_persistent,
224
          uint64_t in_fid_volatile,
225
          TALLOC_CTX *mem_ctx,
226
          DATA_BLOB *out_output_buffer)
227
0
{
228
0
  TALLOC_CTX *frame = talloc_stackframe();
229
0
  struct tevent_context *ev;
230
0
  struct tevent_req *req;
231
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
232
233
0
  if (smbXcli_conn_has_async_calls(conn)) {
234
    /*
235
     * Can't use sync call while an async call is in flight
236
     */
237
0
    status = NT_STATUS_INVALID_PARAMETER_MIX;
238
0
    goto fail;
239
0
  }
240
0
  ev = samba_tevent_context_init(frame);
241
0
  if (ev == NULL) {
242
0
    goto fail;
243
0
  }
244
0
  req = smb2cli_query_info_send(frame, ev,
245
0
              conn, timeout_msec,
246
0
              session, tcon,
247
0
              in_info_type,
248
0
              in_file_info_class,
249
0
              in_max_output_length,
250
0
              in_input_buffer,
251
0
              in_additional_info,
252
0
              in_flags,
253
0
              in_fid_persistent,
254
0
              in_fid_volatile);
255
0
  if (req == NULL) {
256
0
    goto fail;
257
0
  }
258
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
259
0
    goto fail;
260
0
  }
261
0
  status = smb2cli_query_info_recv(req, mem_ctx,
262
0
           out_output_buffer);
263
0
 fail:
264
0
  TALLOC_FREE(frame);
265
0
  return status;
266
0
}