Coverage Report

Created: 2026-09-03 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/libsmb/clisecdesc.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   client security descriptor functions
4
   Copyright (C) Andrew Tridgell 2000
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 "source3/include/client.h"
22
#include "source3/libsmb/proto.h"
23
#include "source3/libsmb/cli_smb2_fnum.h"
24
#include "../libcli/security/secdesc.h"
25
#include "../libcli/smb/smbXcli_base.h"
26
#include "lib/util/tevent_ntstatus.h"
27
28
struct cli_query_security_descriptor_state {
29
  uint8_t param[8];
30
  DATA_BLOB outbuf;
31
};
32
33
static void cli_query_security_descriptor_done1(struct tevent_req *subreq);
34
static void cli_query_security_descriptor_done2(struct tevent_req *subreq);
35
36
struct tevent_req *cli_query_security_descriptor_send(
37
  TALLOC_CTX *mem_ctx,
38
  struct tevent_context *ev,
39
  struct cli_state *cli,
40
  uint16_t fnum,
41
  uint32_t sec_info)
42
0
{
43
0
  struct tevent_req *req = NULL, *subreq = NULL;
44
0
  struct cli_query_security_descriptor_state *state = NULL;
45
46
0
  req = tevent_req_create(
47
0
    mem_ctx, &state, struct cli_query_security_descriptor_state);
48
0
  if (req == NULL) {
49
0
    return NULL;
50
0
  }
51
52
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
53
0
    subreq = cli_smb2_query_info_fnum_send(
54
0
      state,          /* mem_ctx */
55
0
      ev,         /* ev */
56
0
      cli,          /* cli */
57
0
      fnum,         /* fnum */
58
0
      SMB2_0_INFO_SECURITY, /* in_info_type */
59
0
      0,          /* in_info_class */
60
0
      0xFFFF,         /* in_max_output_length */
61
0
      NULL,         /* in_input_buffer */
62
0
      sec_info,       /* in_additional_info */
63
0
      0);         /* in_flags */
64
0
    if (tevent_req_nomem(subreq, req)) {
65
0
      return tevent_req_post(req, ev);
66
0
    }
67
0
    tevent_req_set_callback(
68
0
      subreq, cli_query_security_descriptor_done2, req);
69
0
    return req;
70
0
  }
71
72
0
  PUSH_LE_U16(state->param, 0, fnum);
73
  /* 2 bytes reserved, set to 0 by tevent_req_create */
74
0
  PUSH_LE_U32(state->param, 4, sec_info);
75
76
0
  subreq = cli_trans_send(
77
0
    state,    /* mem_ctx */
78
0
    ev,   /* ev */
79
0
    cli,    /* cli */
80
0
    0,    /* additional_flags2 */
81
0
    SMBnttrans, /* cmd */
82
0
    NULL,   /* pipe_name */
83
0
    -1,   /* fid */
84
0
    NT_TRANSACT_QUERY_SECURITY_DESC, /* function */
85
0
    0,    /* flags */
86
0
    NULL,   /* setup */
87
0
    0,    /* num_setup */
88
0
    0,    /* max_setup */
89
0
    state->param, /* param */
90
0
    8,    /* num_param */
91
0
    4,    /* max_param */
92
0
    NULL,   /* data */
93
0
    0,    /* num_data */
94
0
    0x10000); /* max_data */
95
0
  if (tevent_req_nomem(subreq, req)) {
96
0
    return tevent_req_post(req, ev);
97
0
  }
98
0
  tevent_req_set_callback(
99
0
    subreq, cli_query_security_descriptor_done1, req);
100
0
  return req;
101
0
}
102
103
static void cli_query_security_descriptor_done1(struct tevent_req *subreq)
104
0
{
105
0
  struct tevent_req *req = tevent_req_callback_data(
106
0
    subreq, struct tevent_req);
107
0
  struct cli_query_security_descriptor_state *state = tevent_req_data(
108
0
    req, struct cli_query_security_descriptor_state);
109
0
  NTSTATUS status;
110
0
  uint32_t len;
111
112
0
  status = cli_trans_recv(
113
0
    subreq,   /* req */
114
0
    state,    /* mem_ctx */
115
0
    NULL,   /* recv_flags2 */
116
0
    NULL,   /* setup */
117
0
    0,    /* min_setup */
118
0
    NULL,   /* num_setup */
119
0
    NULL,   /* param */
120
0
    0,    /* min_param */
121
0
    NULL,   /* num_param */
122
0
    &state->outbuf.data, /* data */
123
0
    0,    /* min_data */
124
0
    &len);    /* num_data */
125
0
  TALLOC_FREE(subreq);
126
0
  if (tevent_req_nterror(req, status)) {
127
0
    return;
128
0
  }
129
0
  state->outbuf.length = len; /* uint32_t -> size_t */
130
0
  tevent_req_done(req);
131
0
}
132
133
static void cli_query_security_descriptor_done2(struct tevent_req *subreq)
134
0
{
135
0
  struct tevent_req *req = tevent_req_callback_data(
136
0
    subreq, struct tevent_req);
137
0
  struct cli_query_security_descriptor_state *state = tevent_req_data(
138
0
    req, struct cli_query_security_descriptor_state);
139
0
  NTSTATUS status;
140
141
0
  status = cli_smb2_query_info_fnum_recv(subreq, state, &state->outbuf);
142
0
  TALLOC_FREE(subreq);
143
0
  if (tevent_req_nterror(req, status)) {
144
0
    return;
145
0
  }
146
0
  tevent_req_done(req);
147
0
}
148
149
NTSTATUS cli_query_security_descriptor_recv(
150
  struct tevent_req *req,
151
  TALLOC_CTX *mem_ctx,
152
  struct security_descriptor **sd)
153
0
{
154
0
  struct cli_query_security_descriptor_state *state = tevent_req_data(
155
0
    req, struct cli_query_security_descriptor_state);
156
0
  NTSTATUS status = NT_STATUS_OK;
157
158
0
  if (tevent_req_is_nterror(req, &status)) {
159
0
    goto done;
160
0
  }
161
0
  if (sd != NULL) {
162
0
    status = unmarshall_sec_desc(
163
0
      mem_ctx, state->outbuf.data, state->outbuf.length, sd);
164
0
  }
165
0
done:
166
0
  tevent_req_received(req);
167
0
  return status;
168
0
}
169
170
NTSTATUS cli_query_security_descriptor(struct cli_state *cli,
171
               uint16_t fnum,
172
               uint32_t sec_info,
173
               TALLOC_CTX *mem_ctx,
174
               struct security_descriptor **sd)
175
0
{
176
0
  TALLOC_CTX *frame = talloc_stackframe();
177
0
  struct tevent_context *ev = NULL;
178
0
  struct tevent_req *req = NULL;
179
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
180
181
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
182
0
    status = NT_STATUS_INVALID_PARAMETER;
183
0
    goto fail;
184
0
  }
185
0
  ev = samba_tevent_context_init(frame);
186
0
  if (ev == NULL) {
187
0
    goto fail;
188
0
  }
189
0
  req = cli_query_security_descriptor_send(
190
0
    frame, ev, cli, fnum, sec_info);
191
0
  if (req == NULL) {
192
0
    goto fail;
193
0
  }
194
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
195
0
    goto fail;
196
0
  }
197
0
  status = cli_query_security_descriptor_recv(req, mem_ctx, sd);
198
0
 fail:
199
0
  TALLOC_FREE(frame);
200
0
  return status;
201
0
}
202
203
NTSTATUS cli_query_secdesc(struct cli_state *cli, uint16_t fnum,
204
         TALLOC_CTX *mem_ctx, struct security_descriptor **sd)
205
0
{
206
0
  uint32_t sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL;
207
208
0
  return cli_query_security_descriptor(cli, fnum, sec_info, mem_ctx, sd);
209
0
}
210
211
NTSTATUS cli_query_mxac(struct cli_state *cli,
212
      const char *filename,
213
      uint32_t *mxac)
214
0
{
215
0
  if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
216
0
    return NT_STATUS_NOT_SUPPORTED;
217
0
  }
218
219
0
  return cli_smb2_query_mxac(cli, filename, mxac);
220
0
}
221
222
struct cli_set_security_descriptor_state {
223
  uint8_t param[8];
224
  DATA_BLOB buf;
225
};
226
227
static void cli_set_security_descriptor_done1(struct tevent_req *subreq);
228
static void cli_set_security_descriptor_done2(struct tevent_req *subreq);
229
230
struct tevent_req *cli_set_security_descriptor_send(
231
  TALLOC_CTX *mem_ctx,
232
  struct tevent_context *ev,
233
  struct cli_state *cli,
234
  uint16_t fnum,
235
  uint32_t sec_info,
236
  const struct security_descriptor *sd)
237
0
{
238
0
  struct tevent_req *req = NULL, *subreq = NULL;
239
0
  struct cli_set_security_descriptor_state *state = NULL;
240
0
  NTSTATUS status;
241
242
0
  req = tevent_req_create(
243
0
    mem_ctx, &state, struct cli_set_security_descriptor_state);
244
0
  if (req == NULL) {
245
0
    return NULL;
246
0
  }
247
248
0
  status = marshall_sec_desc(
249
0
    state, sd, &state->buf.data, &state->buf.length);
250
0
  if (tevent_req_nterror(req, status)) {
251
0
    return tevent_req_post(req, ev);
252
0
  }
253
254
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
255
0
    subreq = cli_smb2_set_info_fnum_send(
256
0
      state,          /* mem_ctx */
257
0
      ev,         /* ev */
258
0
      cli,          /* cli */
259
0
      fnum,         /* fnum */
260
0
      SMB2_0_INFO_SECURITY, /* in_info_type */
261
0
      0,          /* in_file_info_class */
262
0
      &state->buf,        /* in_input_buffer */
263
0
      sec_info);        /* in_additional_info */
264
0
    if (tevent_req_nomem(subreq, req)) {
265
0
      return tevent_req_post(req, ev);
266
0
    }
267
0
    tevent_req_set_callback(
268
0
      subreq, cli_set_security_descriptor_done2, req);
269
0
    return req;
270
0
  }
271
272
0
  PUSH_LE_U16(state->param, 0, fnum);
273
  /* 2 bytes reserved, set to 0 by tevent_req_create */
274
0
  PUSH_LE_U32(state->param, 4, sec_info);
275
276
0
  subreq = cli_trans_send(
277
0
    state,    /* mem_ctx */
278
0
    ev,   /* ev */
279
0
    cli,    /* cli */
280
0
    0,    /* additional_flags2 */
281
0
    SMBnttrans, /* cmd */
282
0
    NULL,   /* pipe_name */
283
0
    -1,   /* fid */
284
0
    NT_TRANSACT_SET_SECURITY_DESC, /* function */
285
0
    0,    /* flags */
286
0
    NULL,   /* setup */
287
0
    0,    /* num_setup */
288
0
    0,    /* max_setup */
289
0
    state->param, /* param */
290
0
    8,    /* num_param */
291
0
    0,    /* max_param */
292
0
    state->buf.data, /* data */
293
0
    state->buf.length, /* num_data */
294
0
    0);   /* max_data */
295
0
  if (tevent_req_nomem(subreq, req)) {
296
0
    return tevent_req_post(req, ev);
297
0
  }
298
0
  tevent_req_set_callback(
299
0
    subreq, cli_set_security_descriptor_done1, req);
300
0
  return req;
301
0
}
302
303
static void cli_set_security_descriptor_done1(struct tevent_req *subreq)
304
0
{
305
0
  NTSTATUS status = cli_trans_recv(
306
0
    subreq, NULL, NULL, NULL, 0, NULL, NULL, 0, NULL,
307
0
    NULL, 0, NULL);
308
0
  return tevent_req_simple_finish_ntstatus(subreq, status);
309
0
}
310
311
static void cli_set_security_descriptor_done2(struct tevent_req *subreq)
312
0
{
313
0
  NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
314
0
  tevent_req_simple_finish_ntstatus(subreq, status);
315
0
}
316
317
NTSTATUS cli_set_security_descriptor_recv(struct tevent_req *req)
318
0
{
319
0
  return tevent_req_simple_recv_ntstatus(req);
320
0
}
321
322
/****************************************************************************
323
  set the security descriptor for a open file
324
 ****************************************************************************/
325
NTSTATUS cli_set_security_descriptor(struct cli_state *cli,
326
             uint16_t fnum,
327
             uint32_t sec_info,
328
             const struct security_descriptor *sd)
329
0
{
330
0
  TALLOC_CTX *frame = talloc_stackframe();
331
0
  struct tevent_context *ev = NULL;
332
0
  struct tevent_req *req = NULL;
333
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
334
335
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
336
0
    status = NT_STATUS_INVALID_PARAMETER;
337
0
    goto fail;
338
0
  }
339
0
  ev = samba_tevent_context_init(frame);
340
0
  if (ev == NULL) {
341
0
    goto fail;
342
0
  }
343
0
  req = cli_set_security_descriptor_send(
344
0
    frame, ev, cli, fnum, sec_info, sd);
345
0
  if (req == NULL) {
346
0
    goto fail;
347
0
  }
348
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
349
0
    goto fail;
350
0
  }
351
0
  status = cli_set_security_descriptor_recv(req);
352
0
 fail:
353
0
  TALLOC_FREE(frame);
354
0
  return status;
355
0
}
356
357
NTSTATUS cli_set_secdesc(struct cli_state *cli, uint16_t fnum,
358
       const struct security_descriptor *sd)
359
0
{
360
0
  uint32_t sec_info = 0;
361
362
0
  if (sd->dacl || (sd->type & SEC_DESC_DACL_PRESENT)) {
363
0
    sec_info |= SECINFO_DACL;
364
0
  }
365
0
  if (sd->sacl || (sd->type & SEC_DESC_SACL_PRESENT)) {
366
0
    sec_info |= SECINFO_SACL;
367
0
  }
368
0
  if (sd->owner_sid) {
369
0
    sec_info |= SECINFO_OWNER;
370
0
  }
371
0
  if (sd->group_sid) {
372
0
    sec_info |= SECINFO_GROUP;
373
0
  }
374
375
0
  return cli_set_security_descriptor(cli, fnum, sec_info, sd);
376
0
}