lib:ldb: Use correct integer types for sizes
[vlendec/samba-autobuild/.git] / source3 / utils / sharesec.c
1 /*
2  *  Unix SMB/Netbios implementation.
3  *  Utility for managing share permissions
4  *
5  *  Copyright (C) Tim Potter                    2000
6  *  Copyright (C) Jeremy Allison                2000
7  *  Copyright (C) Jelmer Vernooij               2003
8  *  Copyright (C) Gerald (Jerry) Carter         2005.
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 struct cli_state;
25
26 #include "includes.h"
27 #include "lib/cmdline/cmdline.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/machine_sid.h"
30 #include "util_sd.h"
31 #include "cmdline_contexts.h"
32 #include "lib/util/string_wrappers.h"
33 #include "lib/param/param.h"
34
35 static TALLOC_CTX *ctx;
36
37 enum acl_mode { SMB_ACL_DELETE,
38                 SMB_ACL_MODIFY,
39                 SMB_ACL_ADD,
40                 SMB_ACL_SET,
41                 SMB_SD_DELETE,
42                 SMB_SD_SETSDDL,
43                 SMB_SD_VIEWSDDL,
44                 SMB_ACL_VIEW,
45                 SMB_ACL_VIEW_ALL };
46
47 /********************************************************************
48 ********************************************************************/
49
50 static struct security_descriptor* parse_acl_string(TALLOC_CTX *mem_ctx, const char *szACL, size_t *sd_size )
51 {
52         struct security_descriptor *sd = NULL;
53         struct security_ace *ace;
54         struct security_acl *theacl;
55         int num_ace;
56         const char *pacl;
57         int i;
58
59         if ( !szACL )
60                 return NULL;
61
62         pacl = szACL;
63         num_ace = count_chars( pacl, ',' ) + 1;
64
65         if ( !(ace = talloc_zero_array( mem_ctx, struct security_ace, num_ace )) )
66                 return NULL;
67
68         for ( i=0; i<num_ace; i++ ) {
69                 char *end_acl = strchr_m( pacl, ',' );
70                 fstring acl_string;
71
72                 strncpy( acl_string, pacl, MIN( PTR_DIFF( end_acl, pacl ), sizeof(fstring)-1) );
73                 acl_string[MIN( PTR_DIFF( end_acl, pacl ), sizeof(fstring)-1)] = '\0';
74
75                 if ( !parse_ace(NULL, &ace[i], acl_string ) )
76                         return NULL;
77
78                 pacl = end_acl;
79                 pacl++;
80         }
81
82         if ( !(theacl = make_sec_acl( mem_ctx, NT4_ACL_REVISION, num_ace, ace )) )
83                 return NULL;
84
85         sd = make_sec_desc( mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
86                 NULL, NULL, NULL, theacl, sd_size);
87
88         return sd;
89 }
90
91 /* add an ACE to a list of ACEs in a struct security_acl */
92 static bool add_ace(TALLOC_CTX *mem_ctx, struct security_acl **the_acl, struct security_ace *ace)
93 {
94         struct security_acl *acl = *the_acl;
95
96         if (acl == NULL) {
97                 acl = make_sec_acl(mem_ctx, 3, 1, ace);
98                 if (acl == NULL) {
99                         return false;
100                 }
101         }
102
103         if (acl->num_aces == UINT32_MAX) {
104                 return false;
105         }
106         ADD_TO_ARRAY(
107                 acl, struct security_ace, *ace, &acl->aces, &acl->num_aces);
108         *the_acl = acl;
109         return True;
110 }
111
112 /* The MSDN is contradictory over the ordering of ACE entries in an ACL.
113    However NT4 gives a "The information may have been modified by a
114    computer running Windows NT 5.0" if denied ACEs do not appear before
115    allowed ACEs. */
116
117 static int ace_compare(struct security_ace *ace1, struct security_ace *ace2)
118 {
119         if (security_ace_equal(ace1, ace2))
120                 return 0;
121
122         if (ace1->type != ace2->type)
123                 return NUMERIC_CMP(ace2->type, ace1->type);
124
125         if (dom_sid_compare(&ace1->trustee, &ace2->trustee))
126                 return dom_sid_compare(&ace1->trustee, &ace2->trustee);
127
128         if (ace1->flags != ace2->flags)
129                 return NUMERIC_CMP(ace1->flags, ace2->flags);
130
131         if (ace1->access_mask != ace2->access_mask)
132                 return NUMERIC_CMP(ace1->access_mask, ace2->access_mask);
133
134         if (ace1->size != ace2->size)
135                 return NUMERIC_CMP(ace1->size, ace2->size);
136
137         return memcmp(ace1, ace2, sizeof(struct security_ace));
138 }
139
140 static void sort_acl(struct security_acl *the_acl)
141 {
142         uint32_t i;
143         if (!the_acl) return;
144
145         TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces, ace_compare);
146
147         for (i=1;i<the_acl->num_aces;) {
148                 if (security_ace_equal(&the_acl->aces[i-1],
149                                        &the_acl->aces[i])) {
150                         ARRAY_DEL_ELEMENT(
151                                 the_acl->aces, i, the_acl->num_aces);
152                         the_acl->num_aces--;
153                 } else {
154                         i++;
155                 }
156         }
157 }
158
159
160 static int change_share_sec(TALLOC_CTX *mem_ctx, const char *sharename, char *the_acl, enum acl_mode mode)
161 {
162         struct security_descriptor *sd = NULL;
163         struct security_descriptor *old = NULL;
164         size_t sd_size = 0;
165         uint32_t i, j;
166         NTSTATUS status;
167
168         if (mode != SMB_ACL_SET && mode != SMB_SD_DELETE) {
169             if (!(old = get_share_security( mem_ctx, sharename, &sd_size )) ) {
170                 fprintf(stderr, "Unable to retrieve permissions for share "
171                         "[%s]\n", sharename);
172                 return -1;
173             }
174         }
175
176         if ( (mode != SMB_ACL_VIEW && mode != SMB_SD_DELETE) &&
177             !(sd = parse_acl_string(mem_ctx, the_acl, &sd_size )) ) {
178                 fprintf( stderr, "Failed to parse acl\n");
179                 return -1;
180         }
181
182         switch (mode) {
183         case SMB_ACL_VIEW_ALL:
184                 /* should not happen */
185                 return 0;
186         case SMB_ACL_VIEW:
187                 sec_desc_print(NULL, stdout, old, false);
188                 return 0;
189         case SMB_ACL_DELETE:
190             for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
191                 bool found = False;
192
193                 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
194                     if (security_ace_equal(&sd->dacl->aces[i],
195                                            &old->dacl->aces[j])) {
196                         uint32_t k;
197                         for (k=j; k<old->dacl->num_aces-1;k++) {
198                             old->dacl->aces[k] = old->dacl->aces[k+1];
199                         }
200                         old->dacl->num_aces--;
201                         found = True;
202                         break;
203                     }
204                 }
205
206                 if (!found) {
207                         printf("ACL for ACE:");
208                         print_ace(NULL, stdout, &sd->dacl->aces[i], false);
209                         printf(" not found\n");
210                 }
211             }
212             break;
213         case SMB_ACL_MODIFY:
214             for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
215                 bool found = False;
216
217                 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
218                     if (dom_sid_equal(&sd->dacl->aces[i].trustee,
219                         &old->dacl->aces[j].trustee)) {
220                         old->dacl->aces[j] = sd->dacl->aces[i];
221                         found = True;
222                     }
223                 }
224
225                 if (!found) {
226                     struct dom_sid_buf buf;
227                     printf("ACL for SID %s not found\n",
228                            dom_sid_str_buf(&sd->dacl->aces[i].trustee, &buf));
229                 }
230             }
231
232             if (sd->owner_sid) {
233                 old->owner_sid = sd->owner_sid;
234             }
235
236             if (sd->group_sid) {
237                 old->group_sid = sd->group_sid;
238             }
239             break;
240         case SMB_ACL_ADD:
241             for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
242                 add_ace(mem_ctx, &old->dacl, &sd->dacl->aces[i]);
243             }
244             break;
245         case SMB_ACL_SET:
246             old = sd;
247             break;
248         case SMB_SD_DELETE:
249             status = delete_share_security(sharename);
250             if (!NT_STATUS_IS_OK(status)) {
251                 fprintf( stderr, "Failed to delete security descriptor for "
252                          "share [%s]\n", sharename );
253                 return -1;
254             }
255             return 0;
256         default:
257                 fprintf(stderr, "invalid command\n");
258                 return -1;
259         }
260
261         /* Denied ACE entries must come before allowed ones */
262         sort_acl(old->dacl);
263
264         status = set_share_security(sharename, old);
265         if (!NT_STATUS_IS_OK(status)) {
266             fprintf( stderr, "Failed to store acl for share [%s]\n", sharename );
267             return 2;
268         }
269         return 0;
270 }
271
272 static int set_sharesec_sddl(const char *sharename, const char *sddl)
273 {
274         struct security_descriptor *sd;
275         NTSTATUS status;
276
277         sd = sddl_decode(talloc_tos(), sddl, get_global_sam_sid());
278         if (sd == NULL) {
279                 fprintf(stderr, "Failed to parse acl\n");
280                 return -1;
281         }
282
283         status = set_share_security(sharename, sd);
284         TALLOC_FREE(sd);
285         if (!NT_STATUS_IS_OK(status)) {
286                 fprintf(stderr, "Failed to store acl for share [%s]\n",
287                         sharename);
288                 return -1;
289         }
290
291         return 0;
292 }
293
294 static int view_sharesec_sddl(const char *sharename)
295 {
296         struct security_descriptor *sd;
297         size_t sd_size;
298         char *acl;
299
300         sd = get_share_security(talloc_tos(), sharename, &sd_size);
301         if (sd == NULL) {
302                 fprintf(stderr, "Unable to retrieve permissions for share "
303                         "[%s]\n", sharename);
304                 return -1;
305         }
306
307         acl = sddl_encode(talloc_tos(), sd, get_global_sam_sid());
308         TALLOC_FREE(sd);
309         if (acl == NULL) {
310                 fprintf(stderr, "Unable to sddl-encode permissions for share "
311                         "[%s]\n", sharename);
312                 return -1;
313         }
314         printf("%s\n", acl);
315         TALLOC_FREE(acl);
316         return 0;
317 }
318
319 /********************************************************************
320   main program
321 ********************************************************************/
322
323 enum {
324         OPT_VIEW_ALL = 1000,
325         OPT_VIEW_SDDL,
326 };
327
328 int main(int argc, const char *argv[])
329 {
330         int opt;
331         int retval = 0;
332         enum acl_mode mode = SMB_ACL_SET;
333         static char *the_acl = NULL;
334         fstring sharename;
335         bool force_acl = False;
336         int snum;
337         poptContext pc;
338         bool initialize_sid = False;
339         bool ok;
340         struct loadparm_context *lp_ctx = NULL;
341         struct poptOption long_options[] = {
342                 POPT_AUTOHELP
343                 {
344                         .longName   = "remove",
345                         .shortName  = 'r',
346                         .argInfo    = POPT_ARG_STRING,
347                         .arg        = &the_acl,
348                         .val        = 'r',
349                         .descrip    = "Remove ACEs",
350                         .argDescrip = "ACL",
351                 },
352                 {
353                         .longName   = "modify",
354                         .shortName  = 'm',
355                         .argInfo    = POPT_ARG_STRING,
356                         .arg        = &the_acl,
357                         .val        = 'm',
358                         .descrip    = "Modify existing ACEs",
359                         .argDescrip = "ACL",
360                 },
361                 {
362                         .longName   = "add",
363                         .shortName  = 'a',
364                         .argInfo    = POPT_ARG_STRING,
365                         .arg        = &the_acl,
366                         .val        = 'a',
367                         .descrip    = "Add ACEs",
368                         .argDescrip = "ACL",
369                 },
370                 {
371                         .longName   = "replace",
372                         .shortName  = 'R',
373                         .argInfo    = POPT_ARG_STRING,
374                         .arg        = &the_acl,
375                         .val        = 'R',
376                         .descrip    = "Overwrite share permission ACL",
377                         .argDescrip = "ACLS",
378                 },
379                 {
380                         .longName   = "delete",
381                         .shortName  = 'D',
382                         .argInfo    = POPT_ARG_NONE,
383                         .arg        = NULL,
384                         .val        = 'D',
385                         .descrip    = "Delete the entire security descriptor",
386                 },
387                 {
388                         .longName   = "setsddl",
389                         .shortName  = 'S',
390                         .argInfo    = POPT_ARG_STRING,
391                         .arg        = the_acl,
392                         .val        = 'S',
393                         .descrip    = "Set the SD in sddl format",
394                 },
395                 {
396                         .longName   = "viewsddl",
397                         .argInfo    = POPT_ARG_NONE,
398                         .arg        = the_acl,
399                         .val        = OPT_VIEW_SDDL,
400                         .descrip    = "View the SD in sddl format",
401                 },
402                 {
403                         .longName   = "view",
404                         .shortName  = 'v',
405                         .argInfo    = POPT_ARG_NONE,
406                         .arg        = NULL,
407                         .val        = 'v',
408                         .descrip    = "View current share permissions",
409                 },
410                 {
411                         .longName   = "view-all",
412                         .shortName  = 0,
413                         .argInfo    = POPT_ARG_NONE,
414                         .arg        = NULL,
415                         .val        = OPT_VIEW_ALL,
416                         .descrip    = "View all current share permissions",
417                 },
418                 {
419                         .longName   = "machine-sid",
420                         .shortName  = 'M',
421                         .argInfo    = POPT_ARG_NONE,
422                         .arg        = NULL,
423                         .val        = 'M',
424                         .descrip    = "Initialize the machine SID",
425                 },
426                 {
427                         .longName   = "force",
428                         .shortName  = 'F',
429                         .argInfo    = POPT_ARG_NONE,
430                         .arg        = NULL,
431                         .val        = 'F',
432                         .descrip    = "Force storing the ACL",
433                         .argDescrip = "ACLS",
434                 },
435                 POPT_COMMON_SAMBA
436                 POPT_COMMON_VERSION
437                 POPT_TABLEEND
438         };
439
440         if ( !(ctx = talloc_stackframe()) ) {
441                 fprintf( stderr, "Failed to initialize talloc context!\n");
442                 return -1;
443         }
444
445         smb_init_locale();
446
447         ok = samba_cmdline_init(ctx,
448                                 SAMBA_CMDLINE_CONFIG_NONE,
449                                 false /* require_smbconf */);
450         if (!ok) {
451                 DBG_ERR("Failed to init cmdline parser!\n");
452                 TALLOC_FREE(ctx);
453                 exit(1);
454         }
455         lp_ctx = samba_cmdline_get_lp_ctx();
456         /* set default debug level to 1 regardless of what smb.conf sets */
457         lpcfg_set_cmdline(lp_ctx, "log level", "1");
458
459         pc = samba_popt_get_context(getprogname(),
460                                     argc,
461                                     argv,
462                                     long_options,
463                                     0);
464         if (pc == NULL) {
465                 DBG_ERR("Failed to setup popt context!\n");
466                 TALLOC_FREE(ctx);
467                 exit(1);
468         }
469
470         poptSetOtherOptionHelp(pc, "sharename\n");
471
472         while ((opt = poptGetNextOpt(pc)) != -1) {
473                 switch (opt) {
474                 case 'r':
475                         the_acl = smb_xstrdup(poptGetOptArg(pc));
476                         mode = SMB_ACL_DELETE;
477                         break;
478
479                 case 'm':
480                         the_acl = smb_xstrdup(poptGetOptArg(pc));
481                         mode = SMB_ACL_MODIFY;
482                         break;
483
484                 case 'a':
485                         the_acl = smb_xstrdup(poptGetOptArg(pc));
486                         mode = SMB_ACL_ADD;
487                         break;
488
489                 case 'R':
490                         the_acl = smb_xstrdup(poptGetOptArg(pc));
491                         mode = SMB_ACL_SET;
492                         break;
493
494                 case 'D':
495                         mode = SMB_SD_DELETE;
496                         break;
497
498                 case 'S':
499                         mode = SMB_SD_SETSDDL;
500                         the_acl = smb_xstrdup(poptGetOptArg(pc));
501                         break;
502
503                 case OPT_VIEW_SDDL:
504                         mode = SMB_SD_VIEWSDDL;
505                         break;
506
507                 case 'v':
508                         mode = SMB_ACL_VIEW;
509                         break;
510
511                 case 'F':
512                         force_acl = True;
513                         break;
514
515                 case 'M':
516                         initialize_sid = True;
517                         break;
518                 case OPT_VIEW_ALL:
519                         mode = SMB_ACL_VIEW_ALL;
520                         break;
521                 case POPT_ERROR_BADOPT:
522                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
523                                 poptBadOption(pc, 0), poptStrerror(opt));
524                         poptPrintUsage(pc, stderr, 0);
525                         exit(1);
526                 }
527         }
528
529         setlinebuf(stdout);
530
531         lp_load_with_registry_shares(get_dyn_CONFIGFILE());
532
533         /* check for initializing secrets.tdb first */
534
535         if ( initialize_sid ) {
536                 struct dom_sid *sid = get_global_sam_sid();
537                 struct dom_sid_buf buf;
538
539                 if ( !sid ) {
540                         fprintf( stderr, "Failed to retrieve Machine SID!\n");
541                         retval = 3;
542                         goto done;
543                 }
544
545                 printf ("%s\n", dom_sid_str_buf(sid, &buf) );
546                 retval = 0;
547                 goto done;
548         }
549
550         if ( mode == SMB_ACL_VIEW && force_acl ) {
551                 fprintf( stderr, "Invalid combination of -F and -v\n");
552                 retval = -1;
553                 goto done;
554         }
555
556         if (mode == SMB_ACL_VIEW_ALL) {
557                 int i;
558
559                 for (i=0; i<lp_numservices(); i++) {
560                         TALLOC_CTX *frame = talloc_stackframe();
561                         const struct loadparm_substitution *lp_sub =
562                                 loadparm_s3_global_substitution();
563                         const char *service = lp_servicename(frame, lp_sub, i);
564
565                         if (service == NULL) {
566                                 continue;
567                         }
568
569                         printf("[%s]\n", service);
570                         change_share_sec(frame, service, NULL, SMB_ACL_VIEW);
571                         printf("\n");
572                         TALLOC_FREE(frame);
573                 }
574                 goto done;
575         }
576
577         /* get the sharename */
578
579         if(!poptPeekArg(pc)) {
580                 poptPrintUsage(pc, stderr, 0);
581                 retval = -1;
582                 goto done;
583         }
584
585         fstrcpy(sharename, poptGetArg(pc));
586
587         snum = lp_servicenumber( sharename );
588
589         if ( snum == -1 && !force_acl ) {
590                 fprintf( stderr, "Invalid sharename: %s\n", sharename);
591                 retval = -1;
592                 goto done;
593         }
594
595         switch (mode) {
596         case SMB_SD_SETSDDL:
597                 retval = set_sharesec_sddl(sharename, the_acl);
598                 break;
599         case SMB_SD_VIEWSDDL:
600                 retval = view_sharesec_sddl(sharename);
601                 break;
602         default:
603                 retval = change_share_sec(ctx, sharename, the_acl, mode);
604                 break;
605         }
606
607 done:
608         gfree_all();
609         poptFreeContext(pc);
610         talloc_destroy(ctx);
611
612         return retval;
613 }