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"
31 #include "lib/util/string_wrappers.h"
33 /* These values discovered by inspection */
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
},
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_RIGHTS_DIR_WRITE
|SEC_DIR_TRAVERSE
},
54 { "FULL", SEC_RIGHTS_DIR_ALL
},
62 } sec_desc_ctrl_bits
[] = {
63 {SEC_DESC_OWNER_DEFAULTED
, "OD", "Owner Defaulted"},
64 {SEC_DESC_GROUP_DEFAULTED
, "GD", "Group Defaulted"},
65 {SEC_DESC_DACL_PRESENT
, "DP", "DACL Present"},
66 {SEC_DESC_DACL_DEFAULTED
, "DD", "DACL Defaulted"},
67 {SEC_DESC_SACL_PRESENT
, "SP", "SACL Present"},
68 {SEC_DESC_SACL_DEFAULTED
, "SD", "SACL Defaulted"},
69 {SEC_DESC_DACL_TRUSTED
, "DT", "DACL Trusted"},
70 {SEC_DESC_SERVER_SECURITY
, "SS", "Server Security"},
71 {SEC_DESC_DACL_AUTO_INHERIT_REQ
, "DR", "DACL Inheritance Required"},
72 {SEC_DESC_SACL_AUTO_INHERIT_REQ
, "SR", "SACL Inheritance Required"},
73 {SEC_DESC_DACL_AUTO_INHERITED
, "DI", "DACL Auto Inherited"},
74 {SEC_DESC_SACL_AUTO_INHERITED
, "SI", "SACL Auto Inherited"},
75 {SEC_DESC_DACL_PROTECTED
, "PD", "DACL Protected"},
76 {SEC_DESC_SACL_PROTECTED
, "PS", "SACL Protected"},
77 {SEC_DESC_RM_CONTROL_VALID
, "RM", "RM Control Valid"},
78 {SEC_DESC_SELF_RELATIVE
, "SR", "Self Relative"},
81 /* Open cli connection and policy handle */
82 static NTSTATUS
cli_lsa_lookup_sid(struct cli_state
*cli
,
83 const struct dom_sid
*sid
,
85 enum lsa_SidType
*type
,
86 char **domain
, char **name
)
88 struct smbXcli_tcon
*orig_tcon
= NULL
;
89 struct rpc_pipe_client
*p
= NULL
;
90 struct policy_handle handle
;
92 TALLOC_CTX
*frame
= talloc_stackframe();
93 enum lsa_SidType
*types
;
97 if (cli_state_has_tcon(cli
)) {
98 orig_tcon
= cli_state_save_tcon(cli
);
99 if (orig_tcon
== NULL
) {
100 status
= NT_STATUS_NO_MEMORY
;
105 status
= cli_tree_connect(cli
, "IPC$", "?????", NULL
);
106 if (!NT_STATUS_IS_OK(status
)) {
110 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_lsarpc
,
112 if (!NT_STATUS_IS_OK(status
)) {
116 status
= rpccli_lsa_open_policy(p
, talloc_tos(), True
,
117 GENERIC_EXECUTE_ACCESS
, &handle
);
118 if (!NT_STATUS_IS_OK(status
)) {
122 status
= rpccli_lsa_lookup_sids(p
, talloc_tos(), &handle
, 1, sid
,
123 &domains
, &names
, &types
);
124 if (!NT_STATUS_IS_OK(status
)) {
129 *domain
= talloc_move(mem_ctx
, &domains
[0]);
130 *name
= talloc_move(mem_ctx
, &names
[0]);
132 status
= NT_STATUS_OK
;
137 cli_state_restore_tcon(cli
, orig_tcon
);
142 /* convert a SID to a string, either numeric or username/group */
143 void SidToString(struct cli_state
*cli
, fstring str
, const struct dom_sid
*sid
,
148 enum lsa_SidType type
;
151 sid_to_fstring(str
, sid
);
153 if (numeric
|| cli
== NULL
) {
157 status
= cli_lsa_lookup_sid(cli
, sid
, talloc_tos(), &type
,
160 if (!NT_STATUS_IS_OK(status
)) {
165 slprintf(str
, sizeof(fstring
) - 1, "%s%s%s",
166 domain
, lp_winbind_separator(), name
);
172 static NTSTATUS
cli_lsa_lookup_name(struct cli_state
*cli
,
174 enum lsa_SidType
*type
,
177 struct smbXcli_tcon
*orig_tcon
= NULL
;
178 struct rpc_pipe_client
*p
= NULL
;
179 struct policy_handle handle
;
181 TALLOC_CTX
*frame
= talloc_stackframe();
182 struct dom_sid
*sids
;
183 enum lsa_SidType
*types
;
185 if (cli_state_has_tcon(cli
)) {
186 orig_tcon
= cli_state_save_tcon(cli
);
187 if (orig_tcon
== NULL
) {
188 status
= NT_STATUS_NO_MEMORY
;
193 status
= cli_tree_connect(cli
, "IPC$", "?????", NULL
);
194 if (!NT_STATUS_IS_OK(status
)) {
198 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_lsarpc
,
200 if (!NT_STATUS_IS_OK(status
)) {
204 status
= rpccli_lsa_open_policy(p
, talloc_tos(), True
,
205 GENERIC_EXECUTE_ACCESS
, &handle
);
206 if (!NT_STATUS_IS_OK(status
)) {
210 status
= rpccli_lsa_lookup_names(p
, talloc_tos(), &handle
, 1, &name
,
211 NULL
, 1, &sids
, &types
);
212 if (!NT_STATUS_IS_OK(status
)) {
219 status
= NT_STATUS_OK
;
224 cli_state_restore_tcon(cli
, orig_tcon
);
229 /* convert a string to a SID, either numeric or username/group */
230 bool StringToSid(struct cli_state
*cli
, struct dom_sid
*sid
, const char *str
)
232 enum lsa_SidType type
;
234 if (string_to_sid(sid
, str
)) {
242 return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli
, str
, &type
, sid
));
245 static void print_ace_flags(FILE *f
, uint8_t flags
)
247 char *str
= talloc_strdup(NULL
, "");
253 if (flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) {
254 str
= talloc_asprintf(str
, "%s%s",
260 if (flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
261 str
= talloc_asprintf(str
, "%s%s",
267 if (flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
268 str
= talloc_asprintf(str
, "%s%s",
274 if (flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
275 str
= talloc_asprintf(str
, "%s%s",
281 if (flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
282 str
= talloc_asprintf(str
, "%s%s",
288 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
289 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
292 if (str
[strlen(str
)-1] == '|') {
293 str
[strlen(str
)-1] = '\0';
294 fprintf(f
, "/%s/", str
);
296 fprintf(f
, "/0x%x/", flags
);
302 fprintf(f
, "/0x%x/", flags
);
305 /* print an ACE on a FILE, using either numeric or ascii representation */
306 void print_ace(struct cli_state
*cli
, FILE *f
, struct security_ace
*ace
,
309 const struct perm_value
*v
;
314 SidToString(cli
, sidstr
, &ace
->trustee
, numeric
);
316 fprintf(f
, "%s:", sidstr
);
319 fprintf(f
, "%d/0x%x/0x%08x",
320 ace
->type
, ace
->flags
, ace
->access_mask
);
326 if (ace
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED
) {
327 fprintf(f
, "ALLOWED");
328 } else if (ace
->type
== SEC_ACE_TYPE_ACCESS_DENIED
) {
329 fprintf(f
, "DENIED");
331 fprintf(f
, "%d", ace
->type
);
334 print_ace_flags(f
, ace
->flags
);
336 /* Standard permissions */
338 for (v
= standard_values
; v
->perm
; v
++) {
339 if (ace
->access_mask
== v
->mask
) {
340 fprintf(f
, "%s", v
->perm
);
345 /* Special permissions. Print out a hex value if we have
346 leftover bits in the mask. */
348 got_mask
= ace
->access_mask
;
351 for (v
= special_values
; v
->perm
; v
++) {
352 if ((ace
->access_mask
& v
->mask
) == v
->mask
) {
354 fprintf(f
, "%s", v
->perm
);
356 got_mask
&= ~v
->mask
;
362 fprintf(f
, "0x%08x", ace
->access_mask
);
370 static bool parse_ace_flags(const char *str
, unsigned int *pflags
)
376 if (strnequal(p
, "OI", 2)) {
377 *pflags
|= SEC_ACE_FLAG_OBJECT_INHERIT
;
379 } else if (strnequal(p
, "CI", 2)) {
380 *pflags
|= SEC_ACE_FLAG_CONTAINER_INHERIT
;
382 } else if (strnequal(p
, "NP", 2)) {
383 *pflags
|= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
;
385 } else if (strnequal(p
, "IO", 2)) {
386 *pflags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
388 } else if (*p
== 'I') {
389 *pflags
|= SEC_ACE_FLAG_INHERITED_ACE
;
409 /* parse an ACE in the same format as print_ace() */
410 bool parse_ace(struct cli_state
*cli
, struct security_ace
*ace
,
411 const char *orig_str
)
416 unsigned int atype
= 0;
417 unsigned int aflags
= 0;
418 unsigned int amask
= 0;
421 const struct perm_value
*v
;
422 char *str
= SMB_STRDUP(orig_str
);
423 TALLOC_CTX
*frame
= talloc_stackframe();
431 p
= strchr_m(str
,':');
433 printf("ACE '%s': missing ':'.\n", orig_str
);
441 if (!StringToSid(cli
, &sid
, str
)) {
442 printf("ACE '%s': failed to convert '%s' to SID\n",
450 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
451 printf("ACE '%s': failed to find '/' character.\n",
458 if (strncmp(tok
, "ALLOWED", strlen("ALLOWED")) == 0) {
459 atype
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
460 } else if (strncmp(tok
, "DENIED", strlen("DENIED")) == 0) {
461 atype
= SEC_ACE_TYPE_ACCESS_DENIED
;
463 } else if (strnequal(tok
, "0x", 2)) {
466 result
= sscanf(tok
, "%x", &atype
);
468 (atype
!= SEC_ACE_TYPE_ACCESS_ALLOWED
&&
469 atype
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
470 printf("ACE '%s': bad hex value for type at '%s'\n",
476 } else if(tok
[0] >= '0' && tok
[0] <= '9') {
479 result
= sscanf(tok
, "%u", &atype
);
481 (atype
!= SEC_ACE_TYPE_ACCESS_ALLOWED
&&
482 atype
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
483 printf("ACE '%s': bad integer value for type at '%s'\n",
490 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
497 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
498 printf("ACE '%s': bad flags entry at '%s'\n",
505 if (tok
[0] < '0' || tok
[0] > '9') {
506 if (!parse_ace_flags(tok
, &aflags
)) {
507 printf("ACE '%s': bad named flags entry at '%s'\n",
513 } else if (strnequal(tok
, "0x", 2)) {
514 if (!sscanf(tok
, "%x", &aflags
)) {
515 printf("ACE '%s': bad hex flags entry at '%s'\n",
522 if (!sscanf(tok
, "%u", &aflags
)) {
523 printf("ACE '%s': bad integer flags entry at '%s'\n",
531 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
532 printf("ACE '%s': missing / at '%s'\n",
539 if (strncmp(tok
, "0x", 2) == 0) {
540 if (sscanf(tok
, "%x", &amask
) != 1) {
541 printf("ACE '%s': bad hex number at '%s'\n",
550 for (v
= standard_values
; v
->perm
; v
++) {
551 if (strcmp(tok
, v
->perm
) == 0) {
562 for (v
= special_values
; v
->perm
; v
++) {
563 if (v
->perm
[0] == *p
) {
570 printf("ACE '%s': bad permission value at '%s'\n",
587 init_sec_ace(ace
, &sid
, atype
, mask
, aflags
);
593 static void print_acl_ctrl(FILE *file
, uint16_t ctrl
, bool numeric
)
596 const char* separator
= "";
598 fprintf(file
, "CONTROL:");
600 fprintf(file
, "0x%x\n", ctrl
);
604 for (i
= ARRAY_SIZE(sec_desc_ctrl_bits
) - 1; i
>= 0; i
--) {
605 if (ctrl
& sec_desc_ctrl_bits
[i
].mask
) {
606 fprintf(file
, "%s%s",
607 separator
, sec_desc_ctrl_bits
[i
].str
);
614 /* print a ascii version of a security descriptor on a FILE handle */
615 void sec_desc_print(struct cli_state
*cli
, FILE *f
,
616 struct security_descriptor
*sd
, bool numeric
)
621 fprintf(f
, "REVISION:%d\n", sd
->revision
);
622 print_acl_ctrl(f
, sd
->type
, numeric
);
624 /* Print owner and group sid */
627 SidToString(cli
, sidstr
, sd
->owner_sid
, numeric
);
632 fprintf(f
, "OWNER:%s\n", sidstr
);
635 SidToString(cli
, sidstr
, sd
->group_sid
, numeric
);
640 fprintf(f
, "GROUP:%s\n", sidstr
);
643 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
644 struct security_ace
*ace
= &sd
->dacl
->aces
[i
];
646 print_ace(cli
, f
, ace
, numeric
);