pthreadpool: Use detached threads
[kai/samba-autobuild/.git] / source3 / lib / util_sd.c
1 /*
2    Unix SMB/CIFS implementation.
3    Security Descriptor (SD) helper functions
4
5    Copyright (C) Andrew Tridgell 2000
6    Copyright (C) Tim Potter      2000
7    Copyright (C) Jeremy Allison  2000
8    Copyright (C) Jelmer Vernooij 2003
9
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.
14
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.
19
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/>.
22 */
23
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
32 /* These values discovered by inspection */
33
34 struct perm_value {
35         const char *perm;
36         uint32_t mask;
37 };
38
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 },
47 };
48
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 },
55 };
56
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"},
78 };
79
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)
86 {
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;
95
96         status = cli_tree_connect(cli, "IPC$", "?????", "", 0);
97         if (!NT_STATUS_IS_OK(status)) {
98                 goto tcon_fail;
99         }
100
101         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
102                                           &p);
103         if (!NT_STATUS_IS_OK(status)) {
104                 goto fail;
105         }
106
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;
111         }
112
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;
117         }
118
119         *type = types[0];
120         *domain = talloc_move(mem_ctx, &domains[0]);
121         *name = talloc_move(mem_ctx, &names[0]);
122
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;
131 }
132
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)
136 {
137         char *domain = NULL;
138         char *name = NULL;
139         enum lsa_SidType type;
140         NTSTATUS status;
141
142         sid_to_fstring(str, sid);
143
144         if (numeric || cli == NULL) {
145                 return;
146         }
147
148         status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
149                                     &domain, &name);
150
151         if (!NT_STATUS_IS_OK(status)) {
152                 return;
153         }
154
155         if (*domain) {
156                 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
157                         domain, lp_winbind_separator(), name);
158         } else {
159                 fstrcpy(str, name);
160         }
161 }
162
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)
167 {
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;
175
176         status = cli_tree_connect(cli, "IPC$", "?????", "", 0);
177         if (!NT_STATUS_IS_OK(status)) {
178                 goto tcon_fail;
179         }
180
181         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
182                                           &p);
183         if (!NT_STATUS_IS_OK(status)) {
184                 goto fail;
185         }
186
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;
191         }
192
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;
197         }
198
199         *type = types[0];
200         *sid = sids[0];
201
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;
210 }
211
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)
214 {
215         enum lsa_SidType type;
216
217         if (string_to_sid(sid, str)) {
218                 return true;
219         }
220
221         if (cli == NULL) {
222                 return false;
223         }
224
225         return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli, str, &type, sid));
226 }
227
228 static void print_ace_flags(FILE *f, uint8_t flags)
229 {
230         char *str = talloc_strdup(NULL, "");
231
232         if (!str) {
233                 goto out;
234         }
235
236         if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
237                 str = talloc_asprintf(str, "%s%s",
238                                 str, "OI|");
239                 if (!str) {
240                         goto out;
241                 }
242         }
243         if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
244                 str = talloc_asprintf(str, "%s%s",
245                                 str, "CI|");
246                 if (!str) {
247                         goto out;
248                 }
249         }
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;
255                 }
256         }
257         if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
258                 str = talloc_asprintf(str, "%s%s",
259                                 str, "IO|");
260                 if (!str) {
261                         goto out;
262                 }
263         }
264         if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
265                 str = talloc_asprintf(str, "%s%s",
266                                 str, "I|");
267                 if (!str) {
268                         goto out;
269                 }
270         }
271         /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
272            and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
273            audit ace flags. */
274
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);
280         }
281         TALLOC_FREE(str);
282         return;
283
284   out:
285         fprintf(f, "/0x%x/", flags);
286 }
287
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)
291 {
292         const struct perm_value *v;
293         fstring sidstr;
294         int do_print = 0;
295         uint32_t got_mask;
296
297         SidToString(cli, sidstr, &ace->trustee, numeric);
298
299         fprintf(f, "%s:", sidstr);
300
301         if (numeric) {
302                 fprintf(f, "%d/0x%x/0x%08x",
303                         ace->type, ace->flags, ace->access_mask);
304                 return;
305         }
306
307         /* Ace type */
308
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);
315         }
316
317         print_ace_flags(f, ace->flags);
318
319         /* Standard permissions */
320
321         for (v = standard_values; v->perm; v++) {
322                 if (ace->access_mask == v->mask) {
323                         fprintf(f, "%s", v->perm);
324                         return;
325                 }
326         }
327
328         /* Special permissions.  Print out a hex value if we have
329            leftover bits in the mask. */
330
331         got_mask = ace->access_mask;
332
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);
338                         }
339                         got_mask &= ~v->mask;
340                 }
341         }
342
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;
349                 }
350         }
351 }
352
353 static bool parse_ace_flags(const char *str, unsigned int *pflags)
354 {
355         const char *p = str;
356         *pflags = 0;
357
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;
376                 }
377
378                 switch (*p) {
379                 case '|':
380                         p++;
381                 case '\0':
382                         continue;
383                 default:
384                         return false;
385                 }
386         }
387         return true;
388 }
389
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)
393 {
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();
405
406         if (!str) {
407                 TALLOC_FREE(frame);
408                 return False;
409         }
410
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;
418         }
419         *p = '\0';
420         p++;
421
422         if (!StringToSid(cli, &sid, str)) {
423                 printf("ACE '%s': failed to convert '%s' to SID\n",
424                         orig_str, str);
425                 SAFE_FREE(str);
426                 TALLOC_FREE(frame);
427                 return False;
428         }
429
430         cp = p;
431         if (!next_token_talloc(frame, &cp, &tok, "/")) {
432                 printf("ACE '%s': failed to find '/' character.\n",
433                         orig_str);
434                 SAFE_FREE(str);
435                 TALLOC_FREE(frame);
436                 return False;
437         }
438
439         if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
440                 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
441         } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
442                 atype = SEC_ACE_TYPE_ACCESS_DENIED;
443
444         } else if (strnequal(tok, "0x", 2)) {
445                 int result;
446
447                 result = sscanf(tok, "%x", &atype);
448                 if (result == 0 ||
449                     (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
450                      atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
451                         printf("ACE '%s': bad hex value for type at '%s'\n",
452                                orig_str, tok);
453                         SAFE_FREE(str);
454                         TALLOC_FREE(frame);
455                         return false;
456                 }
457         } else if(tok[0] >= '0' && tok[0] <= '9') {
458                 int result;
459
460                 result = sscanf(tok, "%u", &atype);
461                 if (result == 0 ||
462                     (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
463                      atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
464                         printf("ACE '%s': bad integer value for type at '%s'\n",
465                                orig_str, tok);
466                         SAFE_FREE(str);
467                         TALLOC_FREE(frame);
468                         return false;
469                 }
470         } else {
471                 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
472                         orig_str, tok);
473                 SAFE_FREE(str);
474                 TALLOC_FREE(frame);
475                 return False;
476         }
477
478         if (!next_token_talloc(frame, &cp, &tok, "/")) {
479                 printf("ACE '%s': bad flags entry at '%s'\n",
480                         orig_str, tok);
481                 SAFE_FREE(str);
482                 TALLOC_FREE(frame);
483                 return False;
484         }
485
486         if (tok[0] < '0' || tok[0] > '9') {
487                 if (!parse_ace_flags(tok, &aflags)) {
488                         printf("ACE '%s': bad named flags entry at '%s'\n",
489                                 orig_str, tok);
490                         SAFE_FREE(str);
491                         TALLOC_FREE(frame);
492                         return False;
493                 }
494         } else if (strnequal(tok, "0x", 2)) {
495                 if (!sscanf(tok, "%x", &aflags)) {
496                         printf("ACE '%s': bad hex flags entry at '%s'\n",
497                                 orig_str, tok);
498                         SAFE_FREE(str);
499                         TALLOC_FREE(frame);
500                         return False;
501                 }
502         } else {
503                 if (!sscanf(tok, "%u", &aflags)) {
504                         printf("ACE '%s': bad integer flags entry at '%s'\n",
505                                 orig_str, tok);
506                         SAFE_FREE(str);
507                         TALLOC_FREE(frame);
508                         return False;
509                 }
510         }
511
512         if (!next_token_talloc(frame, &cp, &tok, "/")) {
513                 printf("ACE '%s': missing / at '%s'\n",
514                         orig_str, tok);
515                 SAFE_FREE(str);
516                 TALLOC_FREE(frame);
517                 return False;
518         }
519
520         if (strncmp(tok, "0x", 2) == 0) {
521                 if (sscanf(tok, "%x", &amask) != 1) {
522                         printf("ACE '%s': bad hex number at '%s'\n",
523                                 orig_str, tok);
524                         SAFE_FREE(str);
525                         TALLOC_FREE(frame);
526                         return False;
527                 }
528                 goto done;
529         }
530
531         for (v = standard_values; v->perm; v++) {
532                 if (strcmp(tok, v->perm) == 0) {
533                         amask = v->mask;
534                         goto done;
535                 }
536         }
537
538         p = tok;
539
540         while(*p) {
541                 bool found = False;
542
543                 for (v = special_values; v->perm; v++) {
544                         if (v->perm[0] == *p) {
545                                 amask |= v->mask;
546                                 found = True;
547                         }
548                 }
549
550                 if (!found) {
551                         printf("ACE '%s': bad permission value at '%s'\n",
552                                 orig_str, p);
553                         SAFE_FREE(str);
554                         TALLOC_FREE(frame);
555                         return False;
556                 }
557                 p++;
558         }
559
560         if (*p) {
561                 TALLOC_FREE(frame);
562                 SAFE_FREE(str);
563                 return False;
564         }
565
566  done:
567         mask = amask;
568         init_sec_ace(ace, &sid, atype, mask, aflags);
569         TALLOC_FREE(frame);
570         SAFE_FREE(str);
571         return True;
572 }
573
574 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
575 {
576         int i;
577         const char* separator = "";
578
579         fprintf(file, "CONTROL:");
580         if (numeric) {
581                 fprintf(file, "0x%x\n", ctrl);
582                 return;
583         }
584
585         for (i = ARRAY_SIZE(sec_desc_ctrl_bits) - 1; i >= 0; i--) {
586                 if (ctrl & sec_desc_ctrl_bits[i].mask) {
587                         fprintf(file, "%s%s",
588                                 separator, sec_desc_ctrl_bits[i].str);
589                         separator = "|";
590                 }
591         }
592         fputc('\n', file);
593 }
594
595 /* print a ascii version of a security descriptor on a FILE handle */
596 void sec_desc_print(struct cli_state *cli, FILE *f,
597                     struct security_descriptor *sd, bool numeric)
598 {
599         fstring sidstr;
600         uint32_t i;
601
602         fprintf(f, "REVISION:%d\n", sd->revision);
603         print_acl_ctrl(f, sd->type, numeric);
604
605         /* Print owner and group sid */
606
607         if (sd->owner_sid) {
608                 SidToString(cli, sidstr, sd->owner_sid, numeric);
609         } else {
610                 fstrcpy(sidstr, "");
611         }
612
613         fprintf(f, "OWNER:%s\n", sidstr);
614
615         if (sd->group_sid) {
616                 SidToString(cli, sidstr, sd->group_sid, numeric);
617         } else {
618                 fstrcpy(sidstr, "");
619         }
620
621         fprintf(f, "GROUP:%s\n", sidstr);
622
623         /* Print aces */
624         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
625                 struct security_ace *ace = &sd->dacl->aces[i];
626                 fprintf(f, "ACL:");
627                 print_ace(cli, f, ace, numeric);
628                 fprintf(f, "\n");
629         }
630
631 }