Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/libcli/raw/rawfsinfo.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   RAW_QFS_* operations
5
6
   Copyright (C) Andrew Tridgell 2003
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 "librpc/gen_ndr/ndr_misc.h"
26
27
/****************************************************************************
28
 Query FS Info - SMBdskattr call (async send)
29
****************************************************************************/
30
static struct smbcli_request *smb_raw_dskattr_send(struct smbcli_tree *tree,
31
            union smb_fsinfo *fsinfo)
32
0
{
33
0
  struct smbcli_request *req;
34
35
0
  req = smbcli_request_setup(tree, SMBdskattr, 0, 0);
36
0
  if (req == NULL) {
37
0
    return NULL;
38
0
  }
39
40
0
  if (!smbcli_request_send(req)) {
41
0
    smbcli_request_destroy(req);
42
0
    return NULL;
43
0
  }
44
45
0
  return req;
46
0
}
47
48
/****************************************************************************
49
 Query FS Info - SMBdskattr call (async recv)
50
****************************************************************************/
51
static NTSTATUS smb_raw_dskattr_recv(struct smbcli_request *req,
52
             union smb_fsinfo *fsinfo)
53
0
{
54
0
  if (!smbcli_request_receive(req) ||
55
0
      smbcli_request_is_error(req)) {
56
0
    goto failed;
57
0
  }
58
59
0
  SMBCLI_CHECK_WCT(req, 5);
60
0
  fsinfo->dskattr.out.units_total =     SVAL(req->in.vwv, VWV(0));
61
0
  fsinfo->dskattr.out.blocks_per_unit = SVAL(req->in.vwv, VWV(1));
62
0
  fsinfo->dskattr.out.block_size =      SVAL(req->in.vwv, VWV(2));
63
0
  fsinfo->dskattr.out.units_free =      SVAL(req->in.vwv, VWV(3));
64
65
0
failed:
66
0
  return smbcli_request_destroy(req);
67
0
}
68
69
70
/****************************************************************************
71
 RAW_QFS_ trans2 interface via blobs (async send)
72
****************************************************************************/
73
static struct smbcli_request *smb_raw_qfsinfo_send(struct smbcli_tree *tree,
74
            TALLOC_CTX *mem_ctx,
75
            uint16_t info_level)
76
0
{
77
0
  struct smb_trans2 tp;
78
0
  uint16_t setup = TRANSACT2_QFSINFO;
79
80
0
  tp.in.max_setup = 0;
81
0
  tp.in.flags = 0;
82
0
  tp.in.timeout = 0;
83
0
  tp.in.setup_count = 1;
84
0
  tp.in.max_param = 0;
85
0
  tp.in.max_data = 0xFFFF;
86
0
  tp.in.setup = &setup;
87
0
  tp.in.data = data_blob(NULL, 0);
88
0
  tp.in.timeout = 0;
89
90
0
  tp.in.params = data_blob_talloc(mem_ctx, NULL, 2);
91
0
  if (!tp.in.params.data) {
92
0
    return NULL;
93
0
  }
94
0
  SSVAL(tp.in.params.data, 0, info_level);
95
96
0
  return smb_raw_trans2_send(tree, &tp);
97
0
}
98
99
/****************************************************************************
100
 RAW_QFS_ trans2 interface via blobs (async recv)
101
****************************************************************************/
102
static NTSTATUS smb_raw_qfsinfo_blob_recv(struct smbcli_request *req,
103
            TALLOC_CTX *mem_ctx,
104
            DATA_BLOB *blob)
105
0
{
106
0
  struct smb_trans2 tp;
107
0
  NTSTATUS status;
108
109
0
  status = smb_raw_trans2_recv(req, mem_ctx, &tp);
110
111
0
  if (NT_STATUS_IS_OK(status)) {
112
0
    (*blob) = tp.out.data;
113
0
  }
114
115
0
  return status;
116
0
}
117
118
119
/* local macros to make the code more readable */
120
0
#define QFS_CHECK_MIN_SIZE(size) if (blob.length < (size)) { \
121
0
      DEBUG(1,("Unexpected QFS reply size %d for level %u - expected min of %d\n", \
122
0
         (int)blob.length, fsinfo->generic.level, (size))); \
123
0
      status = NT_STATUS_INFO_LENGTH_MISMATCH; \
124
0
      goto failed; \
125
0
}
126
0
#define QFS_CHECK_SIZE(size) if (blob.length != (size)) { \
127
0
      DEBUG(1,("Unexpected QFS reply size %d for level %u - expected %d\n", \
128
0
         (int)blob.length, fsinfo->generic.level, (size))); \
129
0
      status = NT_STATUS_INFO_LENGTH_MISMATCH; \
130
0
      goto failed; \
131
0
}
132
133
134
/****************************************************************************
135
 Query FSInfo raw interface (async send)
136
****************************************************************************/
137
struct smbcli_request *smb_raw_fsinfo_send(struct smbcli_tree *tree,
138
          TALLOC_CTX *mem_ctx,
139
          union smb_fsinfo *fsinfo)
140
0
{
141
0
  uint16_t info_level;
142
143
  /* handle the only non-trans2 call separately */
144
0
  if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
145
0
    return smb_raw_dskattr_send(tree, fsinfo);
146
0
  }
147
0
  if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
148
0
    return NULL;
149
0
  }
150
151
  /* the headers map the trans2 levels direct to info levels */
152
0
  info_level = (uint16_t)fsinfo->generic.level;
153
154
0
  return smb_raw_qfsinfo_send(tree, mem_ctx, info_level);
155
0
}
156
157
/*
158
  parse the fsinfo 'passthru' level replies
159
*/
160
NTSTATUS smb_raw_fsinfo_passthru_parse(DATA_BLOB blob, TALLOC_CTX *mem_ctx,
161
               enum smb_fsinfo_level level,
162
               union smb_fsinfo *fsinfo)
163
0
{
164
0
  NTSTATUS status = NT_STATUS_OK;
165
0
  int i;
166
167
  /* parse the results */
168
0
  switch (level) {
169
0
  case RAW_QFS_VOLUME_INFORMATION:
170
0
    QFS_CHECK_MIN_SIZE(18);
171
0
    fsinfo->volume_info.out.create_time   = smbcli_pull_nttime(blob.data, 0);
172
0
    fsinfo->volume_info.out.serial_number = IVAL(blob.data, 8);
173
0
    smbcli_blob_pull_string(NULL, mem_ctx, &blob,
174
0
          &fsinfo->volume_info.out.volume_name,
175
0
          12, 18, STR_UNICODE);
176
0
    break;
177
178
0
  case RAW_QFS_SIZE_INFORMATION:
179
0
    QFS_CHECK_SIZE(24);
180
0
    fsinfo->size_info.out.total_alloc_units = BVAL(blob.data,  0);
181
0
    fsinfo->size_info.out.avail_alloc_units = BVAL(blob.data,  8);
182
0
    fsinfo->size_info.out.sectors_per_unit =  IVAL(blob.data, 16);
183
0
    fsinfo->size_info.out.bytes_per_sector =  IVAL(blob.data, 20);
184
0
    break;
185
186
0
  case RAW_QFS_DEVICE_INFORMATION:
187
0
    QFS_CHECK_SIZE(8);
188
0
    fsinfo->device_info.out.device_type     = IVAL(blob.data,  0);
189
0
    fsinfo->device_info.out.characteristics = IVAL(blob.data,  4);
190
0
    break;
191
192
0
  case RAW_QFS_ATTRIBUTE_INFORMATION:
193
0
    QFS_CHECK_MIN_SIZE(12);
194
0
    fsinfo->attribute_info.out.fs_attr   =                 IVAL(blob.data, 0);
195
0
    fsinfo->attribute_info.out.max_file_component_length = IVAL(blob.data, 4);
196
0
    smbcli_blob_pull_string(NULL, mem_ctx, &blob,
197
0
          &fsinfo->attribute_info.out.fs_type,
198
0
          8, 12, STR_UNICODE);
199
0
    break;
200
201
0
  case RAW_QFS_QUOTA_INFORMATION:
202
0
    QFS_CHECK_SIZE(48);
203
0
    fsinfo->quota_information.out.unknown[0] =  BVAL(blob.data,  0);
204
0
    fsinfo->quota_information.out.unknown[1] =  BVAL(blob.data,  8);
205
0
    fsinfo->quota_information.out.unknown[2] =  BVAL(blob.data, 16);
206
0
    fsinfo->quota_information.out.quota_soft =  BVAL(blob.data, 24);
207
0
    fsinfo->quota_information.out.quota_hard =  BVAL(blob.data, 32);
208
0
    fsinfo->quota_information.out.quota_flags = BVAL(blob.data, 40);
209
0
    break;
210
211
0
  case RAW_QFS_FULL_SIZE_INFORMATION:
212
0
    QFS_CHECK_SIZE(32);
213
0
    fsinfo->full_size_information.out.total_alloc_units =        BVAL(blob.data,  0);
214
0
    fsinfo->full_size_information.out.call_avail_alloc_units =   BVAL(blob.data,  8);
215
0
    fsinfo->full_size_information.out.actual_avail_alloc_units = BVAL(blob.data, 16);
216
0
    fsinfo->full_size_information.out.sectors_per_unit =         IVAL(blob.data, 24);
217
0
    fsinfo->full_size_information.out.bytes_per_sector =         IVAL(blob.data, 28);
218
0
    break;
219
220
0
  case RAW_QFS_OBJECTID_INFORMATION: {
221
0
    DATA_BLOB b2 = data_blob_const(blob.data, MIN(16, blob.length));
222
0
    QFS_CHECK_SIZE(64);
223
0
    status = GUID_from_ndr_blob(&b2, &fsinfo->objectid_information.out.guid);
224
0
    NT_STATUS_NOT_OK_RETURN(status);
225
0
    for (i=0;i<6;i++) {
226
0
      fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8);
227
0
    }
228
0
    break;
229
230
0
  case RAW_QFS_SECTOR_SIZE_INFORMATION:
231
0
    QFS_CHECK_SIZE(28);
232
0
    fsinfo->sector_size_info.out.logical_bytes_per_sector
233
0
              = IVAL(blob.data,  0);
234
0
    fsinfo->sector_size_info.out.phys_bytes_per_sector_atomic
235
0
              = IVAL(blob.data,  4);
236
0
    fsinfo->sector_size_info.out.phys_bytes_per_sector_perf
237
0
              = IVAL(blob.data,  8);
238
0
    fsinfo->sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic
239
0
              = IVAL(blob.data, 12);
240
0
    fsinfo->sector_size_info.out.flags  = IVAL(blob.data, 16);
241
0
    fsinfo->sector_size_info.out.byte_off_sector_align
242
0
              = IVAL(blob.data, 20);
243
0
    fsinfo->sector_size_info.out.byte_off_partition_align
244
0
              = IVAL(blob.data, 24);
245
0
    break;
246
0
  }
247
248
0
  default:
249
0
    status = NT_STATUS_INVALID_INFO_CLASS;
250
0
  }
251
252
0
failed:
253
0
  return status;
254
0
}
255
256
257
/****************************************************************************
258
 Query FSInfo raw interface (async recv)
259
****************************************************************************/
260
NTSTATUS smb_raw_fsinfo_recv(struct smbcli_request *req,
261
           TALLOC_CTX *mem_ctx,
262
           union smb_fsinfo *fsinfo)
263
0
{
264
0
  DATA_BLOB blob;
265
0
  NTSTATUS status;
266
0
  struct smbcli_session *session = req?req->session:NULL;
267
268
0
  if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
269
0
    return smb_raw_dskattr_recv(req, fsinfo);
270
0
  }
271
272
0
  status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob);
273
0
  if (!NT_STATUS_IS_OK(status)) {
274
0
    return status;
275
0
  }
276
277
  /* parse the results */
278
0
  switch (fsinfo->generic.level) {
279
0
  case RAW_QFS_GENERIC:
280
0
  case RAW_QFS_DSKATTR:
281
    /* handled above */
282
0
    break;
283
284
0
  case RAW_QFS_ALLOCATION:
285
0
    QFS_CHECK_SIZE(18);
286
0
    fsinfo->allocation.out.fs_id =             IVAL(blob.data,  0);
287
0
    fsinfo->allocation.out.sectors_per_unit =  IVAL(blob.data,  4);
288
0
    fsinfo->allocation.out.total_alloc_units = IVAL(blob.data,  8);
289
0
    fsinfo->allocation.out.avail_alloc_units = IVAL(blob.data, 12);
290
0
    fsinfo->allocation.out.bytes_per_sector =  SVAL(blob.data, 16);
291
0
    break;
292
293
0
  case RAW_QFS_VOLUME:
294
0
    QFS_CHECK_MIN_SIZE(5);
295
0
    fsinfo->volume.out.serial_number = IVAL(blob.data, 0);
296
0
    smbcli_blob_pull_string(session, mem_ctx, &blob,
297
0
             &fsinfo->volume.out.volume_name,
298
0
             4, 5, STR_LEN8BIT | STR_NOALIGN);
299
0
    break;
300
301
0
  case RAW_QFS_VOLUME_INFO:
302
0
  case RAW_QFS_VOLUME_INFORMATION:
303
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
304
0
                 RAW_QFS_VOLUME_INFORMATION, fsinfo);
305
306
0
  case RAW_QFS_SIZE_INFO:
307
0
  case RAW_QFS_SIZE_INFORMATION:
308
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
309
0
                 RAW_QFS_SIZE_INFORMATION, fsinfo);
310
311
0
  case RAW_QFS_DEVICE_INFO:
312
0
  case RAW_QFS_DEVICE_INFORMATION:
313
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
314
0
                 RAW_QFS_DEVICE_INFORMATION, fsinfo);
315
316
0
  case RAW_QFS_ATTRIBUTE_INFO:
317
0
  case RAW_QFS_ATTRIBUTE_INFORMATION:
318
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
319
0
                 RAW_QFS_ATTRIBUTE_INFORMATION, fsinfo);
320
321
0
  case RAW_QFS_UNIX_INFO:
322
0
    QFS_CHECK_SIZE(12);
323
0
    fsinfo->unix_info.out.major_version = SVAL(blob.data, 0);
324
0
    fsinfo->unix_info.out.minor_version = SVAL(blob.data, 2);
325
0
    fsinfo->unix_info.out.capability    = SVAL(blob.data, 4);
326
0
    break;
327
328
0
  case RAW_QFS_QUOTA_INFORMATION:
329
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
330
0
                 RAW_QFS_QUOTA_INFORMATION, fsinfo);
331
332
0
  case RAW_QFS_FULL_SIZE_INFORMATION:
333
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
334
0
                 RAW_QFS_FULL_SIZE_INFORMATION, fsinfo);
335
336
0
  case RAW_QFS_OBJECTID_INFORMATION:
337
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
338
0
                 RAW_QFS_OBJECTID_INFORMATION, fsinfo);
339
340
0
  case RAW_QFS_SECTOR_SIZE_INFORMATION:
341
0
    return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
342
0
        RAW_QFS_SECTOR_SIZE_INFORMATION, fsinfo);
343
0
  }
344
345
0
failed:
346
0
  return status;
347
0
}
348
349
/****************************************************************************
350
 Query FSInfo raw interface (sync interface)
351
****************************************************************************/
352
_PUBLIC_ NTSTATUS smb_raw_fsinfo(struct smbcli_tree *tree,
353
      TALLOC_CTX *mem_ctx,
354
      union smb_fsinfo *fsinfo)
355
0
{
356
0
  struct smbcli_request *req = smb_raw_fsinfo_send(tree, mem_ctx, fsinfo);
357
0
  return smb_raw_fsinfo_recv(req, mem_ctx, fsinfo);
358
0
}
359
360
/****************************************************************************
361
 Set FSInfo raw interface (async recv)
362
****************************************************************************/
363
static NTSTATUS smb_raw_setfsinfo_recv(struct smbcli_request *req,
364
           TALLOC_CTX *mem_ctx,
365
           union smb_setfsinfo *set_fsinfo)
366
0
{
367
0
  DATA_BLOB blob = data_blob_null;
368
0
  NTSTATUS status;
369
370
0
  if (set_fsinfo->generic.level != RAW_SETFS_UNIX_INFO) {
371
0
    return NT_STATUS_INVALID_PARAMETER;
372
0
  }
373
374
0
  status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob);
375
0
  data_blob_free(&blob);
376
0
  return status;
377
0
}
378
379
/****************************************************************************
380
 Set FSInfo raw interface (async send)
381
****************************************************************************/
382
static struct smbcli_request *smb_raw_setfsinfo_send(struct smbcli_tree *tree,
383
            TALLOC_CTX *mem_ctx,
384
            union smb_setfsinfo *set_fsinfo)
385
0
{
386
0
  struct smb_trans2 tp;
387
0
  uint16_t info_level;
388
0
  uint16_t setup = TRANSACT2_SETFSINFO;
389
390
0
  if (set_fsinfo->generic.level != RAW_SETFS_UNIX_INFO) {
391
0
    return NULL;
392
0
  }
393
0
  tp.in.max_setup = 0;
394
0
  tp.in.flags = 0;
395
0
  tp.in.timeout = 0;
396
0
  tp.in.setup_count = 1;
397
0
  tp.in.max_param = 0;
398
0
  tp.in.max_data = 0xFFFF;
399
0
  tp.in.setup = &setup;
400
0
  tp.in.timeout = 0;
401
402
0
  tp.in.params = data_blob_talloc(mem_ctx, NULL, 4);
403
0
  if (!tp.in.params.data) {
404
0
    return NULL;
405
0
  }
406
0
  info_level = (uint16_t)set_fsinfo->generic.level;
407
0
  SSVAL(tp.in.params.data, 0, 0);
408
0
  SSVAL(tp.in.params.data, 2, info_level);
409
410
0
  tp.in.data = data_blob_talloc(mem_ctx, NULL, 12);
411
0
  if (!tp.in.data.data) {
412
0
    return NULL;
413
0
  }
414
415
0
  SSVAL(tp.in.data.data, 0, set_fsinfo->unix_info.in.major_version);
416
0
  SSVAL(tp.in.data.data, 2, set_fsinfo->unix_info.in.minor_version);
417
0
  SBVAL(tp.in.data.data, 4, set_fsinfo->unix_info.in.capability);
418
419
0
  return smb_raw_trans2_send(tree, &tp);
420
0
}
421
422
/****************************************************************************
423
 Set FSInfo raw interface (sync interface)
424
****************************************************************************/
425
_PUBLIC_ NTSTATUS smb_raw_setfsinfo(struct smbcli_tree *tree,
426
      TALLOC_CTX *mem_ctx,
427
      union smb_setfsinfo *set_fsinfo)
428
0
{
429
0
  struct smbcli_request *req = smb_raw_setfsinfo_send(tree, mem_ctx, set_fsinfo);
430
0
  return smb_raw_setfsinfo_recv(req, mem_ctx, set_fsinfo);
431
0
}