CVE-2023-4091: smbd: use open_access_mask for access check in open_file()
[Samba.git] / source3 / lib / util_sd.c
blob23f37b7e7347315a2066ab39816ae23891a8cec0
1 /*
2 Unix SMB/CIFS implementation.
3 Security Descriptor (SD) helper functions
5 Copyright (C) Andrew Tridgell 2000
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Jeremy Allison 2000
8 Copyright (C) Jelmer Vernooij 2003
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "libsmb/libsmb.h"
26 #include "util_sd.h"
27 #include "librpc/gen_ndr/ndr_lsa.h"
28 #include "../libcli/security/security.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "rpc_client/cli_lsarpc.h"
31 #include "lib/util/string_wrappers.h"
33 /* These values discovered by inspection */
35 struct perm_value {
36 const char *perm;
37 uint32_t mask;
40 static const struct perm_value special_values[] = {
41 { "R", SEC_RIGHTS_FILE_READ },
42 { "W", SEC_RIGHTS_FILE_WRITE },
43 { "X", SEC_RIGHTS_FILE_EXECUTE },
44 { "D", SEC_STD_DELETE },
45 { "P", SEC_STD_WRITE_DAC },
46 { "O", SEC_STD_WRITE_OWNER },
47 { NULL, 0 },
50 static const struct perm_value standard_values[] = {
51 { "READ", SEC_RIGHTS_DIR_READ|SEC_DIR_TRAVERSE },
52 { "CHANGE", SEC_RIGHTS_DIR_READ|SEC_STD_DELETE|\
53 SEC_DIR_DELETE_CHILD|\
54 SEC_RIGHTS_DIR_WRITE|SEC_DIR_TRAVERSE },
55 { "FULL", SEC_RIGHTS_DIR_ALL },
56 { NULL, 0 },
59 static const struct {
60 uint16_t mask;
61 const char *str;
62 const char *desc;
63 } sec_desc_ctrl_bits[] = {
64 {SEC_DESC_OWNER_DEFAULTED, "OD", "Owner Defaulted"},
65 {SEC_DESC_GROUP_DEFAULTED, "GD", "Group Defaulted"},
66 {SEC_DESC_DACL_PRESENT, "DP", "DACL Present"},
67 {SEC_DESC_DACL_DEFAULTED, "DD", "DACL Defaulted"},
68 {SEC_DESC_SACL_PRESENT, "SP", "SACL Present"},
69 {SEC_DESC_SACL_DEFAULTED, "SD", "SACL Defaulted"},
70 {SEC_DESC_DACL_TRUSTED, "DT", "DACL Trusted"},
71 {SEC_DESC_SERVER_SECURITY, "SS", "Server Security"},
72 {SEC_DESC_DACL_AUTO_INHERIT_REQ, "DR", "DACL Inheritance Required"},
73 {SEC_DESC_SACL_AUTO_INHERIT_REQ, "SR", "SACL Inheritance Required"},
74 {SEC_DESC_DACL_AUTO_INHERITED, "DI", "DACL Auto Inherited"},
75 {SEC_DESC_SACL_AUTO_INHERITED, "SI", "SACL Auto Inherited"},
76 {SEC_DESC_DACL_PROTECTED, "PD", "DACL Protected"},
77 {SEC_DESC_SACL_PROTECTED, "PS", "SACL Protected"},
78 {SEC_DESC_RM_CONTROL_VALID, "RM", "RM Control Valid"},
79 {SEC_DESC_SELF_RELATIVE , "SR", "Self Relative"},
82 /* Open cli connection and policy handle */
83 static NTSTATUS cli_lsa_lookup_sid(struct cli_state *cli,
84 const struct dom_sid *sid,
85 TALLOC_CTX *mem_ctx,
86 enum lsa_SidType *type,
87 char **domain, char **name)
89 struct smbXcli_tcon *orig_tcon = NULL;
90 char *orig_share = NULL;
91 struct rpc_pipe_client *p = NULL;
92 struct policy_handle handle;
93 NTSTATUS status;
94 TALLOC_CTX *frame = talloc_stackframe();
95 enum lsa_SidType *types;
96 char **domains;
97 char **names;
99 if (cli_state_has_tcon(cli)) {
100 cli_state_save_tcon_share(cli, &orig_tcon, &orig_share);
103 status = cli_tree_connect(cli, "IPC$", "?????", NULL);
104 if (!NT_STATUS_IS_OK(status)) {
105 goto tcon_fail;
108 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
109 &p);
110 if (!NT_STATUS_IS_OK(status)) {
111 goto fail;
114 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
115 GENERIC_EXECUTE_ACCESS, &handle);
116 if (!NT_STATUS_IS_OK(status)) {
117 goto fail;
120 status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
121 &domains, &names, &types);
122 if (!NT_STATUS_IS_OK(status)) {
123 goto fail;
126 *type = types[0];
127 *domain = talloc_move(mem_ctx, &domains[0]);
128 *name = talloc_move(mem_ctx, &names[0]);
130 status = NT_STATUS_OK;
131 fail:
132 TALLOC_FREE(p);
133 cli_tdis(cli);
134 tcon_fail:
135 cli_state_restore_tcon_share(cli, orig_tcon, orig_share);
136 TALLOC_FREE(frame);
137 return status;
140 /* convert a SID to a string, either numeric or username/group */
141 void SidToString(struct cli_state *cli, fstring str, const struct dom_sid *sid,
142 bool numeric)
144 char *domain = NULL;
145 char *name = NULL;
146 enum lsa_SidType type;
147 NTSTATUS status;
149 sid_to_fstring(str, sid);
151 if (numeric || cli == NULL) {
152 return;
155 status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
156 &domain, &name);
158 if (!NT_STATUS_IS_OK(status)) {
159 return;
162 if (*domain) {
163 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
164 domain, lp_winbind_separator(), name);
165 } else {
166 fstrcpy(str, name);
170 static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
171 const char *name,
172 enum lsa_SidType *type,
173 struct dom_sid *sid)
175 struct smbXcli_tcon *orig_tcon = NULL;
176 char *orig_share = NULL;
177 struct rpc_pipe_client *p = NULL;
178 struct policy_handle handle;
179 NTSTATUS status;
180 TALLOC_CTX *frame = talloc_stackframe();
181 struct dom_sid *sids;
182 enum lsa_SidType *types;
184 if (cli_state_has_tcon(cli)) {
185 cli_state_save_tcon_share(cli, &orig_tcon, &orig_share);
188 status = cli_tree_connect(cli, "IPC$", "?????", NULL);
189 if (!NT_STATUS_IS_OK(status)) {
190 goto tcon_fail;
193 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
194 &p);
195 if (!NT_STATUS_IS_OK(status)) {
196 goto fail;
199 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
200 GENERIC_EXECUTE_ACCESS, &handle);
201 if (!NT_STATUS_IS_OK(status)) {
202 goto fail;
205 status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
206 NULL, 1, &sids, &types);
207 if (!NT_STATUS_IS_OK(status)) {
208 goto fail;
211 *type = types[0];
212 *sid = sids[0];
214 status = NT_STATUS_OK;
215 fail:
216 TALLOC_FREE(p);
217 cli_tdis(cli);
218 tcon_fail:
219 cli_state_restore_tcon_share(cli, orig_tcon, orig_share);
220 TALLOC_FREE(frame);
221 return status;
224 /* convert a string to a SID, either numeric or username/group */
225 bool StringToSid(struct cli_state *cli, struct dom_sid *sid, const char *str)
227 enum lsa_SidType type;
229 if (string_to_sid(sid, str)) {
230 return true;
233 if (cli == NULL) {
234 return false;
237 return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli, str, &type, sid));
240 static void print_ace_flags(FILE *f, uint8_t flags)
242 char *str = talloc_strdup(NULL, "");
243 size_t len;
245 if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
246 talloc_asprintf_addbuf(&str, "OI|");
248 if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
249 talloc_asprintf_addbuf(&str, "CI|");
251 if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
252 talloc_asprintf_addbuf(&str, "NP|");
254 if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
255 talloc_asprintf_addbuf(&str, "IO|");
257 if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
258 talloc_asprintf_addbuf(&str, "I|");
260 if (str == NULL) {
261 goto out;
264 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
265 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
266 audit ace flags. */
268 len = strlen(str);
269 if (len > 0) {
270 fprintf(f, "/%.*s/", (int)len-1, str);
271 } else {
272 fprintf(f, "/0x%x/", flags);
274 TALLOC_FREE(str);
275 return;
277 out:
278 fprintf(f, "/0x%x/", flags);
281 /* print an ACE on a FILE, using either numeric or ascii representation */
282 void print_ace(struct cli_state *cli, FILE *f, struct security_ace *ace,
283 bool numeric)
285 const struct perm_value *v;
286 fstring sidstr;
287 int do_print = 0;
288 uint32_t got_mask;
290 SidToString(cli, sidstr, &ace->trustee, numeric);
292 fprintf(f, "%s:", sidstr);
294 if (numeric) {
295 fprintf(f, "%d/0x%x/0x%08x",
296 ace->type, ace->flags, ace->access_mask);
297 return;
300 /* Ace type */
302 if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
303 fprintf(f, "ALLOWED");
304 } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
305 fprintf(f, "DENIED");
306 } else {
307 fprintf(f, "%d", ace->type);
310 print_ace_flags(f, ace->flags);
312 /* Standard permissions */
314 for (v = standard_values; v->perm; v++) {
315 if (ace->access_mask == v->mask) {
316 fprintf(f, "%s", v->perm);
317 return;
321 /* Special permissions. Print out a hex value if we have
322 leftover bits in the mask. */
324 got_mask = ace->access_mask;
326 again:
327 for (v = special_values; v->perm; v++) {
328 if ((ace->access_mask & v->mask) == v->mask) {
329 if (do_print) {
330 fprintf(f, "%s", v->perm);
332 got_mask &= ~v->mask;
336 if (!do_print) {
337 if (got_mask != 0) {
338 fprintf(f, "0x%08x", ace->access_mask);
339 } else {
340 do_print = 1;
341 goto again;
346 static bool parse_ace_flags(const char *str, unsigned int *pflags)
348 const char *p = str;
349 *pflags = 0;
351 while (*p) {
352 if (strnequal(p, "OI", 2)) {
353 *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT;
354 p += 2;
355 } else if (strnequal(p, "CI", 2)) {
356 *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
357 p += 2;
358 } else if (strnequal(p, "NP", 2)) {
359 *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
360 p += 2;
361 } else if (strnequal(p, "IO", 2)) {
362 *pflags |= SEC_ACE_FLAG_INHERIT_ONLY;
363 p += 2;
364 } else if (*p == 'I') {
365 *pflags |= SEC_ACE_FLAG_INHERITED_ACE;
366 p += 1;
367 } else if (*p) {
368 return false;
371 switch (*p) {
372 case '|':
373 p++;
375 FALL_THROUGH;
376 case '\0':
377 continue;
378 default:
379 return false;
382 return true;
385 /* parse an ACE in the same format as print_ace() */
386 bool parse_ace(struct cli_state *cli, struct security_ace *ace,
387 const char *orig_str)
389 char *p;
390 const char *cp;
391 char *tok;
392 unsigned int atype = 0;
393 unsigned int aflags = 0;
394 unsigned int amask = 0;
395 struct dom_sid sid;
396 uint32_t mask;
397 const struct perm_value *v;
398 char *str = SMB_STRDUP(orig_str);
399 TALLOC_CTX *frame = talloc_stackframe();
401 if (!str) {
402 TALLOC_FREE(frame);
403 return False;
406 ZERO_STRUCTP(ace);
407 p = strchr_m(str,':');
408 if (!p) {
409 printf("ACE '%s': missing ':'.\n", orig_str);
410 SAFE_FREE(str);
411 TALLOC_FREE(frame);
412 return False;
414 *p = '\0';
415 p++;
417 if (!StringToSid(cli, &sid, str)) {
418 printf("ACE '%s': failed to convert '%s' to SID\n",
419 orig_str, str);
420 SAFE_FREE(str);
421 TALLOC_FREE(frame);
422 return False;
425 cp = p;
426 if (!next_token_talloc(frame, &cp, &tok, "/")) {
427 printf("ACE '%s': failed to find '/' character.\n",
428 orig_str);
429 SAFE_FREE(str);
430 TALLOC_FREE(frame);
431 return False;
434 if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
435 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
436 } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
437 atype = SEC_ACE_TYPE_ACCESS_DENIED;
439 } else if (strnequal(tok, "0x", 2)) {
440 int result;
442 result = sscanf(tok, "%x", &atype);
443 if (result == 0 ||
444 (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
445 atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
446 printf("ACE '%s': bad hex value for type at '%s'\n",
447 orig_str, tok);
448 SAFE_FREE(str);
449 TALLOC_FREE(frame);
450 return false;
452 } else if(tok[0] >= '0' && tok[0] <= '9') {
453 int result;
455 result = sscanf(tok, "%u", &atype);
456 if (result == 0 ||
457 (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
458 atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
459 printf("ACE '%s': bad integer value for type at '%s'\n",
460 orig_str, tok);
461 SAFE_FREE(str);
462 TALLOC_FREE(frame);
463 return false;
465 } else {
466 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
467 orig_str, tok);
468 SAFE_FREE(str);
469 TALLOC_FREE(frame);
470 return False;
473 if (!next_token_talloc(frame, &cp, &tok, "/")) {
474 printf("ACE '%s': bad flags entry at '%s'\n",
475 orig_str, tok);
476 SAFE_FREE(str);
477 TALLOC_FREE(frame);
478 return False;
481 if (tok[0] < '0' || tok[0] > '9') {
482 if (!parse_ace_flags(tok, &aflags)) {
483 printf("ACE '%s': bad named flags entry at '%s'\n",
484 orig_str, tok);
485 SAFE_FREE(str);
486 TALLOC_FREE(frame);
487 return False;
489 } else if (strnequal(tok, "0x", 2)) {
490 if (!sscanf(tok, "%x", &aflags)) {
491 printf("ACE '%s': bad hex flags entry at '%s'\n",
492 orig_str, tok);
493 SAFE_FREE(str);
494 TALLOC_FREE(frame);
495 return False;
497 } else {
498 if (!sscanf(tok, "%u", &aflags)) {
499 printf("ACE '%s': bad integer flags entry at '%s'\n",
500 orig_str, tok);
501 SAFE_FREE(str);
502 TALLOC_FREE(frame);
503 return False;
507 if (!next_token_talloc(frame, &cp, &tok, "/")) {
508 printf("ACE '%s': missing / at '%s'\n",
509 orig_str, tok);
510 SAFE_FREE(str);
511 TALLOC_FREE(frame);
512 return False;
515 if (strncmp(tok, "0x", 2) == 0) {
516 if (sscanf(tok, "%x", &amask) != 1) {
517 printf("ACE '%s': bad hex number at '%s'\n",
518 orig_str, tok);
519 SAFE_FREE(str);
520 TALLOC_FREE(frame);
521 return False;
523 goto done;
526 for (v = standard_values; v->perm; v++) {
527 if (strcmp(tok, v->perm) == 0) {
528 amask = v->mask;
529 goto done;
533 p = tok;
535 while(*p) {
536 bool found = False;
538 for (v = special_values; v->perm; v++) {
539 if (v->perm[0] == *p) {
540 amask |= v->mask;
541 found = True;
545 if (!found) {
546 printf("ACE '%s': bad permission value at '%s'\n",
547 orig_str, p);
548 SAFE_FREE(str);
549 TALLOC_FREE(frame);
550 return False;
552 p++;
555 if (*p) {
556 TALLOC_FREE(frame);
557 SAFE_FREE(str);
558 return False;
561 done:
562 mask = amask;
563 init_sec_ace(ace, &sid, atype, mask, aflags);
564 TALLOC_FREE(frame);
565 SAFE_FREE(str);
566 return True;
569 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
571 int i;
572 const char* separator = "";
574 fprintf(file, "CONTROL:");
575 if (numeric) {
576 fprintf(file, "0x%x\n", ctrl);
577 return;
580 for (i = ARRAY_SIZE(sec_desc_ctrl_bits) - 1; i >= 0; i--) {
581 if (ctrl & sec_desc_ctrl_bits[i].mask) {
582 fprintf(file, "%s%s",
583 separator, sec_desc_ctrl_bits[i].str);
584 separator = "|";
587 fputc('\n', file);
590 /* print a ascii version of a security descriptor on a FILE handle */
591 void sec_desc_print(struct cli_state *cli, FILE *f,
592 struct security_descriptor *sd, bool numeric)
594 fstring sidstr;
595 uint32_t i;
597 fprintf(f, "REVISION:%d\n", sd->revision);
598 print_acl_ctrl(f, sd->type, numeric);
600 /* Print owner and group sid */
602 if (sd->owner_sid) {
603 SidToString(cli, sidstr, sd->owner_sid, numeric);
604 } else {
605 fstrcpy(sidstr, "");
608 fprintf(f, "OWNER:%s\n", sidstr);
610 if (sd->group_sid) {
611 SidToString(cli, sidstr, sd->group_sid, numeric);
612 } else {
613 fstrcpy(sidstr, "");
616 fprintf(f, "GROUP:%s\n", sidstr);
618 /* Print aces */
619 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
620 struct security_ace *ace = &sd->dacl->aces[i];
621 fprintf(f, "ACL:");
622 print_ace(cli, f, ace, numeric);
623 fprintf(f, "\n");