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/>.
25 #include "libsmb/libsmb.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 */
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 },
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 },
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,
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;
91 TALLOC_CTX *frame = talloc_stackframe();
92 enum lsa_SidType *types;
96 status = cli_tree_connect(cli, "IPC$", "?????", "", 0);
97 if (!NT_STATUS_IS_OK(status)) {
101 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
103 if (!NT_STATUS_IS_OK(status)) {
107 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
108 GENERIC_EXECUTE_ACCESS, &handle);
109 if (!NT_STATUS_IS_OK(status)) {
113 status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
114 &domains, &names, &types);
115 if (!NT_STATUS_IS_OK(status)) {
120 *domain = talloc_move(mem_ctx, &domains[0]);
121 *name = talloc_move(mem_ctx, &names[0]);
123 status = NT_STATUS_OK;
128 cli_state_set_tid(cli, orig_cnum);
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,
139 enum lsa_SidType type;
142 sid_to_fstring(str, sid);
144 if (numeric || cli == NULL) {
148 status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
151 if (!NT_STATUS_IS_OK(status)) {
156 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
157 domain, lp_winbind_separator(), name);
163 static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
165 enum lsa_SidType *type,
168 uint16_t orig_cnum = cli_state_get_tid(cli);
169 struct rpc_pipe_client *p;
170 struct policy_handle handle;
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)) {
181 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
183 if (!NT_STATUS_IS_OK(status)) {
187 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
188 GENERIC_EXECUTE_ACCESS, &handle);
189 if (!NT_STATUS_IS_OK(status)) {
193 status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
194 NULL, 1, &sids, &types);
195 if (!NT_STATUS_IS_OK(status)) {
202 status = NT_STATUS_OK;
207 cli_state_set_tid(cli, orig_cnum);
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)) {
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, "");
236 if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
237 str = talloc_asprintf(str, "%s%s",
243 if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
244 str = talloc_asprintf(str, "%s%s",
250 if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
251 str = talloc_asprintf(str, "%s%s",
257 if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
258 str = talloc_asprintf(str, "%s%s",
264 if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
265 str = talloc_asprintf(str, "%s%s",
271 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
272 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
275 if (str[strlen(str)-1] == '|') {
276 str[strlen(str)-1] = '\0';
277 fprintf(f, "/%s/", str);
279 fprintf(f, "/0x%x/", flags);
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,
292 const struct perm_value *v;
297 SidToString(cli, sidstr, &ace->trustee, numeric);
299 fprintf(f, "%s:", sidstr);
302 fprintf(f, "%d/0x%x/0x%08x",
303 ace->type, ace->flags, ace->access_mask);
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");
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);
328 /* Special permissions. Print out a hex value if we have
329 leftover bits in the mask. */
331 got_mask = ace->access_mask;
334 for (v = special_values; v->perm; v++) {
335 if ((ace->access_mask & v->mask) == v->mask) {
337 fprintf(f, "%s", v->perm);
339 got_mask &= ~v->mask;
345 fprintf(f, "0x%08x", ace->access_mask);
353 static bool parse_ace_flags(const char *str, unsigned int *pflags)
359 if (strnequal(p, "OI", 2)) {
360 *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT;
362 } else if (strnequal(p, "CI", 2)) {
363 *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
365 } else if (strnequal(p, "NP", 2)) {
366 *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
368 } else if (strnequal(p, "IO", 2)) {
369 *pflags |= SEC_ACE_FLAG_INHERIT_ONLY;
371 } else if (*p == 'I') {
372 *pflags |= SEC_ACE_FLAG_INHERITED_ACE;
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)
397 unsigned int atype = 0;
398 unsigned int aflags = 0;
399 unsigned int amask = 0;
402 const struct perm_value *v;
403 char *str = SMB_STRDUP(orig_str);
404 TALLOC_CTX *frame = talloc_stackframe();
412 p = strchr_m(str,':');
414 printf("ACE '%s': missing ':'.\n", orig_str);
422 if (!StringToSid(cli, &sid, str)) {
423 printf("ACE '%s': failed to convert '%s' to SID\n",
431 if (!next_token_talloc(frame, &cp, &tok, "/")) {
432 printf("ACE '%s': failed to find '/' character.\n",
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)) {
447 result = sscanf(tok, "%x", &atype);
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",
457 } else if(tok[0] >= '0' && tok[0] <= '9') {
460 result = sscanf(tok, "%u", &atype);
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",
471 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
478 if (!next_token_talloc(frame, &cp, &tok, "/")) {
479 printf("ACE '%s': bad flags entry at '%s'\n",
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",
494 } else if (strnequal(tok, "0x", 2)) {
495 if (!sscanf(tok, "%x", &aflags)) {
496 printf("ACE '%s': bad hex flags entry at '%s'\n",
503 if (!sscanf(tok, "%u", &aflags)) {
504 printf("ACE '%s': bad integer flags entry at '%s'\n",
512 if (!next_token_talloc(frame, &cp, &tok, "/")) {
513 printf("ACE '%s': missing / at '%s'\n",
520 if (strncmp(tok, "0x", 2) == 0) {
521 if (sscanf(tok, "%x", &amask) != 1) {
522 printf("ACE '%s': bad hex number at '%s'\n",
531 for (v = standard_values; v->perm; v++) {
532 if (strcmp(tok, v->perm) == 0) {
543 for (v = special_values; v->perm; v++) {
544 if (v->perm[0] == *p) {
551 printf("ACE '%s': bad permission value at '%s'\n",
568 init_sec_ace(ace, &sid, atype, mask, aflags);
574 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
577 const char* separator = "";
579 fprintf(file, "CONTROL:");
581 fprintf(file, "0x%x\n", ctrl);
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);
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)
602 fprintf(f, "REVISION:%d\n", sd->revision);
603 print_acl_ctrl(f, sd->type, numeric);
605 /* Print owner and group sid */
608 SidToString(cli, sidstr, sd->owner_sid, numeric);
613 fprintf(f, "OWNER:%s\n", sidstr);
616 SidToString(cli, sidstr, sd->group_sid, numeric);
621 fprintf(f, "GROUP:%s\n", sidstr);
624 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
625 struct security_ace *ace = &sd->dacl->aces[i];
627 print_ace(cli, f, ace, numeric);