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 struct smbXcli_tcon
*orig_tcon
= NULL
;
88 struct rpc_pipe_client
*p
= NULL
;
89 struct policy_handle handle
;
91 TALLOC_CTX
*frame
= talloc_stackframe();
92 enum lsa_SidType
*types
;
96 if (cli_state_has_tcon(cli
)) {
97 orig_tcon
= cli_state_save_tcon(cli
);
98 if (orig_tcon
== NULL
) {
99 status
= NT_STATUS_NO_MEMORY
;
104 status
= cli_tree_connect(cli
, "IPC$", "?????", NULL
);
105 if (!NT_STATUS_IS_OK(status
)) {
109 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_lsarpc
,
111 if (!NT_STATUS_IS_OK(status
)) {
115 status
= rpccli_lsa_open_policy(p
, talloc_tos(), True
,
116 GENERIC_EXECUTE_ACCESS
, &handle
);
117 if (!NT_STATUS_IS_OK(status
)) {
121 status
= rpccli_lsa_lookup_sids(p
, talloc_tos(), &handle
, 1, sid
,
122 &domains
, &names
, &types
);
123 if (!NT_STATUS_IS_OK(status
)) {
128 *domain
= talloc_move(mem_ctx
, &domains
[0]);
129 *name
= talloc_move(mem_ctx
, &names
[0]);
131 status
= NT_STATUS_OK
;
136 cli_state_restore_tcon(cli
, orig_tcon
);
141 /* convert a SID to a string, either numeric or username/group */
142 void SidToString(struct cli_state
*cli
, fstring str
, const struct dom_sid
*sid
,
147 enum lsa_SidType type
;
150 sid_to_fstring(str
, sid
);
152 if (numeric
|| cli
== NULL
) {
156 status
= cli_lsa_lookup_sid(cli
, sid
, talloc_tos(), &type
,
159 if (!NT_STATUS_IS_OK(status
)) {
164 slprintf(str
, sizeof(fstring
) - 1, "%s%s%s",
165 domain
, lp_winbind_separator(), name
);
171 static NTSTATUS
cli_lsa_lookup_name(struct cli_state
*cli
,
173 enum lsa_SidType
*type
,
176 struct smbXcli_tcon
*orig_tcon
= NULL
;
177 struct rpc_pipe_client
*p
;
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 orig_tcon
= cli_state_save_tcon(cli
);
186 if (orig_tcon
== NULL
) {
187 status
= NT_STATUS_NO_MEMORY
;
192 status
= cli_tree_connect(cli
, "IPC$", "?????", NULL
);
193 if (!NT_STATUS_IS_OK(status
)) {
197 status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_lsarpc
,
199 if (!NT_STATUS_IS_OK(status
)) {
203 status
= rpccli_lsa_open_policy(p
, talloc_tos(), True
,
204 GENERIC_EXECUTE_ACCESS
, &handle
);
205 if (!NT_STATUS_IS_OK(status
)) {
209 status
= rpccli_lsa_lookup_names(p
, talloc_tos(), &handle
, 1, &name
,
210 NULL
, 1, &sids
, &types
);
211 if (!NT_STATUS_IS_OK(status
)) {
218 status
= NT_STATUS_OK
;
223 cli_state_restore_tcon(cli
, orig_tcon
);
228 /* convert a string to a SID, either numeric or username/group */
229 bool StringToSid(struct cli_state
*cli
, struct dom_sid
*sid
, const char *str
)
231 enum lsa_SidType type
;
233 if (string_to_sid(sid
, str
)) {
241 return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli
, str
, &type
, sid
));
244 static void print_ace_flags(FILE *f
, uint8_t flags
)
246 char *str
= talloc_strdup(NULL
, "");
252 if (flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) {
253 str
= talloc_asprintf(str
, "%s%s",
259 if (flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
260 str
= talloc_asprintf(str
, "%s%s",
266 if (flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
267 str
= talloc_asprintf(str
, "%s%s",
273 if (flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
274 str
= talloc_asprintf(str
, "%s%s",
280 if (flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
281 str
= talloc_asprintf(str
, "%s%s",
287 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
288 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
291 if (str
[strlen(str
)-1] == '|') {
292 str
[strlen(str
)-1] = '\0';
293 fprintf(f
, "/%s/", str
);
295 fprintf(f
, "/0x%x/", flags
);
301 fprintf(f
, "/0x%x/", flags
);
304 /* print an ACE on a FILE, using either numeric or ascii representation */
305 void print_ace(struct cli_state
*cli
, FILE *f
, struct security_ace
*ace
,
308 const struct perm_value
*v
;
313 SidToString(cli
, sidstr
, &ace
->trustee
, numeric
);
315 fprintf(f
, "%s:", sidstr
);
318 fprintf(f
, "%d/0x%x/0x%08x",
319 ace
->type
, ace
->flags
, ace
->access_mask
);
325 if (ace
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED
) {
326 fprintf(f
, "ALLOWED");
327 } else if (ace
->type
== SEC_ACE_TYPE_ACCESS_DENIED
) {
328 fprintf(f
, "DENIED");
330 fprintf(f
, "%d", ace
->type
);
333 print_ace_flags(f
, ace
->flags
);
335 /* Standard permissions */
337 for (v
= standard_values
; v
->perm
; v
++) {
338 if (ace
->access_mask
== v
->mask
) {
339 fprintf(f
, "%s", v
->perm
);
344 /* Special permissions. Print out a hex value if we have
345 leftover bits in the mask. */
347 got_mask
= ace
->access_mask
;
350 for (v
= special_values
; v
->perm
; v
++) {
351 if ((ace
->access_mask
& v
->mask
) == v
->mask
) {
353 fprintf(f
, "%s", v
->perm
);
355 got_mask
&= ~v
->mask
;
361 fprintf(f
, "0x%08x", ace
->access_mask
);
369 static bool parse_ace_flags(const char *str
, unsigned int *pflags
)
375 if (strnequal(p
, "OI", 2)) {
376 *pflags
|= SEC_ACE_FLAG_OBJECT_INHERIT
;
378 } else if (strnequal(p
, "CI", 2)) {
379 *pflags
|= SEC_ACE_FLAG_CONTAINER_INHERIT
;
381 } else if (strnequal(p
, "NP", 2)) {
382 *pflags
|= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
;
384 } else if (strnequal(p
, "IO", 2)) {
385 *pflags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
387 } else if (*p
== 'I') {
388 *pflags
|= SEC_ACE_FLAG_INHERITED_ACE
;
406 /* parse an ACE in the same format as print_ace() */
407 bool parse_ace(struct cli_state
*cli
, struct security_ace
*ace
,
408 const char *orig_str
)
413 unsigned int atype
= 0;
414 unsigned int aflags
= 0;
415 unsigned int amask
= 0;
418 const struct perm_value
*v
;
419 char *str
= SMB_STRDUP(orig_str
);
420 TALLOC_CTX
*frame
= talloc_stackframe();
428 p
= strchr_m(str
,':');
430 printf("ACE '%s': missing ':'.\n", orig_str
);
438 if (!StringToSid(cli
, &sid
, str
)) {
439 printf("ACE '%s': failed to convert '%s' to SID\n",
447 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
448 printf("ACE '%s': failed to find '/' character.\n",
455 if (strncmp(tok
, "ALLOWED", strlen("ALLOWED")) == 0) {
456 atype
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
457 } else if (strncmp(tok
, "DENIED", strlen("DENIED")) == 0) {
458 atype
= SEC_ACE_TYPE_ACCESS_DENIED
;
460 } else if (strnequal(tok
, "0x", 2)) {
463 result
= sscanf(tok
, "%x", &atype
);
465 (atype
!= SEC_ACE_TYPE_ACCESS_ALLOWED
&&
466 atype
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
467 printf("ACE '%s': bad hex value for type at '%s'\n",
473 } else if(tok
[0] >= '0' && tok
[0] <= '9') {
476 result
= sscanf(tok
, "%u", &atype
);
478 (atype
!= SEC_ACE_TYPE_ACCESS_ALLOWED
&&
479 atype
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
480 printf("ACE '%s': bad integer value for type at '%s'\n",
487 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
494 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
495 printf("ACE '%s': bad flags entry at '%s'\n",
502 if (tok
[0] < '0' || tok
[0] > '9') {
503 if (!parse_ace_flags(tok
, &aflags
)) {
504 printf("ACE '%s': bad named flags entry at '%s'\n",
510 } else if (strnequal(tok
, "0x", 2)) {
511 if (!sscanf(tok
, "%x", &aflags
)) {
512 printf("ACE '%s': bad hex flags entry at '%s'\n",
519 if (!sscanf(tok
, "%u", &aflags
)) {
520 printf("ACE '%s': bad integer flags entry at '%s'\n",
528 if (!next_token_talloc(frame
, &cp
, &tok
, "/")) {
529 printf("ACE '%s': missing / at '%s'\n",
536 if (strncmp(tok
, "0x", 2) == 0) {
537 if (sscanf(tok
, "%x", &amask
) != 1) {
538 printf("ACE '%s': bad hex number at '%s'\n",
547 for (v
= standard_values
; v
->perm
; v
++) {
548 if (strcmp(tok
, v
->perm
) == 0) {
559 for (v
= special_values
; v
->perm
; v
++) {
560 if (v
->perm
[0] == *p
) {
567 printf("ACE '%s': bad permission value at '%s'\n",
584 init_sec_ace(ace
, &sid
, atype
, mask
, aflags
);
590 static void print_acl_ctrl(FILE *file
, uint16_t ctrl
, bool numeric
)
593 const char* separator
= "";
595 fprintf(file
, "CONTROL:");
597 fprintf(file
, "0x%x\n", ctrl
);
601 for (i
= ARRAY_SIZE(sec_desc_ctrl_bits
) - 1; i
>= 0; i
--) {
602 if (ctrl
& sec_desc_ctrl_bits
[i
].mask
) {
603 fprintf(file
, "%s%s",
604 separator
, sec_desc_ctrl_bits
[i
].str
);
611 /* print a ascii version of a security descriptor on a FILE handle */
612 void sec_desc_print(struct cli_state
*cli
, FILE *f
,
613 struct security_descriptor
*sd
, bool numeric
)
618 fprintf(f
, "REVISION:%d\n", sd
->revision
);
619 print_acl_ctrl(f
, sd
->type
, numeric
);
621 /* Print owner and group sid */
624 SidToString(cli
, sidstr
, sd
->owner_sid
, numeric
);
629 fprintf(f
, "OWNER:%s\n", sidstr
);
632 SidToString(cli
, sidstr
, sd
->group_sid
, numeric
);
637 fprintf(f
, "GROUP:%s\n", sidstr
);
640 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
641 struct security_ace
*ace
= &sd
->dacl
->aces
[i
];
643 print_ace(cli
, f
, ace
, numeric
);