nsswitch: explicitly mark nss_module_register() _PUBLIC_ on FreeBSD
[Samba.git] / source3 / lib / util_sd.c
blobd90d566cdb208f5acaed452875ab8f86249b26da
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"
31 #include "lib/util/string_wrappers.h"
33 /* These values discovered by inspection */
35 struct perm_value {
36 const char *perm;
37 uint32_t mask;
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 },
47 { NULL, 0 },
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 },
55 { NULL, 0 },
58 static const struct {
59 uint16_t mask;
60 const char *str;
61 const char *desc;
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,
84 TALLOC_CTX *mem_ctx,
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;
91 NTSTATUS status;
92 TALLOC_CTX *frame = talloc_stackframe();
93 enum lsa_SidType *types;
94 char **domains;
95 char **names;
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;
101 goto tcon_fail;
105 status = cli_tree_connect(cli, "IPC$", "?????", NULL);
106 if (!NT_STATUS_IS_OK(status)) {
107 goto tcon_fail;
110 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
111 &p);
112 if (!NT_STATUS_IS_OK(status)) {
113 goto fail;
116 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
117 GENERIC_EXECUTE_ACCESS, &handle);
118 if (!NT_STATUS_IS_OK(status)) {
119 goto fail;
122 status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
123 &domains, &names, &types);
124 if (!NT_STATUS_IS_OK(status)) {
125 goto fail;
128 *type = types[0];
129 *domain = talloc_move(mem_ctx, &domains[0]);
130 *name = talloc_move(mem_ctx, &names[0]);
132 status = NT_STATUS_OK;
133 fail:
134 TALLOC_FREE(p);
135 cli_tdis(cli);
136 tcon_fail:
137 cli_state_restore_tcon(cli, orig_tcon);
138 TALLOC_FREE(frame);
139 return status;
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,
144 bool numeric)
146 char *domain = NULL;
147 char *name = NULL;
148 enum lsa_SidType type;
149 NTSTATUS status;
151 sid_to_fstring(str, sid);
153 if (numeric || cli == NULL) {
154 return;
157 status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
158 &domain, &name);
160 if (!NT_STATUS_IS_OK(status)) {
161 return;
164 if (*domain) {
165 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
166 domain, lp_winbind_separator(), name);
167 } else {
168 fstrcpy(str, name);
172 static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
173 const char *name,
174 enum lsa_SidType *type,
175 struct dom_sid *sid)
177 struct smbXcli_tcon *orig_tcon = NULL;
178 struct rpc_pipe_client *p = NULL;
179 struct policy_handle handle;
180 NTSTATUS status;
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;
189 goto tcon_fail;
193 status = cli_tree_connect(cli, "IPC$", "?????", NULL);
194 if (!NT_STATUS_IS_OK(status)) {
195 goto tcon_fail;
198 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
199 &p);
200 if (!NT_STATUS_IS_OK(status)) {
201 goto fail;
204 status = rpccli_lsa_open_policy(p, talloc_tos(), True,
205 GENERIC_EXECUTE_ACCESS, &handle);
206 if (!NT_STATUS_IS_OK(status)) {
207 goto fail;
210 status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
211 NULL, 1, &sids, &types);
212 if (!NT_STATUS_IS_OK(status)) {
213 goto fail;
216 *type = types[0];
217 *sid = sids[0];
219 status = NT_STATUS_OK;
220 fail:
221 TALLOC_FREE(p);
222 cli_tdis(cli);
223 tcon_fail:
224 cli_state_restore_tcon(cli, orig_tcon);
225 TALLOC_FREE(frame);
226 return status;
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)) {
235 return true;
238 if (cli == NULL) {
239 return false;
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, "");
249 if (!str) {
250 goto out;
253 if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
254 str = talloc_asprintf(str, "%s%s",
255 str, "OI|");
256 if (!str) {
257 goto out;
260 if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
261 str = talloc_asprintf(str, "%s%s",
262 str, "CI|");
263 if (!str) {
264 goto out;
267 if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
268 str = talloc_asprintf(str, "%s%s",
269 str, "NP|");
270 if (!str) {
271 goto out;
274 if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
275 str = talloc_asprintf(str, "%s%s",
276 str, "IO|");
277 if (!str) {
278 goto out;
281 if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
282 str = talloc_asprintf(str, "%s%s",
283 str, "I|");
284 if (!str) {
285 goto out;
288 /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
289 and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
290 audit ace flags. */
292 if (str[strlen(str)-1] == '|') {
293 str[strlen(str)-1] = '\0';
294 fprintf(f, "/%s/", str);
295 } else {
296 fprintf(f, "/0x%x/", flags);
298 TALLOC_FREE(str);
299 return;
301 out:
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,
307 bool numeric)
309 const struct perm_value *v;
310 fstring sidstr;
311 int do_print = 0;
312 uint32_t got_mask;
314 SidToString(cli, sidstr, &ace->trustee, numeric);
316 fprintf(f, "%s:", sidstr);
318 if (numeric) {
319 fprintf(f, "%d/0x%x/0x%08x",
320 ace->type, ace->flags, ace->access_mask);
321 return;
324 /* Ace type */
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");
330 } else {
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);
341 return;
345 /* Special permissions. Print out a hex value if we have
346 leftover bits in the mask. */
348 got_mask = ace->access_mask;
350 again:
351 for (v = special_values; v->perm; v++) {
352 if ((ace->access_mask & v->mask) == v->mask) {
353 if (do_print) {
354 fprintf(f, "%s", v->perm);
356 got_mask &= ~v->mask;
360 if (!do_print) {
361 if (got_mask != 0) {
362 fprintf(f, "0x%08x", ace->access_mask);
363 } else {
364 do_print = 1;
365 goto again;
370 static bool parse_ace_flags(const char *str, unsigned int *pflags)
372 const char *p = str;
373 *pflags = 0;
375 while (*p) {
376 if (strnequal(p, "OI", 2)) {
377 *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT;
378 p += 2;
379 } else if (strnequal(p, "CI", 2)) {
380 *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
381 p += 2;
382 } else if (strnequal(p, "NP", 2)) {
383 *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
384 p += 2;
385 } else if (strnequal(p, "IO", 2)) {
386 *pflags |= SEC_ACE_FLAG_INHERIT_ONLY;
387 p += 2;
388 } else if (*p == 'I') {
389 *pflags |= SEC_ACE_FLAG_INHERITED_ACE;
390 p += 1;
391 } else if (*p) {
392 return false;
395 switch (*p) {
396 case '|':
397 p++;
399 FALL_THROUGH;
400 case '\0':
401 continue;
402 default:
403 return false;
406 return true;
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)
413 char *p;
414 const char *cp;
415 char *tok;
416 unsigned int atype = 0;
417 unsigned int aflags = 0;
418 unsigned int amask = 0;
419 struct dom_sid sid;
420 uint32_t mask;
421 const struct perm_value *v;
422 char *str = SMB_STRDUP(orig_str);
423 TALLOC_CTX *frame = talloc_stackframe();
425 if (!str) {
426 TALLOC_FREE(frame);
427 return False;
430 ZERO_STRUCTP(ace);
431 p = strchr_m(str,':');
432 if (!p) {
433 printf("ACE '%s': missing ':'.\n", orig_str);
434 SAFE_FREE(str);
435 TALLOC_FREE(frame);
436 return False;
438 *p = '\0';
439 p++;
441 if (!StringToSid(cli, &sid, str)) {
442 printf("ACE '%s': failed to convert '%s' to SID\n",
443 orig_str, str);
444 SAFE_FREE(str);
445 TALLOC_FREE(frame);
446 return False;
449 cp = p;
450 if (!next_token_talloc(frame, &cp, &tok, "/")) {
451 printf("ACE '%s': failed to find '/' character.\n",
452 orig_str);
453 SAFE_FREE(str);
454 TALLOC_FREE(frame);
455 return False;
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)) {
464 int result;
466 result = sscanf(tok, "%x", &atype);
467 if (result == 0 ||
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",
471 orig_str, tok);
472 SAFE_FREE(str);
473 TALLOC_FREE(frame);
474 return false;
476 } else if(tok[0] >= '0' && tok[0] <= '9') {
477 int result;
479 result = sscanf(tok, "%u", &atype);
480 if (result == 0 ||
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",
484 orig_str, tok);
485 SAFE_FREE(str);
486 TALLOC_FREE(frame);
487 return false;
489 } else {
490 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
491 orig_str, tok);
492 SAFE_FREE(str);
493 TALLOC_FREE(frame);
494 return False;
497 if (!next_token_talloc(frame, &cp, &tok, "/")) {
498 printf("ACE '%s': bad flags entry at '%s'\n",
499 orig_str, tok);
500 SAFE_FREE(str);
501 TALLOC_FREE(frame);
502 return False;
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",
508 orig_str, tok);
509 SAFE_FREE(str);
510 TALLOC_FREE(frame);
511 return False;
513 } else if (strnequal(tok, "0x", 2)) {
514 if (!sscanf(tok, "%x", &aflags)) {
515 printf("ACE '%s': bad hex flags entry at '%s'\n",
516 orig_str, tok);
517 SAFE_FREE(str);
518 TALLOC_FREE(frame);
519 return False;
521 } else {
522 if (!sscanf(tok, "%u", &aflags)) {
523 printf("ACE '%s': bad integer flags entry at '%s'\n",
524 orig_str, tok);
525 SAFE_FREE(str);
526 TALLOC_FREE(frame);
527 return False;
531 if (!next_token_talloc(frame, &cp, &tok, "/")) {
532 printf("ACE '%s': missing / at '%s'\n",
533 orig_str, tok);
534 SAFE_FREE(str);
535 TALLOC_FREE(frame);
536 return False;
539 if (strncmp(tok, "0x", 2) == 0) {
540 if (sscanf(tok, "%x", &amask) != 1) {
541 printf("ACE '%s': bad hex number at '%s'\n",
542 orig_str, tok);
543 SAFE_FREE(str);
544 TALLOC_FREE(frame);
545 return False;
547 goto done;
550 for (v = standard_values; v->perm; v++) {
551 if (strcmp(tok, v->perm) == 0) {
552 amask = v->mask;
553 goto done;
557 p = tok;
559 while(*p) {
560 bool found = False;
562 for (v = special_values; v->perm; v++) {
563 if (v->perm[0] == *p) {
564 amask |= v->mask;
565 found = True;
569 if (!found) {
570 printf("ACE '%s': bad permission value at '%s'\n",
571 orig_str, p);
572 SAFE_FREE(str);
573 TALLOC_FREE(frame);
574 return False;
576 p++;
579 if (*p) {
580 TALLOC_FREE(frame);
581 SAFE_FREE(str);
582 return False;
585 done:
586 mask = amask;
587 init_sec_ace(ace, &sid, atype, mask, aflags);
588 TALLOC_FREE(frame);
589 SAFE_FREE(str);
590 return True;
593 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
595 int i;
596 const char* separator = "";
598 fprintf(file, "CONTROL:");
599 if (numeric) {
600 fprintf(file, "0x%x\n", ctrl);
601 return;
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);
608 separator = "|";
611 fputc('\n', file);
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)
618 fstring sidstr;
619 uint32_t i;
621 fprintf(f, "REVISION:%d\n", sd->revision);
622 print_acl_ctrl(f, sd->type, numeric);
624 /* Print owner and group sid */
626 if (sd->owner_sid) {
627 SidToString(cli, sidstr, sd->owner_sid, numeric);
628 } else {
629 fstrcpy(sidstr, "");
632 fprintf(f, "OWNER:%s\n", sidstr);
634 if (sd->group_sid) {
635 SidToString(cli, sidstr, sd->group_sid, numeric);
636 } else {
637 fstrcpy(sidstr, "");
640 fprintf(f, "GROUP:%s\n", sidstr);
642 /* Print aces */
643 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
644 struct security_ace *ace = &sd->dacl->aces[i];
645 fprintf(f, "ACL:");
646 print_ace(cli, f, ace, numeric);
647 fprintf(f, "\n");