pyldb: avoid segfault when adding an element with no name
[kamenim/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         struct smbXcli_tcon *orig_tcon = NULL;
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         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;
100                         goto tcon_fail;
101                 }
102         }
103
104         status = cli_tree_connect(cli, "IPC$", "?????", NULL);
105         if (!NT_STATUS_IS_OK(status)) {
106                 goto tcon_fail;
107         }
108
109         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
110                                           &p);
111         if (!NT_STATUS_IS_OK(status)) {
112                 goto fail;
113         }
114
115         status = rpccli_lsa_open_policy(p, talloc_tos(), True,
116                                         GENERIC_EXECUTE_ACCESS, &handle);
117         if (!NT_STATUS_IS_OK(status)) {
118                 goto fail;
119         }
120
121         status = rpccli_lsa_lookup_sids(p, talloc_tos(), &handle, 1, sid,
122                                         &domains, &names, &types);
123         if (!NT_STATUS_IS_OK(status)) {
124                 goto fail;
125         }
126
127         *type = types[0];
128         *domain = talloc_move(mem_ctx, &domains[0]);
129         *name = talloc_move(mem_ctx, &names[0]);
130
131         status = NT_STATUS_OK;
132  fail:
133         TALLOC_FREE(p);
134         cli_tdis(cli);
135  tcon_fail:
136         cli_state_restore_tcon(cli, orig_tcon);
137         TALLOC_FREE(frame);
138         return status;
139 }
140
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,
143                  bool numeric)
144 {
145         char *domain = NULL;
146         char *name = NULL;
147         enum lsa_SidType type;
148         NTSTATUS status;
149
150         sid_to_fstring(str, sid);
151
152         if (numeric || cli == NULL) {
153                 return;
154         }
155
156         status = cli_lsa_lookup_sid(cli, sid, talloc_tos(), &type,
157                                     &domain, &name);
158
159         if (!NT_STATUS_IS_OK(status)) {
160                 return;
161         }
162
163         if (*domain) {
164                 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
165                         domain, lp_winbind_separator(), name);
166         } else {
167                 fstrcpy(str, name);
168         }
169 }
170
171 static NTSTATUS cli_lsa_lookup_name(struct cli_state *cli,
172                                     const char *name,
173                                     enum lsa_SidType *type,
174                                     struct dom_sid *sid)
175 {
176         struct smbXcli_tcon *orig_tcon = NULL;
177         struct rpc_pipe_client *p;
178         struct policy_handle handle;
179         NTSTATUS status;
180         TALLOC_CTX *frame = talloc_stackframe();
181         struct dom_sid *sids;
182         enum lsa_SidType *types;
183
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;
188                         goto tcon_fail;
189                 }
190         }
191
192         status = cli_tree_connect(cli, "IPC$", "?????", NULL);
193         if (!NT_STATUS_IS_OK(status)) {
194                 goto tcon_fail;
195         }
196
197         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc,
198                                           &p);
199         if (!NT_STATUS_IS_OK(status)) {
200                 goto fail;
201         }
202
203         status = rpccli_lsa_open_policy(p, talloc_tos(), True,
204                                         GENERIC_EXECUTE_ACCESS, &handle);
205         if (!NT_STATUS_IS_OK(status)) {
206                 goto fail;
207         }
208
209         status = rpccli_lsa_lookup_names(p, talloc_tos(), &handle, 1, &name,
210                                          NULL, 1, &sids, &types);
211         if (!NT_STATUS_IS_OK(status)) {
212                 goto fail;
213         }
214
215         *type = types[0];
216         *sid = sids[0];
217
218         status = NT_STATUS_OK;
219  fail:
220         TALLOC_FREE(p);
221         cli_tdis(cli);
222  tcon_fail:
223         cli_state_restore_tcon(cli, orig_tcon);
224         TALLOC_FREE(frame);
225         return status;
226 }
227
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)
230 {
231         enum lsa_SidType type;
232
233         if (string_to_sid(sid, str)) {
234                 return true;
235         }
236
237         if (cli == NULL) {
238                 return false;
239         }
240
241         return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli, str, &type, sid));
242 }
243
244 static void print_ace_flags(FILE *f, uint8_t flags)
245 {
246         char *str = talloc_strdup(NULL, "");
247
248         if (!str) {
249                 goto out;
250         }
251
252         if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
253                 str = talloc_asprintf(str, "%s%s",
254                                 str, "OI|");
255                 if (!str) {
256                         goto out;
257                 }
258         }
259         if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
260                 str = talloc_asprintf(str, "%s%s",
261                                 str, "CI|");
262                 if (!str) {
263                         goto out;
264                 }
265         }
266         if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
267                 str = talloc_asprintf(str, "%s%s",
268                                 str, "NP|");
269                 if (!str) {
270                         goto out;
271                 }
272         }
273         if (flags & SEC_ACE_FLAG_INHERIT_ONLY) {
274                 str = talloc_asprintf(str, "%s%s",
275                                 str, "IO|");
276                 if (!str) {
277                         goto out;
278                 }
279         }
280         if (flags & SEC_ACE_FLAG_INHERITED_ACE) {
281                 str = talloc_asprintf(str, "%s%s",
282                                 str, "I|");
283                 if (!str) {
284                         goto out;
285                 }
286         }
287         /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
288            and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're
289            audit ace flags. */
290
291         if (str[strlen(str)-1] == '|') {
292                 str[strlen(str)-1] = '\0';
293                 fprintf(f, "/%s/", str);
294         } else {
295                 fprintf(f, "/0x%x/", flags);
296         }
297         TALLOC_FREE(str);
298         return;
299
300   out:
301         fprintf(f, "/0x%x/", flags);
302 }
303
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,
306                bool numeric)
307 {
308         const struct perm_value *v;
309         fstring sidstr;
310         int do_print = 0;
311         uint32_t got_mask;
312
313         SidToString(cli, sidstr, &ace->trustee, numeric);
314
315         fprintf(f, "%s:", sidstr);
316
317         if (numeric) {
318                 fprintf(f, "%d/0x%x/0x%08x",
319                         ace->type, ace->flags, ace->access_mask);
320                 return;
321         }
322
323         /* Ace type */
324
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");
329         } else {
330                 fprintf(f, "%d", ace->type);
331         }
332
333         print_ace_flags(f, ace->flags);
334
335         /* Standard permissions */
336
337         for (v = standard_values; v->perm; v++) {
338                 if (ace->access_mask == v->mask) {
339                         fprintf(f, "%s", v->perm);
340                         return;
341                 }
342         }
343
344         /* Special permissions.  Print out a hex value if we have
345            leftover bits in the mask. */
346
347         got_mask = ace->access_mask;
348
349  again:
350         for (v = special_values; v->perm; v++) {
351                 if ((ace->access_mask & v->mask) == v->mask) {
352                         if (do_print) {
353                                 fprintf(f, "%s", v->perm);
354                         }
355                         got_mask &= ~v->mask;
356                 }
357         }
358
359         if (!do_print) {
360                 if (got_mask != 0) {
361                         fprintf(f, "0x%08x", ace->access_mask);
362                 } else {
363                         do_print = 1;
364                         goto again;
365                 }
366         }
367 }
368
369 static bool parse_ace_flags(const char *str, unsigned int *pflags)
370 {
371         const char *p = str;
372         *pflags = 0;
373
374         while (*p) {
375                 if (strnequal(p, "OI", 2)) {
376                         *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT;
377                         p += 2;
378                 } else if (strnequal(p, "CI", 2)) {
379                         *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
380                         p += 2;
381                 } else if (strnequal(p, "NP", 2)) {
382                         *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
383                         p += 2;
384                 } else if (strnequal(p, "IO", 2)) {
385                         *pflags |= SEC_ACE_FLAG_INHERIT_ONLY;
386                         p += 2;
387                 } else if (*p == 'I') {
388                         *pflags |= SEC_ACE_FLAG_INHERITED_ACE;
389                         p += 1;
390                 } else if (*p) {
391                         return false;
392                 }
393
394                 switch (*p) {
395                 case '|':
396                         p++;
397
398                         FALL_THROUGH;
399                 case '\0':
400                         continue;
401                 default:
402                         return false;
403                 }
404         }
405         return true;
406 }
407
408 /* parse an ACE in the same format as print_ace() */
409 bool parse_ace(struct cli_state *cli, struct security_ace *ace,
410                const char *orig_str)
411 {
412         char *p;
413         const char *cp;
414         char *tok;
415         unsigned int atype = 0;
416         unsigned int aflags = 0;
417         unsigned int amask = 0;
418         struct dom_sid sid;
419         uint32_t mask;
420         const struct perm_value *v;
421         char *str = SMB_STRDUP(orig_str);
422         TALLOC_CTX *frame = talloc_stackframe();
423
424         if (!str) {
425                 TALLOC_FREE(frame);
426                 return False;
427         }
428
429         ZERO_STRUCTP(ace);
430         p = strchr_m(str,':');
431         if (!p) {
432                 printf("ACE '%s': missing ':'.\n", orig_str);
433                 SAFE_FREE(str);
434                 TALLOC_FREE(frame);
435                 return False;
436         }
437         *p = '\0';
438         p++;
439
440         if (!StringToSid(cli, &sid, str)) {
441                 printf("ACE '%s': failed to convert '%s' to SID\n",
442                         orig_str, str);
443                 SAFE_FREE(str);
444                 TALLOC_FREE(frame);
445                 return False;
446         }
447
448         cp = p;
449         if (!next_token_talloc(frame, &cp, &tok, "/")) {
450                 printf("ACE '%s': failed to find '/' character.\n",
451                         orig_str);
452                 SAFE_FREE(str);
453                 TALLOC_FREE(frame);
454                 return False;
455         }
456
457         if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
458                 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
459         } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
460                 atype = SEC_ACE_TYPE_ACCESS_DENIED;
461
462         } else if (strnequal(tok, "0x", 2)) {
463                 int result;
464
465                 result = sscanf(tok, "%x", &atype);
466                 if (result == 0 ||
467                     (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
468                      atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
469                         printf("ACE '%s': bad hex value for type at '%s'\n",
470                                orig_str, tok);
471                         SAFE_FREE(str);
472                         TALLOC_FREE(frame);
473                         return false;
474                 }
475         } else if(tok[0] >= '0' && tok[0] <= '9') {
476                 int result;
477
478                 result = sscanf(tok, "%u", &atype);
479                 if (result == 0 ||
480                     (atype != SEC_ACE_TYPE_ACCESS_ALLOWED &&
481                      atype != SEC_ACE_TYPE_ACCESS_DENIED)) {
482                         printf("ACE '%s': bad integer value for type at '%s'\n",
483                                orig_str, tok);
484                         SAFE_FREE(str);
485                         TALLOC_FREE(frame);
486                         return false;
487                 }
488         } else {
489                 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
490                         orig_str, tok);
491                 SAFE_FREE(str);
492                 TALLOC_FREE(frame);
493                 return False;
494         }
495
496         if (!next_token_talloc(frame, &cp, &tok, "/")) {
497                 printf("ACE '%s': bad flags entry at '%s'\n",
498                         orig_str, tok);
499                 SAFE_FREE(str);
500                 TALLOC_FREE(frame);
501                 return False;
502         }
503
504         if (tok[0] < '0' || tok[0] > '9') {
505                 if (!parse_ace_flags(tok, &aflags)) {
506                         printf("ACE '%s': bad named flags entry at '%s'\n",
507                                 orig_str, tok);
508                         SAFE_FREE(str);
509                         TALLOC_FREE(frame);
510                         return False;
511                 }
512         } else if (strnequal(tok, "0x", 2)) {
513                 if (!sscanf(tok, "%x", &aflags)) {
514                         printf("ACE '%s': bad hex flags entry at '%s'\n",
515                                 orig_str, tok);
516                         SAFE_FREE(str);
517                         TALLOC_FREE(frame);
518                         return False;
519                 }
520         } else {
521                 if (!sscanf(tok, "%u", &aflags)) {
522                         printf("ACE '%s': bad integer flags entry at '%s'\n",
523                                 orig_str, tok);
524                         SAFE_FREE(str);
525                         TALLOC_FREE(frame);
526                         return False;
527                 }
528         }
529
530         if (!next_token_talloc(frame, &cp, &tok, "/")) {
531                 printf("ACE '%s': missing / at '%s'\n",
532                         orig_str, tok);
533                 SAFE_FREE(str);
534                 TALLOC_FREE(frame);
535                 return False;
536         }
537
538         if (strncmp(tok, "0x", 2) == 0) {
539                 if (sscanf(tok, "%x", &amask) != 1) {
540                         printf("ACE '%s': bad hex number at '%s'\n",
541                                 orig_str, tok);
542                         SAFE_FREE(str);
543                         TALLOC_FREE(frame);
544                         return False;
545                 }
546                 goto done;
547         }
548
549         for (v = standard_values; v->perm; v++) {
550                 if (strcmp(tok, v->perm) == 0) {
551                         amask = v->mask;
552                         goto done;
553                 }
554         }
555
556         p = tok;
557
558         while(*p) {
559                 bool found = False;
560
561                 for (v = special_values; v->perm; v++) {
562                         if (v->perm[0] == *p) {
563                                 amask |= v->mask;
564                                 found = True;
565                         }
566                 }
567
568                 if (!found) {
569                         printf("ACE '%s': bad permission value at '%s'\n",
570                                 orig_str, p);
571                         SAFE_FREE(str);
572                         TALLOC_FREE(frame);
573                         return False;
574                 }
575                 p++;
576         }
577
578         if (*p) {
579                 TALLOC_FREE(frame);
580                 SAFE_FREE(str);
581                 return False;
582         }
583
584  done:
585         mask = amask;
586         init_sec_ace(ace, &sid, atype, mask, aflags);
587         TALLOC_FREE(frame);
588         SAFE_FREE(str);
589         return True;
590 }
591
592 static void print_acl_ctrl(FILE *file, uint16_t ctrl, bool numeric)
593 {
594         int i;
595         const char* separator = "";
596
597         fprintf(file, "CONTROL:");
598         if (numeric) {
599                 fprintf(file, "0x%x\n", ctrl);
600                 return;
601         }
602
603         for (i = ARRAY_SIZE(sec_desc_ctrl_bits) - 1; i >= 0; i--) {
604                 if (ctrl & sec_desc_ctrl_bits[i].mask) {
605                         fprintf(file, "%s%s",
606                                 separator, sec_desc_ctrl_bits[i].str);
607                         separator = "|";
608                 }
609         }
610         fputc('\n', file);
611 }
612
613 /* print a ascii version of a security descriptor on a FILE handle */
614 void sec_desc_print(struct cli_state *cli, FILE *f,
615                     struct security_descriptor *sd, bool numeric)
616 {
617         fstring sidstr;
618         uint32_t i;
619
620         fprintf(f, "REVISION:%d\n", sd->revision);
621         print_acl_ctrl(f, sd->type, numeric);
622
623         /* Print owner and group sid */
624
625         if (sd->owner_sid) {
626                 SidToString(cli, sidstr, sd->owner_sid, numeric);
627         } else {
628                 fstrcpy(sidstr, "");
629         }
630
631         fprintf(f, "OWNER:%s\n", sidstr);
632
633         if (sd->group_sid) {
634                 SidToString(cli, sidstr, sd->group_sid, numeric);
635         } else {
636                 fstrcpy(sidstr, "");
637         }
638
639         fprintf(f, "GROUP:%s\n", sidstr);
640
641         /* Print aces */
642         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
643                 struct security_ace *ace = &sd->dacl->aces[i];
644                 fprintf(f, "ACL:");
645                 print_ace(cli, f, ace, numeric);
646                 fprintf(f, "\n");
647         }
648
649 }