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
);
421 /* Try to parse numeric form */
423 if (sscanf(p
, "%u/%u/%u", &atype
, &aflags
, &amask
) == 3 &&
424 StringToSid(cli
, &sid
, str
)) {
428 /* Try to parse text form */
430 if (!StringToSid(cli
, &sid
, str
)) {
431 printf("ACE '%s': failed to convert '%s' to SID\n",
439 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
440 printf("ACE '%s': failed to find '/' character.\n",
447 if (strncmp(tok
, "ALLOWED", strlen("ALLOWED")) == 0) {
448 atype
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
449 } else if (strncmp(tok
, "DENIED", strlen("DENIED")) == 0) {
450 atype
= SEC_ACE_TYPE_ACCESS_DENIED
;
452 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
459 /* Only numeric form accepted for flags at present */
461 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
462 printf("ACE '%s': bad flags entry at '%s'\n",
469 if (tok
[0] < '0' || tok
[0] > '9') {
470 if (!parse_ace_flags(tok
, &aflags
)) {
471 printf("ACE '%s': bad named flags entry at '%s'\n",
477 } else if (strnequal(tok
, "0x", 2)) {
478 if (!sscanf(tok
, "%x", &aflags
)) {
479 printf("ACE '%s': bad hex flags entry at '%s'\n",
486 if (!sscanf(tok
, "%u", &aflags
)) {
487 printf("ACE '%s': bad integer flags entry at '%s'\n",
495 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
496 printf("ACE '%s': missing / at '%s'\n",
503 if (strncmp(tok
, "0x", 2) == 0) {
504 if (sscanf(tok
, "%x", &amask
) != 1) {
505 printf("ACE '%s': bad hex number at '%s'\n",
514 for (v
= standard_values
; v
->perm
; v
++) {
515 if (strcmp(tok
, v
->perm
) == 0) {
526 for (v
= special_values
; v
->perm
; v
++) {
527 if (v
->perm
[0] == *p
) {
534 printf("ACE '%s': bad permission value at '%s'\n",
551 init_sec_ace(ace
, &sid
, atype
, mask
, aflags
);
557 static void print_acl_ctrl(FILE *file
, uint16_t ctrl
, bool numeric
)
560 const char* separator
= "";
562 fprintf(file
, "CONTROL:");
564 fprintf(file
, "0x%x\n", ctrl
);
568 for (i
= ARRAY_SIZE(sec_desc_ctrl_bits
) - 1; i
>= 0; i
--) {
569 if (ctrl
& sec_desc_ctrl_bits
[i
].mask
) {
570 fprintf(file
, "%s%s",
571 separator
, sec_desc_ctrl_bits
[i
].str
);
578 /* print a ascii version of a security descriptor on a FILE handle */
579 void sec_desc_print(struct cli_state
*cli
, FILE *f
,
580 struct security_descriptor
*sd
, bool numeric
)
585 fprintf(f
, "REVISION:%d\n", sd
->revision
);
586 print_acl_ctrl(f
, sd
->type
, numeric
);
588 /* Print owner and group sid */
591 SidToString(cli
, sidstr
, sd
->owner_sid
, numeric
);
596 fprintf(f
, "OWNER:%s\n", sidstr
);
599 SidToString(cli
, sidstr
, sd
->group_sid
, numeric
);
604 fprintf(f
, "GROUP:%s\n", sidstr
);
607 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
608 struct security_ace
*ace
= &sd
->dacl
->aces
[i
];
610 print_ace(cli
, f
, ace
, numeric
);