s3: smbd: Make extract_snapshot_token() a wrapper for extract_snapshot_token_internal().
[Samba.git] / source3 / lib / util_sd.c
bloba4288a46f3d982f0f55ac99f9442ce3314cca21a
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, "");
244 if (!str) {
245 goto out;
248 if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
249 str = talloc_asprintf(str, "%s%s",
250 str, "OI|");
251 if (!str) {
252 goto out;
255 if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
256 str = talloc_asprintf(str, "%s%s",
257 str, "CI|");
258 if (!str) {
259 goto out;
262 if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
263 str = talloc_asprintf(str, "%s%s",
264 str, "NP|");
265 if (!str) {
266 goto out;
269 if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
270 str = talloc_asprintf(str, "%s%s",
271 str, "IO|");
272 if (!str) {
273 goto out;
276 if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
277 str = talloc_asprintf(str, "%s%s",
278 str, "I|");
279 if (!str) {
280 goto out;
283 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
284 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
285 audit ace flags. */
287 if (str[strlen(str)-1] == '|') {
288 str[strlen(str)-1] = '\0';
289 fprintf(f, "/%s/", str);
290 } else {
291 fprintf(f, "/0x%x/", flags);
293 TALLOC_FREE(str);
294 return;
296 out:
297 fprintf(f, "/0x%x/", flags);
300 /* print an ACE on a FILE, using either numeric or ascii representation */
301 void print_ace(struct cli_state *cli, FILE *f, struct security_ace *ace,
302 bool numeric)
304 const struct perm_value *v;
305 fstring sidstr;
306 int do_print = 0;
307 uint32_t got_mask;
309 SidToString(cli, sidstr, &ace->trustee, numeric);
311 fprintf(f, "%s:", sidstr);
313 if (numeric) {
314 fprintf(f, "%d/0x%x/0x%08x",
315 ace->type, ace->flags, ace->access_mask);
316 return;
319 /* Ace type */
321 if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
322 fprintf(f, "ALLOWED");
323 } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
324 fprintf(f, "DENIED");
325 } else {
326 fprintf(f, "%d", ace->type);
329 print_ace_flags(f, ace->flags);
331 /* Standard permissions */
333 for (v = standard_values; v->perm; v++) {
334 if (ace->access_mask == v->mask) {
335 fprintf(f, "%s", v->perm);
336 return;
340 /* Special permissions. Print out a hex value if we have
341 leftover bits in the mask. */
343 got_mask = ace->access_mask;
345 again:
346 for (v = special_values; v->perm; v++) {
347 if ((ace->access_mask & v->mask) == v->mask) {
348 if (do_print) {
349 fprintf(f, "%s", v->perm);
351 got_mask &= ~v->mask;
355 if (!do_print) {
356 if (got_mask != 0) {
357 fprintf(f, "0x%08x", ace->access_mask);
358 } else {
359 do_print = 1;
360 goto again;
365 static bool parse_ace_flags(const char *str, unsigned int *pflags)
367 const char *p = str;
368 *pflags = 0;
370 while (*p) {
371 if (strnequal(p, "OI", 2)) {
372 *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT;
373 p += 2;
374 } else if (strnequal(p, "CI", 2)) {
375 *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
376 p += 2;
377 } else if (strnequal(p, "NP", 2)) {
378 *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
379 p += 2;
380 } else if (strnequal(p, "IO", 2)) {
381 *pflags |= SEC_ACE_FLAG_INHERIT_ONLY;
382 p += 2;
383 } else if (*p == 'I') {
384 *pflags |= SEC_ACE_FLAG_INHERITED_ACE;
385 p += 1;
386 } else if (*p) {
387 return false;
390 switch (*p) {
391 case '|':
392 p++;
394 FALL_THROUGH;
395 case '\0':
396 continue;
397 default:
398 return false;
401 return true;
404 /* parse an ACE in the same format as print_ace() */
405 bool parse_ace(struct cli_state *cli, struct security_ace *ace,
406 const char *orig_str)
408 char *p;
409 const char *cp;
410 char *tok;
411 unsigned int atype = 0;
412 unsigned int aflags = 0;
413 unsigned int amask = 0;
414 struct dom_sid sid;
415 uint32_t mask;
416 const struct perm_value *v;
417 char *str = SMB_STRDUP(orig_str);
418 TALLOC_CTX *frame = talloc_stackframe();
420 if (!str) {
421 TALLOC_FREE(frame);
422 return False;
425 ZERO_STRUCTP(ace);
426 p = strchr_m(str,':');
427 if (!p) {
428 printf("ACE '%s': missing ':'.\n", orig_str);
429 SAFE_FREE(str);
430 TALLOC_FREE(frame);
431 return False;
433 *p = '\0';
434 p++;
436 if (!StringToSid(cli, &sid, str)) {
437 printf("ACE '%s': failed to convert '%s' to SID\n",
438 orig_str, str);
439 SAFE_FREE(str);
440 TALLOC_FREE(frame);
441 return False;
444 cp = p;
445 if (!next_token_talloc(frame, &cp, &tok, "/")) {
446 printf("ACE '%s': failed to find '/' character.\n",
447 orig_str);
448 SAFE_FREE(str);
449 TALLOC_FREE(frame);
450 return False;
453 if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
454 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
455 } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
456 atype = SEC_ACE_TYPE_ACCESS_DENIED;
458 } else if (strnequal(tok, "0x", 2)) {
459 int result;
461 result = sscanf(tok, "%x", &atype);
462 if (result == 0 ||
463 (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
464 atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
465 printf("ACE '%s': bad hex value for type at '%s'\n",
466 orig_str, tok);
467 SAFE_FREE(str);
468 TALLOC_FREE(frame);
469 return false;
471 } else if(tok[0] >= '0' && tok[0] <= '9') {
472 int result;
474 result = sscanf(tok, "%u", &atype);
475 if (result == 0 ||
476 (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
477 atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
478 printf("ACE '%s': bad integer value for type at '%s'\n",
479 orig_str, tok);
480 SAFE_FREE(str);
481 TALLOC_FREE(frame);
482 return false;
484 } else {
485 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
486 orig_str, tok);
487 SAFE_FREE(str);
488 TALLOC_FREE(frame);
489 return False;
492 if (!next_token_talloc(frame, &cp, &tok, "/")) {
493 printf("ACE '%s': bad flags entry at '%s'\n",
494 orig_str, tok);
495 SAFE_FREE(str);
496 TALLOC_FREE(frame);
497 return False;
500 if (tok[0] < '0' || tok[0] > '9') {
501 if (!parse_ace_flags(tok, &aflags)) {
502 printf("ACE '%s': bad named flags entry at '%s'\n",
503 orig_str, tok);
504 SAFE_FREE(str);
505 TALLOC_FREE(frame);
506 return False;
508 } else if (strnequal(tok, "0x", 2)) {
509 if (!sscanf(tok, "%x", &aflags)) {
510 printf("ACE '%s': bad hex flags entry at '%s'\n",
511 orig_str, tok);
512 SAFE_FREE(str);
513 TALLOC_FREE(frame);
514 return False;
516 } else {
517 if (!sscanf(tok, "%u", &aflags)) {
518 printf("ACE '%s': bad integer flags entry at '%s'\n",
519 orig_str, tok);
520 SAFE_FREE(str);
521 TALLOC_FREE(frame);
522 return False;
526 if (!next_token_talloc(frame, &cp, &tok, "/")) {
527 printf("ACE '%s': missing / at '%s'\n",
528 orig_str, tok);
529 SAFE_FREE(str);
530 TALLOC_FREE(frame);
531 return False;
534 if (strncmp(tok, "0x", 2) == 0) {
535 if (sscanf(tok, "%x", &amask) != 1) {
536 printf("ACE '%s': bad hex number at '%s'\n",
537 orig_str, tok);
538 SAFE_FREE(str);
539 TALLOC_FREE(frame);
540 return False;
542 goto done;
545 for (v = standard_values; v->perm; v++) {
546 if (strcmp(tok, v->perm) == 0) {
547 amask = v->mask;
548 goto done;
552 p = tok;
554 while(*p) {
555 bool found = False;
557 for (v = special_values; v->perm; v++) {
558 if (v->perm[0] == *p) {
559 amask |= v->mask;
560 found = True;
564 if (!found) {
565 printf("ACE '%s': bad permission value at '%s'\n",
566 orig_str, p);
567 SAFE_FREE(str);
568 TALLOC_FREE(frame);
569 return False;
571 p++;
574 if (*p) {
575 TALLOC_FREE(frame);
576 SAFE_FREE(str);
577 return False;
580 done:
581 mask = amask;
582 init_sec_ace(ace, &sid, atype, mask, aflags);
583 TALLOC_FREE(frame);
584 SAFE_FREE(str);
585 return True;
588 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
590 int i;
591 const char* separator = "";
593 fprintf(file, "CONTROL:");
594 if (numeric) {
595 fprintf(file, "0x%x\n", ctrl);
596 return;
599 for (i = ARRAY_SIZE(sec_desc_ctrl_bits) - 1; i >= 0; i--) {
600 if (ctrl & sec_desc_ctrl_bits[i].mask) {
601 fprintf(file, "%s%s",
602 separator, sec_desc_ctrl_bits[i].str);
603 separator = "|";
606 fputc('\n', file);
609 /* print a ascii version of a security descriptor on a FILE handle */
610 void sec_desc_print(struct cli_state *cli, FILE *f,
611 struct security_descriptor *sd, bool numeric)
613 fstring sidstr;
614 uint32_t i;
616 fprintf(f, "REVISION:%d\n", sd->revision);
617 print_acl_ctrl(f, sd->type, numeric);
619 /* Print owner and group sid */
621 if (sd->owner_sid) {
622 SidToString(cli, sidstr, sd->owner_sid, numeric);
623 } else {
624 fstrcpy(sidstr, "");
627 fprintf(f, "OWNER:%s\n", sidstr);
629 if (sd->group_sid) {
630 SidToString(cli, sidstr, sd->group_sid, numeric);
631 } else {
632 fstrcpy(sidstr, "");
635 fprintf(f, "GROUP:%s\n", sidstr);
637 /* Print aces */
638 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
639 struct security_ace *ace = &sd->dacl->aces[i];
640 fprintf(f, "ACL:");
641 print_ace(cli, f, ace, numeric);
642 fprintf(f, "\n");