nfs4acls: Introduce a helper variable
[Samba.git] / source3 / lib / util_sd.c
blob8065a0fbd1a4e6f9a27a80627a81afe928deb830
1 /*
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/>.
24 #include "includes.h"
25 #include "libsmb/libsmb.h"
26 #include "util_sd.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 */
34 struct perm_value {
35 const char *perm;
36 uint32_t mask;
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 },
46 { NULL, 0 },
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 },
54 { NULL, 0 },
57 static const struct {
58 uint16_t mask;
59 const char *str;
60 const char *desc;
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,
83 TALLOC_CTX *mem_ctx,
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;
90 NTSTATUS status;
91 TALLOC_CTX *frame = talloc_stackframe();
92 enum lsa_SidType *types;
93 char **domains;
94 char **names;
96 status = cli_tree_connect(cli, "IPC$", "?????", "", 0);
97 if (!NT_STATUS_IS_OK(status)) {
98 goto tcon_fail;
101 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
102 &p);
103 if (!NT_STATUS_IS_OK(status)) {
104 goto fail;
107 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
108 GENERIC_EXECUTE_ACCESS, &handle);
109 if (!NT_STATUS_IS_OK(status)) {
110 goto fail;
113 status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
114 &domains, &names, &types);
115 if (!NT_STATUS_IS_OK(status)) {
116 goto fail;
119 *type = types[0];
120 *domain = talloc_move(mem_ctx, &domains[0]);
121 *name = talloc_move(mem_ctx, &names[0]);
123 status = NT_STATUS_OK;
124 fail:
125 TALLOC_FREE(p);
126 cli_tdis(cli);
127 tcon_fail:
128 cli_state_set_tid(cli, orig_cnum);
129 TALLOC_FREE(frame);
130 return status;
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,
135 bool numeric)
137 char *domain = NULL;
138 char *name = NULL;
139 enum lsa_SidType type;
140 NTSTATUS status;
142 sid_to_fstring(str, sid);
144 if (numeric || cli == NULL) {
145 return;
148 status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
149 &domain, &name);
151 if (!NT_STATUS_IS_OK(status)) {
152 return;
155 if (*domain) {
156 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
157 domain, lp_winbind_separator(), name);
158 } else {
159 fstrcpy(str, name);
163 static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
164 const char *name,
165 enum lsa_SidType *type,
166 struct dom_sid *sid)
168 uint16_t orig_cnum = cli_state_get_tid(cli);
169 struct rpc_pipe_client *p;
170 struct policy_handle handle;
171 NTSTATUS status;
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)) {
178 goto tcon_fail;
181 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
182 &p);
183 if (!NT_STATUS_IS_OK(status)) {
184 goto fail;
187 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
188 GENERIC_EXECUTE_ACCESS, &handle);
189 if (!NT_STATUS_IS_OK(status)) {
190 goto fail;
193 status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
194 NULL, 1, &sids, &types);
195 if (!NT_STATUS_IS_OK(status)) {
196 goto fail;
199 *type = types[0];
200 *sid = sids[0];
202 status = NT_STATUS_OK;
203 fail:
204 TALLOC_FREE(p);
205 cli_tdis(cli);
206 tcon_fail:
207 cli_state_set_tid(cli, orig_cnum);
208 TALLOC_FREE(frame);
209 return status;
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)) {
218 return true;
221 if (cli == NULL) {
222 return false;
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, "");
232 if (!str) {
233 goto out;
236 if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
237 str = talloc_asprintf(str, "%s%s",
238 str, "OI|");
239 if (!str) {
240 goto out;
243 if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
244 str = talloc_asprintf(str, "%s%s",
245 str, "CI|");
246 if (!str) {
247 goto out;
250 if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
251 str = talloc_asprintf(str, "%s%s",
252 str, "NP|");
253 if (!str) {
254 goto out;
257 if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
258 str = talloc_asprintf(str, "%s%s",
259 str, "IO|");
260 if (!str) {
261 goto out;
264 if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
265 str = talloc_asprintf(str, "%s%s",
266 str, "I|");
267 if (!str) {
268 goto out;
271 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
272 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
273 audit ace flags. */
275 if (str[strlen(str)-1] == '|') {
276 str[strlen(str)-1] = '\0';
277 fprintf(f, "/%s/", str);
278 } else {
279 fprintf(f, "/0x%x/", flags);
281 TALLOC_FREE(str);
282 return;
284 out:
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,
290 bool numeric)
292 const struct perm_value *v;
293 fstring sidstr;
294 int do_print = 0;
295 uint32_t got_mask;
297 SidToString(cli, sidstr, &ace->trustee, numeric);
299 fprintf(f, "%s:", sidstr);
301 if (numeric) {
302 fprintf(f, "%d/0x%x/0x%08x",
303 ace->type, ace->flags, ace->access_mask);
304 return;
307 /* Ace type */
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");
313 } else {
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);
324 return;
328 /* Special permissions. Print out a hex value if we have
329 leftover bits in the mask. */
331 got_mask = ace->access_mask;
333 again:
334 for (v = special_values; v->perm; v++) {
335 if ((ace->access_mask & v->mask) == v->mask) {
336 if (do_print) {
337 fprintf(f, "%s", v->perm);
339 got_mask &= ~v->mask;
343 if (!do_print) {
344 if (got_mask != 0) {
345 fprintf(f, "0x%08x", ace->access_mask);
346 } else {
347 do_print = 1;
348 goto again;
353 static bool parse_ace_flags(const char *str, unsigned int *pflags)
355 const char *p = str;
356 *pflags = 0;
358 while (*p) {
359 if (strnequal(p, "OI", 2)) {
360 *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT;
361 p += 2;
362 } else if (strnequal(p, "CI", 2)) {
363 *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
364 p += 2;
365 } else if (strnequal(p, "NP", 2)) {
366 *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
367 p += 2;
368 } else if (strnequal(p, "IO", 2)) {
369 *pflags |= SEC_ACE_FLAG_INHERIT_ONLY;
370 p += 2;
371 } else if (*p == 'I') {
372 *pflags |= SEC_ACE_FLAG_INHERITED_ACE;
373 p += 1;
374 } else if (*p) {
375 return false;
378 switch (*p) {
379 case '|':
380 p++;
381 case '\0':
382 continue;
383 default:
384 return false;
387 return true;
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)
394 char *p;
395 const char *cp;
396 char *tok;
397 unsigned int atype = 0;
398 unsigned int aflags = 0;
399 unsigned int amask = 0;
400 struct dom_sid sid;
401 uint32_t mask;
402 const struct perm_value *v;
403 char *str = SMB_STRDUP(orig_str);
404 TALLOC_CTX *frame = talloc_stackframe();
406 if (!str) {
407 TALLOC_FREE(frame);
408 return False;
411 ZERO_STRUCTP(ace);
412 p = strchr_m(str,':');
413 if (!p) {
414 printf("ACE '%s': missing ':'.\n", orig_str);
415 SAFE_FREE(str);
416 TALLOC_FREE(frame);
417 return False;
419 *p = '\0';
420 p++;
421 /* Try to parse numeric form */
423 if (sscanf(p, "%u/%u/%u", &atype, &aflags, &amask) == 3 &&
424 StringToSid(cli, &sid, str)) {
425 goto done;
428 /* Try to parse text form */
430 if (!StringToSid(cli, &sid, str)) {
431 printf("ACE '%s': failed to convert '%s' to SID\n",
432 orig_str, str);
433 SAFE_FREE(str);
434 TALLOC_FREE(frame);
435 return False;
438 cp = p;
439 if (!next_token_talloc(frame, &cp, &tok, "/")) {
440 printf("ACE '%s': failed to find '/' character.\n",
441 orig_str);
442 SAFE_FREE(str);
443 TALLOC_FREE(frame);
444 return False;
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;
451 } else {
452 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
453 orig_str, tok);
454 SAFE_FREE(str);
455 TALLOC_FREE(frame);
456 return False;
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",
463 orig_str, tok);
464 SAFE_FREE(str);
465 TALLOC_FREE(frame);
466 return False;
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",
472 orig_str, tok);
473 SAFE_FREE(str);
474 TALLOC_FREE(frame);
475 return False;
477 } else if (strnequal(tok, "0x", 2)) {
478 if (!sscanf(tok, "%x", &aflags)) {
479 printf("ACE '%s': bad hex flags entry at '%s'\n",
480 orig_str, tok);
481 SAFE_FREE(str);
482 TALLOC_FREE(frame);
483 return False;
485 } else {
486 if (!sscanf(tok, "%u", &aflags)) {
487 printf("ACE '%s': bad integer flags entry at '%s'\n",
488 orig_str, tok);
489 SAFE_FREE(str);
490 TALLOC_FREE(frame);
491 return False;
495 if (!next_token_talloc(frame, &cp, &tok, "/")) {
496 printf("ACE '%s': missing / at '%s'\n",
497 orig_str, tok);
498 SAFE_FREE(str);
499 TALLOC_FREE(frame);
500 return False;
503 if (strncmp(tok, "0x", 2) == 0) {
504 if (sscanf(tok, "%x", &amask) != 1) {
505 printf("ACE '%s': bad hex number at '%s'\n",
506 orig_str, tok);
507 SAFE_FREE(str);
508 TALLOC_FREE(frame);
509 return False;
511 goto done;
514 for (v = standard_values; v->perm; v++) {
515 if (strcmp(tok, v->perm) == 0) {
516 amask = v->mask;
517 goto done;
521 p = tok;
523 while(*p) {
524 bool found = False;
526 for (v = special_values; v->perm; v++) {
527 if (v->perm[0] == *p) {
528 amask |= v->mask;
529 found = True;
533 if (!found) {
534 printf("ACE '%s': bad permission value at '%s'\n",
535 orig_str, p);
536 SAFE_FREE(str);
537 TALLOC_FREE(frame);
538 return False;
540 p++;
543 if (*p) {
544 TALLOC_FREE(frame);
545 SAFE_FREE(str);
546 return False;
549 done:
550 mask = amask;
551 init_sec_ace(ace, &sid, atype, mask, aflags);
552 TALLOC_FREE(frame);
553 SAFE_FREE(str);
554 return True;
557 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
559 int i;
560 const char* separator = "";
562 fprintf(file, "CONTROL:");
563 if (numeric) {
564 fprintf(file, "0x%x\n", ctrl);
565 return;
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);
572 separator = "|";
575 fputc('\n', file);
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)
582 fstring sidstr;
583 uint32_t i;
585 fprintf(f, "REVISION:%d\n", sd->revision);
586 print_acl_ctrl(f, sd->type, numeric);
588 /* Print owner and group sid */
590 if (sd->owner_sid) {
591 SidToString(cli, sidstr, sd->owner_sid, numeric);
592 } else {
593 fstrcpy(sidstr, "");
596 fprintf(f, "OWNER:%s\n", sidstr);
598 if (sd->group_sid) {
599 SidToString(cli, sidstr, sd->group_sid, numeric);
600 } else {
601 fstrcpy(sidstr, "");
604 fprintf(f, "GROUP:%s\n", sidstr);
606 /* Print aces */
607 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
608 struct security_ace *ace = &sd->dacl->aces[i];
609 fprintf(f, "ACL:");
610 print_ace(cli, f, ace, numeric);
611 fprintf(f, "\n");