Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/smbd/smb2_getinfo.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Core SMB2 server
4
5
   Copyright (C) Stefan Metzmacher 2009
6
   Copyright (C) Jeremy Allison 2010
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 "smbd/smbd.h"
24
#include "smbd/globals.h"
25
#include "../libcli/smb/smb_common.h"
26
#include "trans2.h"
27
#include "../lib/util/tevent_ntstatus.h"
28
#include "librpc/gen_ndr/ndr_quota.h"
29
#include "librpc/gen_ndr/ndr_security.h"
30
31
#undef DBGC_CLASS
32
0
#define DBGC_CLASS DBGC_SMB2
33
34
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
35
             struct tevent_context *ev,
36
             struct smbd_smb2_request *smb2req,
37
             struct files_struct *in_fsp,
38
             uint8_t in_info_type,
39
             uint8_t in_file_info_class,
40
             uint32_t in_output_buffer_length,
41
             DATA_BLOB in_input_buffer,
42
             uint32_t in_additional_information,
43
             uint32_t in_flags);
44
static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req,
45
               TALLOC_CTX *mem_ctx,
46
               DATA_BLOB *out_output_buffer,
47
               NTSTATUS *p_call_status);
48
49
static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq);
50
NTSTATUS smbd_smb2_request_process_getinfo(struct smbd_smb2_request *req)
51
0
{
52
0
  struct smbXsrv_connection *xconn = req->xconn;
53
0
  NTSTATUS status;
54
0
  const uint8_t *inbody;
55
0
  uint8_t in_info_type;
56
0
  uint8_t in_file_info_class;
57
0
  uint32_t in_output_buffer_length;
58
0
  uint16_t in_input_buffer_offset;
59
0
  uint32_t in_input_buffer_length;
60
0
  DATA_BLOB in_input_buffer;
61
0
  uint32_t in_additional_information;
62
0
  uint32_t in_flags;
63
0
  uint64_t in_file_id_persistent;
64
0
  uint64_t in_file_id_volatile;
65
0
  struct files_struct *in_fsp;
66
0
  struct tevent_req *subreq;
67
68
0
  status = smbd_smb2_request_verify_sizes(req, 0x29);
69
0
  if (!NT_STATUS_IS_OK(status)) {
70
0
    return smbd_smb2_request_error(req, status);
71
0
  }
72
0
  inbody = SMBD_SMB2_IN_BODY_PTR(req);
73
74
0
  in_info_type      = CVAL(inbody, 0x02);
75
0
  in_file_info_class    = CVAL(inbody, 0x03);
76
0
  in_output_buffer_length   = IVAL(inbody, 0x04);
77
0
  in_input_buffer_offset    = SVAL(inbody, 0x08);
78
  /* 0x0A 2 bytes reserved */
79
0
  in_input_buffer_length    = IVAL(inbody, 0x0C);
80
0
  in_additional_information = IVAL(inbody, 0x10);
81
0
  in_flags      = IVAL(inbody, 0x14);
82
0
  in_file_id_persistent   = BVAL(inbody, 0x18);
83
0
  in_file_id_volatile   = BVAL(inbody, 0x20);
84
85
0
  if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) {
86
    /* This is ok */
87
0
  } else if (in_input_buffer_offset !=
88
0
       (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
89
0
    return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
90
0
  }
91
92
0
  if (in_input_buffer_length > SMBD_SMB2_IN_DYN_LEN(req)) {
93
0
    return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
94
0
  }
95
96
0
  in_input_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
97
0
  in_input_buffer.length = in_input_buffer_length;
98
99
0
  if (in_input_buffer.length > xconn->smb2.server.max_trans) {
100
0
    DEBUG(2,("smbd_smb2_request_process_getinfo: "
101
0
       "client ignored max trans: %s: 0x%08X: 0x%08X\n",
102
0
       __location__, (unsigned)in_input_buffer.length,
103
0
       (unsigned)xconn->smb2.server.max_trans));
104
0
    return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
105
0
  }
106
0
  if (in_output_buffer_length > xconn->smb2.server.max_trans) {
107
0
    DEBUG(2,("smbd_smb2_request_process_getinfo: "
108
0
       "client ignored max trans: %s: 0x%08X: 0x%08X\n",
109
0
       __location__, in_output_buffer_length,
110
0
       xconn->smb2.server.max_trans));
111
0
    return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
112
0
  }
113
114
0
  status = smbd_smb2_request_verify_creditcharge(req,
115
0
      MAX(in_input_buffer.length,in_output_buffer_length));
116
0
  if (!NT_STATUS_IS_OK(status)) {
117
0
    return smbd_smb2_request_error(req, status);
118
0
  }
119
120
0
  in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
121
0
  if (in_fsp == NULL) {
122
0
    return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
123
0
  }
124
125
0
  subreq = smbd_smb2_getinfo_send(req, req->sconn->ev_ctx,
126
0
          req, in_fsp,
127
0
          in_info_type,
128
0
          in_file_info_class,
129
0
          in_output_buffer_length,
130
0
          in_input_buffer,
131
0
          in_additional_information,
132
0
          in_flags);
133
0
  if (subreq == NULL) {
134
0
    return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
135
0
  }
136
0
  tevent_req_set_callback(subreq, smbd_smb2_request_getinfo_done, req);
137
138
0
  return smbd_smb2_request_pending_queue(req, subreq, 500);
139
0
}
140
141
static void smbd_smb2_request_getinfo_done(struct tevent_req *subreq)
142
0
{
143
0
  struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
144
0
          struct smbd_smb2_request);
145
0
  DATA_BLOB outbody;
146
0
  DATA_BLOB outdyn;
147
0
  uint16_t out_output_buffer_offset;
148
0
  DATA_BLOB out_output_buffer = data_blob_null;
149
0
  NTSTATUS status;
150
0
  NTSTATUS call_status = NT_STATUS_OK;
151
0
  NTSTATUS error; /* transport error */
152
153
0
  status = smbd_smb2_getinfo_recv(subreq,
154
0
          req,
155
0
          &out_output_buffer,
156
0
          &call_status);
157
0
  TALLOC_FREE(subreq);
158
0
  if (!NT_STATUS_IS_OK(status)) {
159
0
    error = smbd_smb2_request_error(req, status);
160
0
    if (!NT_STATUS_IS_OK(error)) {
161
0
      smbd_server_connection_terminate(req->xconn,
162
0
               nt_errstr(error));
163
0
      return;
164
0
    }
165
0
    return;
166
0
  }
167
168
  /* some GetInfo responses set STATUS_BUFFER_OVERFLOW and return partial,
169
     but valid data */
170
0
  if (!(NT_STATUS_IS_OK(call_status) ||
171
0
        NT_STATUS_EQUAL(call_status, STATUS_BUFFER_OVERFLOW))) {
172
    /* Return a specific error with data. */
173
0
    error = smbd_smb2_request_error_ex(req,
174
0
            call_status,
175
0
            0,
176
0
            &out_output_buffer,
177
0
            __location__);
178
0
    if (!NT_STATUS_IS_OK(error)) {
179
0
      smbd_server_connection_terminate(req->xconn,
180
0
               nt_errstr(error));
181
0
      return;
182
0
    }
183
0
    return;
184
0
  }
185
186
0
  out_output_buffer_offset = SMB2_HDR_BODY + 0x08;
187
188
0
  outbody = smbd_smb2_generate_outbody(req, 0x08);
189
0
  if (outbody.data == NULL) {
190
0
    error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
191
0
    if (!NT_STATUS_IS_OK(error)) {
192
0
      smbd_server_connection_terminate(req->xconn,
193
0
               nt_errstr(error));
194
0
      return;
195
0
    }
196
0
    return;
197
0
  }
198
199
0
  SSVAL(outbody.data, 0x00, 0x08 + 1); /* struct size */
200
0
  SSVAL(outbody.data, 0x02,
201
0
        out_output_buffer_offset);  /* output buffer offset */
202
0
  SIVAL(outbody.data, 0x04,
203
0
        out_output_buffer.length);  /* output buffer length */
204
205
0
  outdyn = out_output_buffer;
206
207
0
  error = smbd_smb2_request_done_ex(req, call_status, outbody, &outdyn, __location__);
208
0
  if (!NT_STATUS_IS_OK(error)) {
209
0
    smbd_server_connection_terminate(req->xconn,
210
0
             nt_errstr(error));
211
0
    return;
212
0
  }
213
0
}
214
215
struct smbd_smb2_getinfo_state {
216
  struct smbd_smb2_request *smb2req;
217
  NTSTATUS status;
218
  DATA_BLOB out_output_buffer;
219
};
220
221
static void smb2_ipc_getinfo(struct tevent_req *req,
222
        struct smbd_smb2_getinfo_state *state,
223
        struct tevent_context *ev,
224
        uint8_t in_info_type,
225
        uint8_t in_file_info_class)
226
0
{
227
  /* We want to reply to SMB2_GETINFO_FILE
228
     with a class of SMB2_FILE_STANDARD_INFO as
229
     otherwise a Win7 client issues this request
230
     twice (2xroundtrips) if we return NOT_SUPPORTED.
231
     NB. We do the same for SMB1 in call_trans2qpipeinfo() */
232
233
0
  if (in_info_type == 0x01 && /* SMB2_GETINFO_FILE */
234
0
      in_file_info_class == 0x05) { /* SMB2_FILE_STANDARD_INFO */
235
0
    state->out_output_buffer = data_blob_talloc(state,
236
0
            NULL, 24);
237
0
    if (tevent_req_nomem(state->out_output_buffer.data, req)) {
238
0
      return;
239
0
    }
240
241
0
    memset(state->out_output_buffer.data,0,24);
242
0
    SOFF_T(state->out_output_buffer.data,0,4096LL);
243
0
    SIVAL(state->out_output_buffer.data,16,1);
244
0
    SIVAL(state->out_output_buffer.data,20,1);
245
0
    tevent_req_done(req);
246
0
  } else {
247
0
    tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
248
0
  }
249
0
}
250
251
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
252
             struct tevent_context *ev,
253
             struct smbd_smb2_request *smb2req,
254
             struct files_struct *fsp,
255
             uint8_t in_info_type,
256
             uint8_t in_file_info_class,
257
             uint32_t in_output_buffer_length,
258
             DATA_BLOB in_input_buffer,
259
             uint32_t in_additional_information,
260
             uint32_t in_flags)
261
0
{
262
0
  struct tevent_req *req;
263
0
  struct smbd_smb2_getinfo_state *state;
264
0
  struct smb_request *smbreq;
265
0
  connection_struct *conn = smb2req->tcon->compat;
266
0
  NTSTATUS status;
267
268
0
  req = tevent_req_create(mem_ctx, &state,
269
0
        struct smbd_smb2_getinfo_state);
270
0
  if (req == NULL) {
271
0
    return NULL;
272
0
  }
273
0
  state->smb2req = smb2req;
274
0
  state->status = NT_STATUS_OK;
275
0
  state->out_output_buffer = data_blob_null;
276
277
0
  DEBUG(10,("smbd_smb2_getinfo_send: %s - %s\n",
278
0
      fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
279
280
0
  smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
281
0
  if (tevent_req_nomem(smbreq, req)) {
282
0
    return tevent_req_post(req, ev);
283
0
  }
284
285
0
  if (IS_IPC(conn)) {
286
0
    smb2_ipc_getinfo(req, state, ev,
287
0
      in_info_type, in_file_info_class);
288
0
    return tevent_req_post(req, ev);
289
0
  }
290
291
0
  switch (in_info_type) {
292
0
  case SMB2_0_INFO_FILE:
293
0
  {
294
0
    uint16_t file_info_level;
295
0
    char *data = NULL;
296
0
    unsigned int data_size = 0;
297
0
    bool delete_pending = false;
298
0
    struct file_id fileid;
299
0
    size_t fixed_portion;
300
301
302
    /*
303
     * MS-SMB2 3.3.5.20.1 "Handling SMB2_0_INFO_FILE"
304
     *
305
     * FileBasicInformation, FileAllInformation,
306
     * FileNetworkOpenInformation, FileAttributeTagInformation
307
     * require FILE_READ_ATTRIBUTES.
308
     *
309
     * FileFullEaInformation requires FILE_READ_EA.
310
     */
311
0
    switch (in_file_info_class) {
312
0
    case FSCC_FILE_BASIC_INFORMATION:
313
0
    case FSCC_FILE_ALL_INFORMATION:
314
0
    case FSCC_FILE_NETWORK_OPEN_INFORMATION:
315
0
    case FSCC_FILE_ATTRIBUTE_TAG_INFORMATION:
316
0
      status = check_any_access_fsp(fsp, SEC_FILE_READ_ATTRIBUTE);
317
0
      if (tevent_req_nterror(req, status)) {
318
0
        return tevent_req_post(req, ev);
319
0
      }
320
0
      break;
321
322
0
    case FSCC_FILE_FULL_EA_INFORMATION:
323
0
      status = check_any_access_fsp(fsp, SEC_FILE_READ_EA);
324
0
      if (tevent_req_nterror(req, status)) {
325
0
        return tevent_req_post(req, ev);
326
0
      }
327
0
      break;
328
0
    }
329
330
0
    switch (in_file_info_class) {
331
0
    case FSCC_FILE_FULL_EA_INFORMATION:
332
0
      file_info_level = SMB2_FILE_FULL_EA_INFORMATION;
333
0
      break;
334
335
0
    case FSCC_FILE_ALL_INFORMATION:
336
0
      file_info_level = SMB2_FILE_ALL_INFORMATION;
337
0
      break;
338
339
0
    case FSCC_FILE_POSIX_INFORMATION:
340
0
      if (!fsp->fsp_flags.posix_open) {
341
0
        tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
342
0
        return tevent_req_post(req, ev);
343
0
      }
344
0
      file_info_level = in_file_info_class;
345
0
      break;
346
347
0
    default:
348
      /* the levels directly map to the passthru levels */
349
0
      file_info_level = in_file_info_class + NT_PASSTHROUGH_OFFSET;
350
0
      break;
351
0
    }
352
353
0
    switch (file_info_level) {
354
0
    case SMB_FILE_NORMALIZED_NAME_INFORMATION:
355
0
      if (smb2req->xconn->protocol < PROTOCOL_SMB3_11) {
356
0
        tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
357
0
        return tevent_req_post(req, ev);
358
0
      }
359
0
      break;
360
0
    }
361
362
0
    if (fsp->fake_file_handle) {
363
      /*
364
       * This is actually for the QUOTA_FAKE_FILE --metze
365
       */
366
367
      /* We know this name is ok, it's already passed the checks. */
368
369
0
    } else if (fsp_get_pathref_fd(fsp) == -1) {
370
      /*
371
       * This is actually a QFILEINFO on a directory
372
       * handle (returned from an NT SMB). NT5.0 seems
373
       * to do this call. JRA.
374
       */
375
0
      int ret = vfs_stat(conn, fsp->fsp_name);
376
0
      if (ret != 0) {
377
0
        DBG_NOTICE("vfs_stat of %s failed (%s)\n",
378
0
           fsp_str_dbg(fsp),
379
0
           strerror(errno));
380
0
        status = map_nt_error_from_unix(errno);
381
0
        tevent_req_nterror(req, status);
382
0
        return tevent_req_post(req, ev);
383
0
      }
384
385
0
      if (fsp_getinfo_ask_sharemode(fsp)) {
386
0
        fileid = vfs_file_id_from_sbuf(
387
0
          conn, &fsp->fsp_name->st);
388
0
        get_file_infos(fileid, fsp->name_hash,
389
0
                 &delete_pending);
390
0
      }
391
0
    } else {
392
      /*
393
       * Original code - this is an open file.
394
       */
395
396
0
      status = vfs_stat_fsp(fsp);
397
0
      if (!NT_STATUS_IS_OK(status)) {
398
0
        DEBUG(3, ("smbd_smb2_getinfo_send: "
399
0
            "fstat of %s failed (%s)\n",
400
0
            fsp_fnum_dbg(fsp), nt_errstr(status)));
401
0
        tevent_req_nterror(req, status);
402
0
        return tevent_req_post(req, ev);
403
0
      }
404
0
      if (fsp_getinfo_ask_sharemode(fsp)) {
405
0
        fileid = vfs_file_id_from_sbuf(
406
0
          conn, &fsp->fsp_name->st);
407
0
        get_file_infos(fileid, fsp->name_hash,
408
0
                 &delete_pending);
409
0
      }
410
0
    }
411
412
0
    status = smbd_do_qfilepathinfo(conn, state,
413
0
                 smbreq,
414
0
                 file_info_level,
415
0
                 fsp,
416
0
                 fsp->fsp_name,
417
0
                 delete_pending,
418
0
                 NULL,
419
0
                 STR_UNICODE,
420
0
                 in_output_buffer_length,
421
0
                 &fixed_portion,
422
0
                 &data,
423
0
                 &data_size);
424
0
    if (!NT_STATUS_IS_OK(status)) {
425
0
      SAFE_FREE(data);
426
0
      if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
427
0
        status = NT_STATUS_INVALID_INFO_CLASS;
428
0
      }
429
0
      tevent_req_nterror(req, status);
430
0
      return tevent_req_post(req, ev);
431
0
    }
432
0
    if (in_output_buffer_length < fixed_portion) {
433
0
      SAFE_FREE(data);
434
0
      tevent_req_nterror(
435
0
        req, NT_STATUS_INFO_LENGTH_MISMATCH);
436
0
      return tevent_req_post(req, ev);
437
0
    }
438
0
    if (data_size > 0) {
439
0
      state->out_output_buffer = data_blob_talloc(state,
440
0
                    data,
441
0
                    data_size);
442
0
      SAFE_FREE(data);
443
0
      if (tevent_req_nomem(state->out_output_buffer.data, req)) {
444
0
        return tevent_req_post(req, ev);
445
0
      }
446
0
      if (data_size > in_output_buffer_length) {
447
0
        state->out_output_buffer.length =
448
0
          in_output_buffer_length;
449
0
        status = STATUS_BUFFER_OVERFLOW;
450
0
      }
451
0
    }
452
0
    SAFE_FREE(data);
453
0
    break;
454
0
  }
455
456
0
  case SMB2_0_INFO_FILESYSTEM:
457
0
  {
458
0
    uint16_t file_info_level;
459
0
    char *data = NULL;
460
0
    int data_size = 0;
461
0
    size_t fixed_portion;
462
463
0
    switch (in_file_info_class) {
464
0
    case FSCC_FS_POSIX_INFORMATION:
465
0
      file_info_level = in_file_info_class;
466
0
      break;
467
0
    default:
468
      /* the levels directly map to the passthru levels */
469
0
      file_info_level = in_file_info_class + NT_PASSTHROUGH_OFFSET;
470
0
      break;
471
0
    }
472
473
0
    status = smbd_do_qfsinfo(smb2req->xconn,
474
0
           conn,
475
0
           state,
476
0
           file_info_level,
477
0
           STR_UNICODE,
478
0
           in_output_buffer_length,
479
0
           &fixed_portion,
480
0
           fsp,
481
0
           &data,
482
0
           &data_size);
483
    /* some responses set STATUS_BUFFER_OVERFLOW and return
484
       partial, but valid data */
485
0
    if (!(NT_STATUS_IS_OK(status) ||
486
0
          NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW))) {
487
0
      SAFE_FREE(data);
488
0
      if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
489
0
        status = NT_STATUS_INVALID_INFO_CLASS;
490
0
      }
491
0
      tevent_req_nterror(req, status);
492
0
      return tevent_req_post(req, ev);
493
0
    }
494
0
    if (in_output_buffer_length < fixed_portion) {
495
0
      SAFE_FREE(data);
496
0
      tevent_req_nterror(
497
0
        req, NT_STATUS_INFO_LENGTH_MISMATCH);
498
0
      return tevent_req_post(req, ev);
499
0
    }
500
0
    if (data_size > 0) {
501
0
      state->out_output_buffer = data_blob_talloc(state,
502
0
                    data,
503
0
                    data_size);
504
0
      SAFE_FREE(data);
505
0
      if (tevent_req_nomem(state->out_output_buffer.data, req)) {
506
0
        return tevent_req_post(req, ev);
507
0
      }
508
0
      if (data_size > in_output_buffer_length) {
509
0
        state->out_output_buffer.length =
510
0
          in_output_buffer_length;
511
0
        status = STATUS_BUFFER_OVERFLOW;
512
0
      }
513
0
    }
514
0
    SAFE_FREE(data);
515
0
    break;
516
0
  }
517
518
0
  case SMB2_0_INFO_SECURITY:
519
0
  {
520
0
    uint8_t *p_marshalled_sd = NULL;
521
0
    size_t sd_size = 0;
522
523
0
    status = smbd_do_query_security_desc(conn,
524
0
        state,
525
0
        fsp,
526
        /* Security info wanted. */
527
0
        in_additional_information &
528
0
        SMB_SUPPORTED_SECINFO_FLAGS,
529
0
        in_output_buffer_length,
530
0
        &p_marshalled_sd,
531
0
        &sd_size);
532
533
0
    if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
534
      /* Return needed size. */
535
0
      state->out_output_buffer = data_blob_talloc(state,
536
0
                    NULL,
537
0
                    4);
538
0
      if (tevent_req_nomem(state->out_output_buffer.data, req)) {
539
0
        return tevent_req_post(req, ev);
540
0
      }
541
0
      SIVAL(state->out_output_buffer.data,0,(uint32_t)sd_size);
542
0
      state->status = NT_STATUS_BUFFER_TOO_SMALL;
543
0
      break;
544
0
    }
545
0
    if (!NT_STATUS_IS_OK(status)) {
546
0
      DEBUG(10,("smbd_smb2_getinfo_send: "
547
0
         "smbd_do_query_security_desc of %s failed "
548
0
         "(%s)\n", fsp_str_dbg(fsp),
549
0
         nt_errstr(status)));
550
0
      tevent_req_nterror(req, status);
551
0
      return tevent_req_post(req, ev);
552
0
    }
553
554
0
    if (sd_size > 0) {
555
0
      state->out_output_buffer = data_blob_talloc(state,
556
0
                    p_marshalled_sd,
557
0
                    sd_size);
558
0
      if (tevent_req_nomem(state->out_output_buffer.data, req)) {
559
0
        return tevent_req_post(req, ev);
560
0
      }
561
0
    }
562
0
    break;
563
0
  }
564
565
0
  case SMB2_0_INFO_QUOTA: {
566
0
#ifdef HAVE_SYS_QUOTAS
567
0
    struct smb2_query_quota_info info;
568
0
    enum ndr_err_code err;
569
0
    uint8_t *data = NULL;
570
0
    uint32_t data_size = 0;
571
0
    struct ndr_pull *ndr_pull = NULL;
572
0
    DATA_BLOB sid_buf = data_blob_null;
573
0
    TALLOC_CTX *tmp_ctx = talloc_init("geninfo_quota");
574
0
    bool ok;
575
576
0
    if (!tmp_ctx) {
577
0
      tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
578
0
      return tevent_req_post(req, ev);
579
0
    }
580
581
0
    ok = check_fsp_ntquota_handle(conn, smbreq, fsp);
582
0
    if (!ok) {
583
0
      DBG_INFO("no valid QUOTA HANDLE\n");
584
0
      TALLOC_FREE(tmp_ctx);
585
0
      tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
586
0
      return tevent_req_post(req, ev);
587
0
    }
588
589
0
    ndr_pull = ndr_pull_init_blob(&in_input_buffer, tmp_ctx);
590
0
    if (!ndr_pull) {
591
0
      TALLOC_FREE(tmp_ctx);
592
0
      tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
593
0
      return tevent_req_post(req, ev);
594
0
    }
595
596
0
    err = ndr_pull_smb2_query_quota_info(ndr_pull,
597
0
                 NDR_SCALARS | NDR_BUFFERS,
598
0
                 &info);
599
600
0
    if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
601
0
      DBG_DEBUG("failed to pull smb2_query_quota_info\n");
602
0
      TALLOC_FREE(tmp_ctx);
603
0
      tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
604
0
      return tevent_req_post(req, ev);
605
0
    }
606
607
0
    DBG_DEBUG("quota list returnsingle %u, restartscan %u, "
608
0
        "sid_list_length %u, start_sid_length %u, "
609
0
        "startsidoffset %u\n",
610
0
        (unsigned int)info.return_single,
611
0
        (unsigned int)info.restart_scan,
612
0
        (unsigned int)info.sid_list_length,
613
0
        (unsigned int)info.start_sid_length,
614
0
        (unsigned int)info.start_sid_offset);
615
616
    /* Currently we do not support the single start sid format */
617
0
    if (info.start_sid_length != 0 || info.start_sid_offset != 0 ) {
618
0
      DBG_INFO("illegal single sid query\n");
619
0
      TALLOC_FREE(tmp_ctx);
620
0
      tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
621
0
      return tevent_req_post(req, ev);
622
0
    }
623
624
0
    if (in_input_buffer.length < ndr_pull->offset) {
625
0
      DBG_INFO("Invalid buffer length\n");
626
0
      TALLOC_FREE(tmp_ctx);
627
0
      tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
628
0
      return tevent_req_post(req, ev);
629
0
    }
630
631
0
    sid_buf.data = in_input_buffer.data + ndr_pull->offset;
632
0
    sid_buf.length = in_input_buffer.length - ndr_pull->offset;
633
634
0
    status = smbd_do_query_getinfo_quota(tmp_ctx,
635
0
          fsp,
636
0
          info.restart_scan,
637
0
          info.return_single,
638
0
          info.sid_list_length,
639
0
          &sid_buf,
640
0
          in_output_buffer_length,
641
0
          &data,
642
0
          &data_size);
643
644
0
    if (!NT_STATUS_IS_OK(status)) {
645
0
      TALLOC_FREE(tmp_ctx);
646
0
      tevent_req_nterror(req, status);
647
0
      return tevent_req_post(req, ev);
648
0
    }
649
650
0
    state->out_output_buffer =
651
0
      data_blob_talloc(state, data, data_size);
652
0
    status  = NT_STATUS_OK;
653
0
    TALLOC_FREE(tmp_ctx);
654
0
    break;
655
#else
656
    tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
657
    return tevent_req_post(req, ev);
658
#endif
659
0
  }
660
661
0
  default:
662
0
    DEBUG(10,("smbd_smb2_getinfo_send: "
663
0
      "unknown in_info_type of %u "
664
0
      " for file %s\n",
665
0
      (unsigned int)in_info_type,
666
0
      fsp_str_dbg(fsp) ));
667
668
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
669
0
    return tevent_req_post(req, ev);
670
0
  }
671
672
0
  state->status = status;
673
0
  tevent_req_done(req);
674
0
  return tevent_req_post(req, ev);
675
0
}
676
677
static NTSTATUS smbd_smb2_getinfo_recv(struct tevent_req *req,
678
               TALLOC_CTX *mem_ctx,
679
               DATA_BLOB *out_output_buffer,
680
               NTSTATUS *pstatus)
681
0
{
682
0
  NTSTATUS status;
683
0
  struct smbd_smb2_getinfo_state *state = tevent_req_data(req,
684
0
            struct smbd_smb2_getinfo_state);
685
686
0
  if (tevent_req_is_nterror(req, &status)) {
687
0
    tevent_req_received(req);
688
0
    return status;
689
0
  }
690
691
0
  *out_output_buffer = state->out_output_buffer;
692
0
  talloc_steal(mem_ctx, out_output_buffer->data);
693
0
  *pstatus = state->status;
694
695
0
  tevent_req_received(req);
696
0
  return NT_STATUS_OK;
697
0
}