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_DIR_DELETE_CHILD
|\
54 SEC_RIGHTS_DIR_WRITE
|SEC_DIR_TRAVERSE
},
55 { "FULL", SEC_RIGHTS_DIR_ALL
},
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
,
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
;
94 TALLOC_CTX
*frame
= talloc_stackframe();
95 enum lsa_SidType
*types
;
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
)) {
108 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_lsarpc
,
110 if (!NT_STATUS_IS_OK(status
)) {
114 status
= rpccli_lsa_open_policy(p
, talloc_tos(), True
,
115 GENERIC_EXECUTE_ACCESS
, &handle
);
116 if (!NT_STATUS_IS_OK(status
)) {
120 status
= rpccli_lsa_lookup_sids(p
, talloc_tos(), &handle
, 1, sid
,
121 &domains
, &names
, &types
);
122 if (!NT_STATUS_IS_OK(status
)) {
127 *domain
= talloc_move(mem_ctx
, &domains
[0]);
128 *name
= talloc_move(mem_ctx
, &names
[0]);
130 status
= NT_STATUS_OK
;
135 cli_state_restore_tcon_share(cli
, orig_tcon
, orig_share
);
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
,
146 enum lsa_SidType type
;
149 sid_to_fstring(str
, sid
);
151 if (numeric
|| cli
== NULL
) {
155 status
= cli_lsa_lookup_sid(cli
, sid
, talloc_tos(), &type
,
158 if (!NT_STATUS_IS_OK(status
)) {
163 slprintf(str
, sizeof(fstring
) - 1, "%s%s%s",
164 domain
, lp_winbind_separator(), name
);
170 static NTSTATUS
cli_lsa_lookup_name(struct cli_state
*cli
,
172 enum lsa_SidType
*type
,
175 struct smbXcli_tcon
*orig_tcon
= NULL
;
176 char *orig_share
= NULL
;
177 struct rpc_pipe_client
*p
= NULL
;
178 struct policy_handle handle
;
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
)) {
193 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_lsarpc
,
195 if (!NT_STATUS_IS_OK(status
)) {
199 status
= rpccli_lsa_open_policy(p
, talloc_tos(), True
,
200 GENERIC_EXECUTE_ACCESS
, &handle
);
201 if (!NT_STATUS_IS_OK(status
)) {
205 status
= rpccli_lsa_lookup_names(p
, talloc_tos(), &handle
, 1, &name
,
206 NULL
, 1, &sids
, &types
);
207 if (!NT_STATUS_IS_OK(status
)) {
214 status
= NT_STATUS_OK
;
219 cli_state_restore_tcon_share(cli
, orig_tcon
, orig_share
);
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
)) {
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
, "");
245 if (flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) {
246 talloc_asprintf_addbuf(&str
, "OI|");
248 if (flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
249 talloc_asprintf_addbuf(&str
, "CI|");
251 if (flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
252 talloc_asprintf_addbuf(&str
, "NP|");
254 if (flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
255 talloc_asprintf_addbuf(&str
, "IO|");
257 if (flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
258 talloc_asprintf_addbuf(&str
, "I|");
264 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
265 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
270 fprintf(f
, "/%.*s/", (int)len
-1, str
);
272 fprintf(f
, "/0x%x/", flags
);
278 fprintf(f
, "/0x%x/", flags
);
281 /* print an ACE on a FILE, using either numeric or ascii representation */
282 void print_ace(struct cli_state
*cli
, FILE *f
, struct security_ace
*ace
,
285 const struct perm_value
*v
;
290 SidToString(cli
, sidstr
, &ace
->trustee
, numeric
);
292 fprintf(f
, "%s:", sidstr
);
295 fprintf(f
, "%d/0x%x/0x%08x",
296 ace
->type
, ace
->flags
, ace
->access_mask
);
302 if (ace
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED
) {
303 fprintf(f
, "ALLOWED");
304 } else if (ace
->type
== SEC_ACE_TYPE_ACCESS_DENIED
) {
305 fprintf(f
, "DENIED");
307 fprintf(f
, "%d", ace
->type
);
310 print_ace_flags(f
, ace
->flags
);
312 /* Standard permissions */
314 for (v
= standard_values
; v
->perm
; v
++) {
315 if (ace
->access_mask
== v
->mask
) {
316 fprintf(f
, "%s", v
->perm
);
321 /* Special permissions. Print out a hex value if we have
322 leftover bits in the mask. */
324 got_mask
= ace
->access_mask
;
327 for (v
= special_values
; v
->perm
; v
++) {
328 if ((ace
->access_mask
& v
->mask
) == v
->mask
) {
330 fprintf(f
, "%s", v
->perm
);
332 got_mask
&= ~v
->mask
;
338 fprintf(f
, "0x%08x", ace
->access_mask
);
346 static bool parse_ace_flags(const char *str
, unsigned int *pflags
)
352 if (strnequal(p
, "OI", 2)) {
353 *pflags
|= SEC_ACE_FLAG_OBJECT_INHERIT
;
355 } else if (strnequal(p
, "CI", 2)) {
356 *pflags
|= SEC_ACE_FLAG_CONTAINER_INHERIT
;
358 } else if (strnequal(p
, "NP", 2)) {
359 *pflags
|= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
;
361 } else if (strnequal(p
, "IO", 2)) {
362 *pflags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
364 } else if (*p
== 'I') {
365 *pflags
|= SEC_ACE_FLAG_INHERITED_ACE
;
385 /* parse an ACE in the same format as print_ace() */
386 bool parse_ace(struct cli_state
*cli
, struct security_ace
*ace
,
387 const char *orig_str
)
392 unsigned int atype
= 0;
393 unsigned int aflags
= 0;
394 unsigned int amask
= 0;
397 const struct perm_value
*v
;
398 char *str
= SMB_STRDUP(orig_str
);
399 TALLOC_CTX
*frame
= talloc_stackframe();
407 p
= strchr_m(str
,':');
409 printf("ACE '%s': missing ':'.\n", orig_str
);
417 if (!StringToSid(cli
, &sid
, str
)) {
418 printf("ACE '%s': failed to convert '%s' to SID\n",
426 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
427 printf("ACE '%s': failed to find '/' character.\n",
434 if (strncmp(tok
, "ALLOWED", strlen("ALLOWED")) == 0) {
435 atype
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
436 } else if (strncmp(tok
, "DENIED", strlen("DENIED")) == 0) {
437 atype
= SEC_ACE_TYPE_ACCESS_DENIED
;
439 } else if (strnequal(tok
, "0x", 2)) {
442 result
= sscanf(tok
, "%x", &atype
);
444 (atype
!= SEC_ACE_TYPE_ACCESS_ALLOWED
&&
445 atype
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
446 printf("ACE '%s': bad hex value for type at '%s'\n",
452 } else if(tok
[0] >= '0' && tok
[0] <= '9') {
455 result
= sscanf(tok
, "%u", &atype
);
457 (atype
!= SEC_ACE_TYPE_ACCESS_ALLOWED
&&
458 atype
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
459 printf("ACE '%s': bad integer value for type at '%s'\n",
466 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
473 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
474 printf("ACE '%s': bad flags entry at '%s'\n",
481 if (tok
[0] < '0' || tok
[0] > '9') {
482 if (!parse_ace_flags(tok
, &aflags
)) {
483 printf("ACE '%s': bad named flags entry at '%s'\n",
489 } else if (strnequal(tok
, "0x", 2)) {
490 if (!sscanf(tok
, "%x", &aflags
)) {
491 printf("ACE '%s': bad hex flags entry at '%s'\n",
498 if (!sscanf(tok
, "%u", &aflags
)) {
499 printf("ACE '%s': bad integer flags entry at '%s'\n",
507 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
508 printf("ACE '%s': missing / at '%s'\n",
515 if (strncmp(tok
, "0x", 2) == 0) {
516 if (sscanf(tok
, "%x", &amask
) != 1) {
517 printf("ACE '%s': bad hex number at '%s'\n",
526 for (v
= standard_values
; v
->perm
; v
++) {
527 if (strcmp(tok
, v
->perm
) == 0) {
538 for (v
= special_values
; v
->perm
; v
++) {
539 if (v
->perm
[0] == *p
) {
546 printf("ACE '%s': bad permission value at '%s'\n",
563 init_sec_ace(ace
, &sid
, atype
, mask
, aflags
);
569 static void print_acl_ctrl(FILE *file
, uint16_t ctrl
, bool numeric
)
572 const char* separator
= "";
574 fprintf(file
, "CONTROL:");
576 fprintf(file
, "0x%x\n", ctrl
);
580 for (i
= ARRAY_SIZE(sec_desc_ctrl_bits
) - 1; i
>= 0; i
--) {
581 if (ctrl
& sec_desc_ctrl_bits
[i
].mask
) {
582 fprintf(file
, "%s%s",
583 separator
, sec_desc_ctrl_bits
[i
].str
);
590 /* print a ascii version of a security descriptor on a FILE handle */
591 void sec_desc_print(struct cli_state
*cli
, FILE *f
,
592 struct security_descriptor
*sd
, bool numeric
)
597 fprintf(f
, "REVISION:%d\n", sd
->revision
);
598 print_acl_ctrl(f
, sd
->type
, numeric
);
600 /* Print owner and group sid */
603 SidToString(cli
, sidstr
, sd
->owner_sid
, numeric
);
608 fprintf(f
, "OWNER:%s\n", sidstr
);
611 SidToString(cli
, sidstr
, sd
->group_sid
, numeric
);
616 fprintf(f
, "GROUP:%s\n", sidstr
);
619 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
620 struct security_ace
*ace
= &sd
->dacl
->aces
[i
];
622 print_ace(cli
, f
, ace
, numeric
);