pthreadpool: Use detached threads
[Samba.git] / source3 / lib / util_sd.c
blob9a7b34fa5d79d1ccf1ea1047f50913db995a5287
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"
32 /* These values discovered by inspection */
34 struct perm_value {
35 const char *perm;
36 uint32_t mask;
39 static const struct perm_value special_values[] = {
40 { "R", SEC_RIGHTS_FILE_READ },
41 { "W", SEC_RIGHTS_FILE_WRITE },
42 { "X", SEC_RIGHTS_FILE_EXECUTE },
43 { "D", SEC_STD_DELETE },
44 { "P", SEC_STD_WRITE_DAC },
45 { "O", SEC_STD_WRITE_OWNER },
46 { NULL, 0 },
49 static const struct perm_value standard_values[] = {
50 { "READ", SEC_RIGHTS_DIR_READ|SEC_DIR_TRAVERSE },
51 { "CHANGE", SEC_RIGHTS_DIR_READ|SEC_STD_DELETE|\
52 SEC_RIGHTS_DIR_WRITE|SEC_DIR_TRAVERSE },
53 { "FULL", SEC_RIGHTS_DIR_ALL },
54 { NULL, 0 },
57 static const struct {
58 uint16_t mask;
59 const char *str;
60 const char *desc;
61 } sec_desc_ctrl_bits[] = {
62 {SEC_DESC_OWNER_DEFAULTED, "OD", "Owner Defaulted"},
63 {SEC_DESC_GROUP_DEFAULTED, "GD", "Group Defaulted"},
64 {SEC_DESC_DACL_PRESENT, "DP", "DACL Present"},
65 {SEC_DESC_DACL_DEFAULTED, "DD", "DACL Defaulted"},
66 {SEC_DESC_SACL_PRESENT, "SP", "SACL Present"},
67 {SEC_DESC_SACL_DEFAULTED, "SD", "SACL Defaulted"},
68 {SEC_DESC_DACL_TRUSTED, "DT", "DACL Trusted"},
69 {SEC_DESC_SERVER_SECURITY, "SS", "Server Security"},
70 {SEC_DESC_DACL_AUTO_INHERIT_REQ, "DR", "DACL Inheritance Required"},
71 {SEC_DESC_SACL_AUTO_INHERIT_REQ, "SR", "SACL Inheritance Required"},
72 {SEC_DESC_DACL_AUTO_INHERITED, "DI", "DACL Auto Inherited"},
73 {SEC_DESC_SACL_AUTO_INHERITED, "SI", "SACL Auto Inherited"},
74 {SEC_DESC_DACL_PROTECTED, "PD", "DACL Protected"},
75 {SEC_DESC_SACL_PROTECTED, "PS", "SACL Protected"},
76 {SEC_DESC_RM_CONTROL_VALID, "RM", "RM Control Valid"},
77 {SEC_DESC_SELF_RELATIVE , "SR", "Self Relative"},
80 /* Open cli connection and policy handle */
81 static NTSTATUS cli_lsa_lookup_sid(struct cli_state *cli,
82 const struct dom_sid *sid,
83 TALLOC_CTX *mem_ctx,
84 enum lsa_SidType *type,
85 char **domain, char **name)
87 uint16_t orig_cnum = cli_state_get_tid(cli);
88 struct rpc_pipe_client *p = NULL;
89 struct policy_handle handle;
90 NTSTATUS status;
91 TALLOC_CTX *frame = talloc_stackframe();
92 enum lsa_SidType *types;
93 char **domains;
94 char **names;
96 status = cli_tree_connect(cli, "IPC$", "?????", "", 0);
97 if (!NT_STATUS_IS_OK(status)) {
98 goto tcon_fail;
101 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
102 &p);
103 if (!NT_STATUS_IS_OK(status)) {
104 goto fail;
107 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
108 GENERIC_EXECUTE_ACCESS, &handle);
109 if (!NT_STATUS_IS_OK(status)) {
110 goto fail;
113 status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
114 &domains, &names, &types);
115 if (!NT_STATUS_IS_OK(status)) {
116 goto fail;
119 *type = types[0];
120 *domain = talloc_move(mem_ctx, &domains[0]);
121 *name = talloc_move(mem_ctx, &names[0]);
123 status = NT_STATUS_OK;
124 fail:
125 TALLOC_FREE(p);
126 cli_tdis(cli);
127 tcon_fail:
128 cli_state_set_tid(cli, orig_cnum);
129 TALLOC_FREE(frame);
130 return status;
133 /* convert a SID to a string, either numeric or username/group */
134 void SidToString(struct cli_state *cli, fstring str, const struct dom_sid *sid,
135 bool numeric)
137 char *domain = NULL;
138 char *name = NULL;
139 enum lsa_SidType type;
140 NTSTATUS status;
142 sid_to_fstring(str, sid);
144 if (numeric || cli == NULL) {
145 return;
148 status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
149 &domain, &name);
151 if (!NT_STATUS_IS_OK(status)) {
152 return;
155 if (*domain) {
156 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
157 domain, lp_winbind_separator(), name);
158 } else {
159 fstrcpy(str, name);
163 static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
164 const char *name,
165 enum lsa_SidType *type,
166 struct dom_sid *sid)
168 uint16_t orig_cnum = cli_state_get_tid(cli);
169 struct rpc_pipe_client *p;
170 struct policy_handle handle;
171 NTSTATUS status;
172 TALLOC_CTX *frame = talloc_stackframe();
173 struct dom_sid *sids;
174 enum lsa_SidType *types;
176 status = cli_tree_connect(cli, "IPC$", "?????", "", 0);
177 if (!NT_STATUS_IS_OK(status)) {
178 goto tcon_fail;
181 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
182 &p);
183 if (!NT_STATUS_IS_OK(status)) {
184 goto fail;
187 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
188 GENERIC_EXECUTE_ACCESS, &handle);
189 if (!NT_STATUS_IS_OK(status)) {
190 goto fail;
193 status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
194 NULL, 1, &sids, &types);
195 if (!NT_STATUS_IS_OK(status)) {
196 goto fail;
199 *type = types[0];
200 *sid = sids[0];
202 status = NT_STATUS_OK;
203 fail:
204 TALLOC_FREE(p);
205 cli_tdis(cli);
206 tcon_fail:
207 cli_state_set_tid(cli, orig_cnum);
208 TALLOC_FREE(frame);
209 return status;
212 /* convert a string to a SID, either numeric or username/group */
213 bool StringToSid(struct cli_state *cli, struct dom_sid *sid, const char *str)
215 enum lsa_SidType type;
217 if (string_to_sid(sid, str)) {
218 return true;
221 if (cli == NULL) {
222 return false;
225 return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli, str, &type, sid));
228 static void print_ace_flags(FILE *f, uint8_t flags)
230 char *str = talloc_strdup(NULL, "");
232 if (!str) {
233 goto out;
236 if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
237 str = talloc_asprintf(str, "%s%s",
238 str, "OI|");
239 if (!str) {
240 goto out;
243 if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
244 str = talloc_asprintf(str, "%s%s",
245 str, "CI|");
246 if (!str) {
247 goto out;
250 if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
251 str = talloc_asprintf(str, "%s%s",
252 str, "NP|");
253 if (!str) {
254 goto out;
257 if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
258 str = talloc_asprintf(str, "%s%s",
259 str, "IO|");
260 if (!str) {
261 goto out;
264 if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
265 str = talloc_asprintf(str, "%s%s",
266 str, "I|");
267 if (!str) {
268 goto out;
271 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
272 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
273 audit ace flags. */
275 if (str[strlen(str)-1] == '|') {
276 str[strlen(str)-1] = '\0';
277 fprintf(f, "/%s/", str);
278 } else {
279 fprintf(f, "/0x%x/", flags);
281 TALLOC_FREE(str);
282 return;
284 out:
285 fprintf(f, "/0x%x/", flags);
288 /* print an ACE on a FILE, using either numeric or ascii representation */
289 void print_ace(struct cli_state *cli, FILE *f, struct security_ace *ace,
290 bool numeric)
292 const struct perm_value *v;
293 fstring sidstr;
294 int do_print = 0;
295 uint32_t got_mask;
297 SidToString(cli, sidstr, &ace->trustee, numeric);
299 fprintf(f, "%s:", sidstr);
301 if (numeric) {
302 fprintf(f, "%d/0x%x/0x%08x",
303 ace->type, ace->flags, ace->access_mask);
304 return;
307 /* Ace type */
309 if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
310 fprintf(f, "ALLOWED");
311 } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
312 fprintf(f, "DENIED");
313 } else {
314 fprintf(f, "%d", ace->type);
317 print_ace_flags(f, ace->flags);
319 /* Standard permissions */
321 for (v = standard_values; v->perm; v++) {
322 if (ace->access_mask == v->mask) {
323 fprintf(f, "%s", v->perm);
324 return;
328 /* Special permissions. Print out a hex value if we have
329 leftover bits in the mask. */
331 got_mask = ace->access_mask;
333 again:
334 for (v = special_values; v->perm; v++) {
335 if ((ace->access_mask & v->mask) == v->mask) {
336 if (do_print) {
337 fprintf(f, "%s", v->perm);
339 got_mask &= ~v->mask;
343 if (!do_print) {
344 if (got_mask != 0) {
345 fprintf(f, "0x%08x", ace->access_mask);
346 } else {
347 do_print = 1;
348 goto again;
353 static bool parse_ace_flags(const char *str, unsigned int *pflags)
355 const char *p = str;
356 *pflags = 0;
358 while (*p) {
359 if (strnequal(p, "OI", 2)) {
360 *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT;
361 p += 2;
362 } else if (strnequal(p, "CI", 2)) {
363 *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
364 p += 2;
365 } else if (strnequal(p, "NP", 2)) {
366 *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
367 p += 2;
368 } else if (strnequal(p, "IO", 2)) {
369 *pflags |= SEC_ACE_FLAG_INHERIT_ONLY;
370 p += 2;
371 } else if (*p == 'I') {
372 *pflags |= SEC_ACE_FLAG_INHERITED_ACE;
373 p += 1;
374 } else if (*p) {
375 return false;
378 switch (*p) {
379 case '|':
380 p++;
381 case '\0':
382 continue;
383 default:
384 return false;
387 return true;
390 /* parse an ACE in the same format as print_ace() */
391 bool parse_ace(struct cli_state *cli, struct security_ace *ace,
392 const char *orig_str)
394 char *p;
395 const char *cp;
396 char *tok;
397 unsigned int atype = 0;
398 unsigned int aflags = 0;
399 unsigned int amask = 0;
400 struct dom_sid sid;
401 uint32_t mask;
402 const struct perm_value *v;
403 char *str = SMB_STRDUP(orig_str);
404 TALLOC_CTX *frame = talloc_stackframe();
406 if (!str) {
407 TALLOC_FREE(frame);
408 return False;
411 ZERO_STRUCTP(ace);
412 p = strchr_m(str,':');
413 if (!p) {
414 printf("ACE '%s': missing ':'.\n", orig_str);
415 SAFE_FREE(str);
416 TALLOC_FREE(frame);
417 return False;
419 *p = '\0';
420 p++;
422 if (!StringToSid(cli, &sid, str)) {
423 printf("ACE '%s': failed to convert '%s' to SID\n",
424 orig_str, str);
425 SAFE_FREE(str);
426 TALLOC_FREE(frame);
427 return False;
430 cp = p;
431 if (!next_token_talloc(frame, &cp, &tok, "/")) {
432 printf("ACE '%s': failed to find '/' character.\n",
433 orig_str);
434 SAFE_FREE(str);
435 TALLOC_FREE(frame);
436 return False;
439 if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
440 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
441 } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
442 atype = SEC_ACE_TYPE_ACCESS_DENIED;
444 } else if (strnequal(tok, "0x", 2)) {
445 int result;
447 result = sscanf(tok, "%x", &atype);
448 if (result == 0 ||
449 (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
450 atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
451 printf("ACE '%s': bad hex value for type at '%s'\n",
452 orig_str, tok);
453 SAFE_FREE(str);
454 TALLOC_FREE(frame);
455 return false;
457 } else if(tok[0] >= '0' && tok[0] <= '9') {
458 int result;
460 result = sscanf(tok, "%u", &atype);
461 if (result == 0 ||
462 (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
463 atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
464 printf("ACE '%s': bad integer value for type at '%s'\n",
465 orig_str, tok);
466 SAFE_FREE(str);
467 TALLOC_FREE(frame);
468 return false;
470 } else {
471 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
472 orig_str, tok);
473 SAFE_FREE(str);
474 TALLOC_FREE(frame);
475 return False;
478 if (!next_token_talloc(frame, &cp, &tok, "/")) {
479 printf("ACE '%s': bad flags entry at '%s'\n",
480 orig_str, tok);
481 SAFE_FREE(str);
482 TALLOC_FREE(frame);
483 return False;
486 if (tok[0] < '0' || tok[0] > '9') {
487 if (!parse_ace_flags(tok, &aflags)) {
488 printf("ACE '%s': bad named flags entry at '%s'\n",
489 orig_str, tok);
490 SAFE_FREE(str);
491 TALLOC_FREE(frame);
492 return False;
494 } else if (strnequal(tok, "0x", 2)) {
495 if (!sscanf(tok, "%x", &aflags)) {
496 printf("ACE '%s': bad hex flags entry at '%s'\n",
497 orig_str, tok);
498 SAFE_FREE(str);
499 TALLOC_FREE(frame);
500 return False;
502 } else {
503 if (!sscanf(tok, "%u", &aflags)) {
504 printf("ACE '%s': bad integer flags entry at '%s'\n",
505 orig_str, tok);
506 SAFE_FREE(str);
507 TALLOC_FREE(frame);
508 return False;
512 if (!next_token_talloc(frame, &cp, &tok, "/")) {
513 printf("ACE '%s': missing / at '%s'\n",
514 orig_str, tok);
515 SAFE_FREE(str);
516 TALLOC_FREE(frame);
517 return False;
520 if (strncmp(tok, "0x", 2) == 0) {
521 if (sscanf(tok, "%x", &amask) != 1) {
522 printf("ACE '%s': bad hex number at '%s'\n",
523 orig_str, tok);
524 SAFE_FREE(str);
525 TALLOC_FREE(frame);
526 return False;
528 goto done;
531 for (v = standard_values; v->perm; v++) {
532 if (strcmp(tok, v->perm) == 0) {
533 amask = v->mask;
534 goto done;
538 p = tok;
540 while(*p) {
541 bool found = False;
543 for (v = special_values; v->perm; v++) {
544 if (v->perm[0] == *p) {
545 amask |= v->mask;
546 found = True;
550 if (!found) {
551 printf("ACE '%s': bad permission value at '%s'\n",
552 orig_str, p);
553 SAFE_FREE(str);
554 TALLOC_FREE(frame);
555 return False;
557 p++;
560 if (*p) {
561 TALLOC_FREE(frame);
562 SAFE_FREE(str);
563 return False;
566 done:
567 mask = amask;
568 init_sec_ace(ace, &sid, atype, mask, aflags);
569 TALLOC_FREE(frame);
570 SAFE_FREE(str);
571 return True;
574 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
576 int i;
577 const char* separator = "";
579 fprintf(file, "CONTROL:");
580 if (numeric) {
581 fprintf(file, "0x%x\n", ctrl);
582 return;
585 for (i = ARRAY_SIZE(sec_desc_ctrl_bits) - 1; i >= 0; i--) {
586 if (ctrl & sec_desc_ctrl_bits[i].mask) {
587 fprintf(file, "%s%s",
588 separator, sec_desc_ctrl_bits[i].str);
589 separator = "|";
592 fputc('\n', file);
595 /* print a ascii version of a security descriptor on a FILE handle */
596 void sec_desc_print(struct cli_state *cli, FILE *f,
597 struct security_descriptor *sd, bool numeric)
599 fstring sidstr;
600 uint32_t i;
602 fprintf(f, "REVISION:%d\n", sd->revision);
603 print_acl_ctrl(f, sd->type, numeric);
605 /* Print owner and group sid */
607 if (sd->owner_sid) {
608 SidToString(cli, sidstr, sd->owner_sid, numeric);
609 } else {
610 fstrcpy(sidstr, "");
613 fprintf(f, "OWNER:%s\n", sidstr);
615 if (sd->group_sid) {
616 SidToString(cli, sidstr, sd->group_sid, numeric);
617 } else {
618 fstrcpy(sidstr, "");
621 fprintf(f, "GROUP:%s\n", sidstr);
623 /* Print aces */
624 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
625 struct security_ace *ace = &sd->dacl->aces[i];
626 fprintf(f, "ACL:");
627 print_ace(cli, f, ace, numeric);
628 fprintf(f, "\n");