00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "includes.h"
00027
00028 static TALLOC_CTX *ctx;
00029
00030 enum acl_mode {SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD, SMB_ACL_SET, SMB_ACL_VIEW };
00031
00032 struct perm_value {
00033 const char *perm;
00034 uint32 mask;
00035 };
00036
00037
00038
00039 static const struct perm_value special_values[] = {
00040 { "R", SEC_RIGHTS_FILE_READ },
00041 { "W", SEC_RIGHTS_FILE_WRITE },
00042 { "X", SEC_RIGHTS_FILE_EXECUTE },
00043 { "D", SEC_STD_DELETE },
00044 { "P", SEC_STD_WRITE_DAC },
00045 { "O", SEC_STD_WRITE_OWNER },
00046 { NULL, 0 },
00047 };
00048
00049 #define SEC_RIGHTS_DIR_CHANGE ( SEC_RIGHTS_DIR_READ|SEC_STD_DELETE|SEC_RIGHTS_DIR_WRITE|SEC_DIR_TRAVERSE )
00050
00051 static const struct perm_value standard_values[] = {
00052 { "READ", SEC_RIGHTS_DIR_READ|SEC_DIR_TRAVERSE },
00053 { "CHANGE", SEC_RIGHTS_DIR_CHANGE },
00054 { "FULL", SEC_RIGHTS_DIR_ALL },
00055 { NULL, 0 },
00056 };
00057
00058
00059
00060
00061
00062 static void print_ace(FILE *f, SEC_ACE *ace)
00063 {
00064 const struct perm_value *v;
00065 int do_print = 0;
00066 uint32 got_mask;
00067
00068 fprintf(f, "%s:", sid_string_static(&ace->trustee));
00069
00070
00071
00072 if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
00073 fprintf(f, "ALLOWED");
00074 } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
00075 fprintf(f, "DENIED");
00076 } else {
00077 fprintf(f, "%d", ace->type);
00078 }
00079
00080
00081
00082 fprintf(f, "/%d/", ace->flags);
00083
00084
00085
00086 for (v = standard_values; v->perm; v++) {
00087 if (ace->access_mask == v->mask) {
00088 fprintf(f, "%s", v->perm);
00089 return;
00090 }
00091 }
00092
00093
00094
00095
00096 got_mask = ace->access_mask;
00097
00098 again:
00099 for (v = special_values; v->perm; v++) {
00100 if ((ace->access_mask & v->mask) == v->mask) {
00101 if (do_print) {
00102 fprintf(f, "%s", v->perm);
00103 }
00104 got_mask &= ~v->mask;
00105 }
00106 }
00107
00108 if (!do_print) {
00109 if (got_mask != 0) {
00110 fprintf(f, "0x%08x", ace->access_mask);
00111 } else {
00112 do_print = 1;
00113 goto again;
00114 }
00115 }
00116 }
00117
00118
00119
00120
00121
00122 static void sec_desc_print(FILE *f, SEC_DESC *sd)
00123 {
00124 uint32 i;
00125
00126 fprintf(f, "REVISION:%d\n", sd->revision);
00127
00128
00129
00130 fprintf(f, "OWNER:%s\n", sid_string_static(sd->owner_sid));
00131
00132 fprintf(f, "GROUP:%s\n", sid_string_static(sd->group_sid));
00133
00134
00135 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
00136 SEC_ACE *ace = &sd->dacl->aces[i];
00137 fprintf(f, "ACL:");
00138 print_ace(f, ace);
00139 fprintf(f, "\n");
00140 }
00141
00142 }
00143
00144
00145
00146
00147
00148 static BOOL parse_ace(SEC_ACE *ace, const char *orig_str)
00149 {
00150 char *p;
00151 const char *cp;
00152 fstring tok;
00153 unsigned int atype = 0;
00154 unsigned int aflags = 0;
00155 unsigned int amask = 0;
00156 DOM_SID sid;
00157 SEC_ACCESS mask;
00158 const struct perm_value *v;
00159 char *str = SMB_STRDUP(orig_str);
00160
00161 if (!str) {
00162 return False;
00163 }
00164
00165 ZERO_STRUCTP(ace);
00166 p = strchr_m(str,':');
00167 if (!p) {
00168 printf("ACE '%s': missing ':'.\n", orig_str);
00169 SAFE_FREE(str);
00170 return False;
00171 }
00172 *p = '\0';
00173 p++;
00174
00175
00176 if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
00177 string_to_sid(&sid, str)) {
00178 goto done;
00179 }
00180
00181
00182
00183 if (!string_to_sid(&sid, str)) {
00184 printf("ACE '%s': failed to convert '%s' to SID\n",
00185 orig_str, str);
00186 SAFE_FREE(str);
00187 return False;
00188 }
00189
00190 cp = p;
00191 if (!next_token(&cp, tok, "/", sizeof(fstring))) {
00192 printf("ACE '%s': failed to find '/' character.\n",
00193 orig_str);
00194 SAFE_FREE(str);
00195 return False;
00196 }
00197
00198 if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
00199 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
00200 } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
00201 atype = SEC_ACE_TYPE_ACCESS_DENIED;
00202 } else {
00203 printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n",
00204 orig_str, tok);
00205 SAFE_FREE(str);
00206 return False;
00207 }
00208
00209
00210
00211
00212 if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
00213 sscanf(tok, "%i", &aflags) && aflags == 0)) {
00214 printf("ACE '%s': bad integer flags entry at '%s'\n",
00215 orig_str, tok);
00216 SAFE_FREE(str);
00217 return False;
00218 }
00219
00220 if (!next_token(&cp, tok, "/", sizeof(fstring))) {
00221 printf("ACE '%s': missing / at '%s'\n",
00222 orig_str, tok);
00223 SAFE_FREE(str);
00224 return False;
00225 }
00226
00227 if (strncmp(tok, "0x", 2) == 0) {
00228 if (sscanf(tok, "%i", &amask) != 1) {
00229 printf("ACE '%s': bad hex number at '%s'\n",
00230 orig_str, tok);
00231 SAFE_FREE(str);
00232 return False;
00233 }
00234 goto done;
00235 }
00236
00237 for (v = standard_values; v->perm; v++) {
00238 if (strcmp(tok, v->perm) == 0) {
00239 amask = v->mask;
00240 goto done;
00241 }
00242 }
00243
00244 p = tok;
00245
00246 while(*p) {
00247 BOOL found = False;
00248
00249 for (v = special_values; v->perm; v++) {
00250 if (v->perm[0] == *p) {
00251 amask |= v->mask;
00252 found = True;
00253 }
00254 }
00255
00256 if (!found) {
00257 printf("ACE '%s': bad permission value at '%s'\n",
00258 orig_str, p);
00259 SAFE_FREE(str);
00260 return False;
00261 }
00262 p++;
00263 }
00264
00265 if (*p) {
00266 SAFE_FREE(str);
00267 return False;
00268 }
00269
00270 done:
00271 mask = amask;
00272 init_sec_ace(ace, &sid, atype, mask, aflags);
00273 SAFE_FREE(str);
00274 return True;
00275 }
00276
00277
00278
00279
00280
00281 static SEC_DESC* parse_acl_string(TALLOC_CTX *mem_ctx, const char *szACL, size_t *sd_size )
00282 {
00283 SEC_DESC *sd = NULL;
00284 SEC_ACE *ace;
00285 SEC_ACL *acl;
00286 int num_ace;
00287 const char *pacl;
00288 int i;
00289
00290 if ( !szACL )
00291 return NULL;
00292
00293 pacl = szACL;
00294 num_ace = count_chars( pacl, ',' ) + 1;
00295
00296 if ( !(ace = TALLOC_ZERO_ARRAY( mem_ctx, SEC_ACE, num_ace )) )
00297 return NULL;
00298
00299 for ( i=0; i<num_ace; i++ ) {
00300 char *end_acl = strchr_m( pacl, ',' );
00301 fstring acl_string;
00302
00303 strncpy( acl_string, pacl, MIN( PTR_DIFF( end_acl, pacl ), sizeof(fstring)-1) );
00304 acl_string[MIN( PTR_DIFF( end_acl, pacl ), sizeof(fstring)-1)] = '\0';
00305
00306 if ( !parse_ace( &ace[i], acl_string ) )
00307 return NULL;
00308
00309 pacl = end_acl;
00310 pacl++;
00311 }
00312
00313 if ( !(acl = make_sec_acl( mem_ctx, NT4_ACL_REVISION, num_ace, ace )) )
00314 return NULL;
00315
00316 sd = make_sec_desc( mem_ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
00317 NULL, NULL, NULL, acl, sd_size);
00318
00319 return sd;
00320 }
00321
00322
00323 static BOOL add_ace(TALLOC_CTX *mem_ctx, SEC_ACL **the_acl, SEC_ACE *ace)
00324 {
00325 SEC_ACL *new_ace;
00326 SEC_ACE *aces;
00327 if (! *the_acl) {
00328 return (((*the_acl) = make_sec_acl(mem_ctx, 3, 1, ace)) != NULL);
00329 }
00330
00331 if (!(aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces))) {
00332 return False;
00333 }
00334 memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
00335 memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
00336 new_ace = make_sec_acl(mem_ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
00337 SAFE_FREE(aces);
00338 (*the_acl) = new_ace;
00339 return True;
00340 }
00341
00342
00343
00344
00345
00346
00347 static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
00348 {
00349 if (sec_ace_equal(ace1, ace2))
00350 return 0;
00351
00352 if (ace1->type != ace2->type)
00353 return ace2->type - ace1->type;
00354
00355 if (sid_compare(&ace1->trustee, &ace2->trustee))
00356 return sid_compare(&ace1->trustee, &ace2->trustee);
00357
00358 if (ace1->flags != ace2->flags)
00359 return ace1->flags - ace2->flags;
00360
00361 if (ace1->access_mask != ace2->access_mask)
00362 return ace1->access_mask - ace2->access_mask;
00363
00364 if (ace1->size != ace2->size)
00365 return ace1->size - ace2->size;
00366
00367 return memcmp(ace1, ace2, sizeof(SEC_ACE));
00368 }
00369
00370 static void sort_acl(SEC_ACL *the_acl)
00371 {
00372 uint32 i;
00373 if (!the_acl) return;
00374
00375 qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), QSORT_CAST ace_compare);
00376
00377 for (i=1;i<the_acl->num_aces;) {
00378 if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
00379 int j;
00380 for (j=i; j<the_acl->num_aces-1; j++) {
00381 the_acl->aces[j] = the_acl->aces[j+1];
00382 }
00383 the_acl->num_aces--;
00384 } else {
00385 i++;
00386 }
00387 }
00388 }
00389
00390
00391 static int change_share_sec(TALLOC_CTX *mem_ctx, const char *sharename, char *the_acl, enum acl_mode mode)
00392 {
00393 SEC_DESC *sd;
00394 SEC_DESC *old = NULL;
00395 size_t sd_size = 0;
00396 uint32 i, j;
00397
00398 if (mode != SMB_ACL_SET) {
00399 if (!(old = get_share_security( mem_ctx, sharename, &sd_size )) ) {
00400 fprintf(stderr, "Unable to retrieve permissions for share [%s]\n", sharename);
00401 return -1;
00402 }
00403 }
00404
00405 if ( (mode != SMB_ACL_VIEW) && !(sd = parse_acl_string(mem_ctx, the_acl, &sd_size )) ) {
00406 fprintf( stderr, "Failed to parse acl\n");
00407 return -1;
00408 }
00409
00410 switch (mode) {
00411 case SMB_ACL_VIEW:
00412 sec_desc_print( stdout, old);
00413 return 0;
00414 case SMB_ACL_DELETE:
00415 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
00416 BOOL found = False;
00417
00418 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
00419 if (sec_ace_equal(&sd->dacl->aces[i], &old->dacl->aces[j])) {
00420 uint32 k;
00421 for (k=j; k<old->dacl->num_aces-1;k++) {
00422 old->dacl->aces[k] = old->dacl->aces[k+1];
00423 }
00424 old->dacl->num_aces--;
00425 found = True;
00426 break;
00427 }
00428 }
00429
00430 if (!found) {
00431 printf("ACL for ACE:");
00432 print_ace(stdout, &sd->dacl->aces[i]);
00433 printf(" not found\n");
00434 }
00435 }
00436
00437 break;
00438 case SMB_ACL_MODIFY:
00439 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
00440 BOOL found = False;
00441
00442 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
00443 if (sid_equal(&sd->dacl->aces[i].trustee,
00444 &old->dacl->aces[j].trustee)) {
00445 old->dacl->aces[j] = sd->dacl->aces[i];
00446 found = True;
00447 }
00448 }
00449
00450 if (!found) {
00451 printf("ACL for SID %s not found\n", sid_string_static(&sd->dacl->aces[i].trustee));
00452 }
00453 }
00454
00455 if (sd->owner_sid) {
00456 old->owner_sid = sd->owner_sid;
00457 }
00458
00459 if (sd->group_sid) {
00460 old->group_sid = sd->group_sid;
00461 }
00462 break;
00463 case SMB_ACL_ADD:
00464 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
00465 add_ace(mem_ctx, &old->dacl, &sd->dacl->aces[i]);
00466 }
00467 break;
00468 case SMB_ACL_SET:
00469 old = sd;
00470 break;
00471 }
00472
00473
00474 sort_acl(old->dacl);
00475
00476 if ( !set_share_security( sharename, old ) ) {
00477 fprintf( stderr, "Failed to store acl for share [%s]\n", sharename );
00478 return 2;
00479 }
00480 return 0;
00481 }
00482
00483
00484
00485
00486
00487 int main(int argc, const char *argv[])
00488 {
00489 int opt;
00490 int retval = 0;
00491 enum acl_mode mode = SMB_ACL_SET;
00492 static char *the_acl = NULL;
00493 fstring sharename;
00494 BOOL force_acl = False;
00495 int snum;
00496 poptContext pc;
00497 BOOL initialize_sid = False;
00498 struct poptOption long_options[] = {
00499 POPT_AUTOHELP
00500 { "remove", 'r', POPT_ARG_STRING, &the_acl, 'r', "Delete an ACE", "ACL" },
00501 { "modify", 'm', POPT_ARG_STRING, &the_acl, 'm', "Modify an acl", "ACL" },
00502 { "add", 'a', POPT_ARG_STRING, &the_acl, 'a', "Add an ACE", "ACL" },
00503 { "replace", 'R', POPT_ARG_STRING, &the_acl, 'R', "Set share mission ACL", "ACLS" },
00504 { "view", 'v', POPT_ARG_NONE, NULL, 'v', "View current share permissions" },
00505 { "machine-sid", 'M', POPT_ARG_NONE, NULL, 'M', "Initialize the machine SID" },
00506 { "force", 'F', POPT_ARG_NONE, NULL, 'F', "Force storing the ACL", "ACLS" },
00507 POPT_COMMON_SAMBA
00508 { NULL }
00509 };
00510
00511 if ( !(ctx = talloc_init("main")) ) {
00512 fprintf( stderr, "Failed to initialize talloc context!\n");
00513 return -1;
00514 }
00515
00516
00517 setup_logging( "sharesec", True );
00518 DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
00519 dbf = x_stderr;
00520 x_setbuf( x_stderr, NULL );
00521
00522 pc = poptGetContext("sharesec", argc, argv, long_options, 0);
00523
00524 poptSetOtherOptionHelp(pc, "sharename\n");
00525
00526 while ((opt = poptGetNextOpt(pc)) != -1) {
00527 switch (opt) {
00528 case 'r':
00529 the_acl = smb_xstrdup(poptGetOptArg(pc));
00530 mode = SMB_ACL_DELETE;
00531 break;
00532
00533 case 'm':
00534 the_acl = smb_xstrdup(poptGetOptArg(pc));
00535 mode = SMB_ACL_MODIFY;
00536 break;
00537
00538 case 'a':
00539 the_acl = smb_xstrdup(poptGetOptArg(pc));
00540 mode = SMB_ACL_ADD;
00541 break;
00542 case 'R':
00543 the_acl = smb_xstrdup(poptGetOptArg(pc));
00544 mode = SMB_ACL_SET;
00545 break;
00546
00547 case 'v':
00548 mode = SMB_ACL_VIEW;
00549 break;
00550
00551 case 'F':
00552 force_acl = True;
00553 break;
00554
00555 case 'M':
00556 initialize_sid = True;
00557 break;
00558 }
00559 }
00560
00561 setlinebuf(stdout);
00562
00563 load_case_tables();
00564
00565 lp_load( dyn_CONFIGFILE, False, False, False, True );
00566
00567
00568
00569 if ( initialize_sid ) {
00570 DOM_SID *sid = get_global_sam_sid();
00571
00572 if ( !sid ) {
00573 fprintf( stderr, "Failed to retrieve Machine SID!\n");
00574 return 3;
00575 }
00576
00577 printf ("%s\n", sid_string_static( sid ) );
00578 return 0;
00579 }
00580
00581 if ( mode == SMB_ACL_VIEW && force_acl ) {
00582 fprintf( stderr, "Invalid combination of -F and -v\n");
00583 return -1;
00584 }
00585
00586
00587
00588 if(!poptPeekArg(pc)) {
00589 poptPrintUsage(pc, stderr, 0);
00590 return -1;
00591 }
00592
00593 fstrcpy(sharename, poptGetArg(pc));
00594
00595 snum = lp_servicenumber( sharename );
00596
00597 if ( snum == -1 && !force_acl ) {
00598 fprintf( stderr, "Invalid sharename: %s\n", sharename);
00599 return -1;
00600 }
00601
00602 retval = change_share_sec(ctx, sharename, the_acl, mode);
00603
00604 talloc_destroy(ctx);
00605
00606 return retval;
00607 }