LCOV - code coverage report
Current view: top level - source3/utils - smbcacls.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 587 781 75.2 %
Date: 2021-09-23 10:06:22 Functions: 28 28 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    ACL get/set utility
       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             :    Copyright (C) Noel Power <noel.power@suse.com> 2013
      10             : 
      11             :    This program is free software; you can redistribute it and/or modify
      12             :    it under the terms of the GNU General Public License as published by
      13             :    the Free Software Foundation; either version 3 of the License, or
      14             :    (at your option) any later version.
      15             : 
      16             :    This program is distributed in the hope that it will be useful,
      17             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :    GNU General Public License for more details.
      20             : 
      21             :    You should have received a copy of the GNU General Public License
      22             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "lib/cmdline/cmdline.h"
      27             : #include "rpc_client/cli_pipe.h"
      28             : #include "../librpc/gen_ndr/ndr_lsa.h"
      29             : #include "rpc_client/cli_lsarpc.h"
      30             : #include "../libcli/security/security.h"
      31             : #include "libsmb/libsmb.h"
      32             : #include "libsmb/clirap.h"
      33             : #include "passdb/machine_sid.h"
      34             : #include "../librpc/gen_ndr/ndr_lsa_c.h"
      35             : #include "util_sd.h"
      36             : 
      37             : static char DIRSEP_CHAR = '\\';
      38             : 
      39             : static int inheritance = 0;
      40             : static int test_args;
      41             : static int sddl;
      42             : static int query_sec_info = -1;
      43             : static int set_sec_info = -1;
      44             : static bool want_mxac;
      45             : 
      46             : static const char *domain_sid = NULL;
      47             : 
      48             : enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD };
      49             : enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP, REQUEST_INHERIT};
      50             : enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
      51             : 
      52             : struct cacl_callback_state {
      53             :         struct cli_credentials *creds;
      54             :         struct cli_state *cli;
      55             :         struct security_descriptor *aclsd;
      56             :         struct security_acl *acl_to_add;
      57             :         enum acl_mode mode;
      58             :         char *the_acl;
      59             :         bool acl_no_propagate;
      60             :         bool numeric;
      61             : };
      62             : 
      63             : /*
      64             :  * if this dfs link is local to this share then we need to
      65             :  * adjust targetpath. A local dfs link is prepended with
      66             :  * '/$SERVER/$SHARE/path_from_args' The 'full' path is not
      67             :  * suitable for passing to cli_list (and will fail)
      68             :  */
      69        2156 : static NTSTATUS local_cli_resolve_path(TALLOC_CTX* ctx,
      70             :                         const char *mountpt,
      71             :                         struct cli_credentials *creds,
      72             :                         struct cli_state *rootcli,
      73             :                         const char *path,
      74             :                         struct cli_state **targetcli,
      75             :                         char **pp_targetpath)
      76             : {
      77        2156 :         size_t searchlen = 0;
      78        2156 :         char *search = NULL;
      79             :         NTSTATUS status;
      80             : 
      81        2156 :         status = cli_resolve_path(ctx,
      82             :                                 mountpt,
      83             :                                 creds,
      84             :                                 rootcli,
      85             :                                 path,
      86             :                                 targetcli,
      87             :                                 pp_targetpath);
      88        2156 :         if (!NT_STATUS_IS_OK(status)) {
      89           0 :                 return status;
      90             :         }
      91             : 
      92        2156 :         search = talloc_asprintf(ctx, "\\%s\\%s",
      93             :                         rootcli->server_domain,
      94             :                         rootcli->share);
      95        2156 :         if (search == NULL) {
      96           0 :                 return NT_STATUS_NO_MEMORY;
      97             :         }
      98             : 
      99        2156 :         searchlen = strlen(search);
     100             : 
     101        2156 :         if (strncmp(*pp_targetpath, search, searchlen) == 0) {
     102        1128 :                 *pp_targetpath += searchlen;
     103             :         }
     104        2156 :         return status;
     105             : }
     106             : 
     107           4 : static NTSTATUS cli_lsa_lookup_domain_sid(struct cli_state *cli,
     108             :                                           struct dom_sid *sid)
     109             : {
     110           4 :         union lsa_PolicyInformation *info = NULL;
     111           4 :         struct smbXcli_tcon *orig_tcon = NULL;
     112           4 :         struct rpc_pipe_client *rpc_pipe = NULL;
     113             :         struct policy_handle handle;
     114             :         NTSTATUS status, result;
     115           4 :         TALLOC_CTX *frame = talloc_stackframe();
     116             : 
     117           4 :         if (cli_state_has_tcon(cli)) {
     118           4 :                 orig_tcon = cli_state_save_tcon(cli);
     119           4 :                 if (orig_tcon == NULL) {
     120           0 :                         status = NT_STATUS_NO_MEMORY;
     121           0 :                         goto done;
     122             :                 }
     123             :         }
     124             : 
     125           4 :         status = cli_tree_connect(cli, "IPC$", "?????", NULL);
     126           4 :         if (!NT_STATUS_IS_OK(status)) {
     127           0 :                 goto done;
     128             :         }
     129             : 
     130           4 :         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc, &rpc_pipe);
     131           4 :         if (!NT_STATUS_IS_OK(status)) {
     132           0 :                 goto tdis;
     133             :         }
     134             : 
     135           4 :         status = rpccli_lsa_open_policy(rpc_pipe, frame, True,
     136             :                                         GENERIC_EXECUTE_ACCESS, &handle);
     137           4 :         if (!NT_STATUS_IS_OK(status)) {
     138           0 :                 goto tdis;
     139             :         }
     140             : 
     141           4 :         status = dcerpc_lsa_QueryInfoPolicy2(rpc_pipe->binding_handle,
     142             :                                              frame, &handle,
     143             :                                              LSA_POLICY_INFO_DOMAIN,
     144             :                                              &info, &result);
     145             : 
     146           4 :         if (any_nt_status_not_ok(status, result, &status)) {
     147           4 :                 goto tdis;
     148             :         }
     149             : 
     150           0 :         *sid = *info->domain.sid;
     151             : 
     152           4 : tdis:
     153           4 :         TALLOC_FREE(rpc_pipe);
     154           4 :         cli_tdis(cli);
     155           4 : done:
     156           4 :         cli_state_restore_tcon(cli, orig_tcon);
     157           4 :         TALLOC_FREE(frame);
     158           4 :         return status;
     159             : }
     160             : 
     161           4 : static struct dom_sid *get_domain_sid(struct cli_state *cli)
     162             : {
     163             :         NTSTATUS status;
     164             :         struct dom_sid_buf buf;
     165             : 
     166           4 :         struct dom_sid *sid = talloc(talloc_tos(), struct dom_sid);
     167           4 :         if (sid == NULL) {
     168           0 :                 DEBUG(0, ("Out of memory\n"));
     169           0 :                 return NULL;
     170             :         }
     171             : 
     172           4 :         if (domain_sid) {
     173           0 :                 if (!dom_sid_parse(domain_sid, sid)) {
     174           0 :                         DEBUG(0,("failed to parse domain sid\n"));
     175           0 :                         TALLOC_FREE(sid);
     176             :                 }
     177             :         } else {
     178           4 :                 status = cli_lsa_lookup_domain_sid(cli, sid);
     179             : 
     180           4 :                 if (!NT_STATUS_IS_OK(status)) {
     181           4 :                         DEBUG(0,("failed to lookup domain sid: %s\n", nt_errstr(status)));
     182           4 :                         TALLOC_FREE(sid);
     183             :                 }
     184             : 
     185             :         }
     186             : 
     187           4 :         DEBUG(2,("Domain SID: %s\n", dom_sid_str_buf(sid, &buf)));
     188           4 :         return sid;
     189             : }
     190             : 
     191             : /* add an ACE to a list of ACEs in a struct security_acl */
     192        7824 : static bool add_ace_with_ctx(TALLOC_CTX *ctx, struct security_acl **the_acl,
     193             :                              const struct security_ace *ace)
     194             : 
     195             : {
     196        7824 :         struct security_acl *acl = *the_acl;
     197             : 
     198        7824 :         if (acl == NULL) {
     199        2100 :                 acl = make_sec_acl(ctx, 3, 0, NULL);
     200        2100 :                 if (acl == NULL) {
     201           0 :                         return false;
     202             :                 }
     203             :         }
     204             : 
     205        7824 :         if (acl->num_aces == UINT32_MAX) {
     206           0 :                 return false;
     207             :         }
     208        7824 :         ADD_TO_ARRAY(
     209             :                 acl, struct security_ace, *ace, &acl->aces, &acl->num_aces);
     210        7824 :         *the_acl = acl;
     211        7824 :         return True;
     212             : }
     213             : 
     214        1516 : static bool add_ace(struct security_acl **the_acl, struct security_ace *ace)
     215             : {
     216        1516 :         return add_ace_with_ctx(talloc_tos(), the_acl, ace);
     217             : }
     218             : 
     219             : /* parse a ascii version of a security descriptor */
     220        1242 : static struct security_descriptor *sec_desc_parse(TALLOC_CTX *ctx, struct cli_state *cli, char *str)
     221             : {
     222        1242 :         const char *p = str;
     223             :         char *tok;
     224        1242 :         struct security_descriptor *ret = NULL;
     225             :         size_t sd_size;
     226        1242 :         struct dom_sid owner_sid = { .num_auths = 0 };
     227        1242 :         bool have_owner = false;
     228        1242 :         struct dom_sid group_sid = { .num_auths = 0 };
     229        1242 :         bool have_group = false;
     230        1242 :         struct security_acl *dacl=NULL;
     231        1242 :         int revision=1;
     232             : 
     233        3762 :         while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) {
     234        1278 :                 if (strncmp(tok,"REVISION:", 9) == 0) {
     235          12 :                         revision = strtol(tok+9, NULL, 16);
     236          12 :                         continue;
     237             :                 }
     238             : 
     239        1266 :                 if (strncmp(tok,"OWNER:", 6) == 0) {
     240          12 :                         if (have_owner) {
     241           0 :                                 printf("Only specify owner once\n");
     242           0 :                                 goto done;
     243             :                         }
     244          12 :                         if (!StringToSid(cli, &owner_sid, tok+6)) {
     245           0 :                                 printf("Failed to parse owner sid\n");
     246           0 :                                 goto done;
     247             :                         }
     248          12 :                         have_owner = true;
     249          12 :                         continue;
     250             :                 }
     251             : 
     252        1254 :                 if (strncmp(tok,"GROUP:", 6) == 0) {
     253          12 :                         if (have_group) {
     254           0 :                                 printf("Only specify group once\n");
     255           0 :                                 goto done;
     256             :                         }
     257          12 :                         if (!StringToSid(cli, &group_sid, tok+6)) {
     258           0 :                                 printf("Failed to parse group sid\n");
     259           0 :                                 goto done;
     260             :                         }
     261          12 :                         have_group = true;
     262          12 :                         continue;
     263             :                 }
     264             : 
     265        1242 :                 if (strncmp(tok,"ACL:", 4) == 0) {
     266             :                         struct security_ace ace;
     267        1242 :                         if (!parse_ace(cli, &ace, tok+4)) {
     268           0 :                                 goto done;
     269             :                         }
     270        1242 :                         if(!add_ace(&dacl, &ace)) {
     271           0 :                                 printf("Failed to add ACL %s\n", tok);
     272           0 :                                 goto done;
     273             :                         }
     274        1242 :                         continue;
     275             :                 }
     276             : 
     277           0 :                 printf("Failed to parse token '%s' in security descriptor,\n", tok);
     278           0 :                 goto done;
     279             :         }
     280             : 
     281        1242 :         ret = make_sec_desc(
     282             :                 ctx,
     283             :                 revision,
     284             :                 SEC_DESC_SELF_RELATIVE,
     285             :                 have_owner ? &owner_sid : NULL,
     286             :                 have_group ? &group_sid : NULL,
     287             :                 NULL,
     288             :                 dacl,
     289             :                 &sd_size);
     290             : 
     291        1242 : done:
     292        1242 :         return ret;
     293             : }
     294             : 
     295             : /*****************************************************
     296             : get fileinfo for filename
     297             : *******************************************************/
     298         666 : static uint16_t get_fileinfo(struct cli_state *cli, const char *filename)
     299             : {
     300         666 :         uint16_t fnum = (uint16_t)-1;
     301             :         NTSTATUS status;
     302         666 :         struct smb_create_returns cr = {0};
     303             : 
     304             :         /* The desired access below is the only one I could find that works
     305             :            with NT4, W2KP and Samba */
     306             : 
     307         666 :         status = cli_ntcreate(
     308             :                 cli,                    /* cli */
     309             :                 filename,               /* fname */
     310             :                 0,                      /* CreatFlags */
     311             :                 READ_CONTROL_ACCESS,    /* CreatFlags */
     312             :                 0,                      /* FileAttributes */
     313             :                 FILE_SHARE_READ|
     314             :                 FILE_SHARE_WRITE,       /* ShareAccess */
     315             :                 FILE_OPEN,              /* CreateDisposition */
     316             :                 0x0,                    /* CreateOptions */
     317             :                 0x0,                    /* SecurityFlags */
     318             :                 &fnum,                      /* pfid */
     319             :                 &cr);                       /* cr */
     320         666 :         if (!NT_STATUS_IS_OK(status)) {
     321           0 :                 printf("Failed to open %s: %s\n", filename, nt_errstr(status));
     322           0 :                 return 0;
     323             :         }
     324             : 
     325         666 :         cli_close(cli, fnum);
     326         666 :         return cr.file_attributes;
     327             : }
     328             : 
     329             : /*****************************************************
     330             : get sec desc for filename
     331             : *******************************************************/
     332        2794 : static struct security_descriptor *get_secdesc_with_ctx(TALLOC_CTX *ctx,
     333             :                                                         struct cli_state *cli,
     334             :                                                         const char *filename)
     335             : {
     336        2794 :         uint16_t fnum = (uint16_t)-1;
     337             :         struct security_descriptor *sd;
     338             :         NTSTATUS status;
     339             :         uint32_t sec_info;
     340        2794 :         uint32_t desired_access = 0;
     341             : 
     342        2794 :         if (query_sec_info == -1) {
     343        2794 :                 sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL;
     344             :         } else {
     345           0 :                 sec_info = query_sec_info;
     346             :         }
     347             : 
     348        2794 :         if (sec_info & (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL)) {
     349        2794 :                 desired_access |= SEC_STD_READ_CONTROL;
     350             :         }
     351        2794 :         if (sec_info & SECINFO_SACL) {
     352           0 :                 desired_access |= SEC_FLAG_SYSTEM_SECURITY;
     353             :         }
     354             : 
     355        2794 :         if (desired_access == 0) {
     356           0 :                 desired_access |= SEC_STD_READ_CONTROL;
     357             :         }
     358             : 
     359        2794 :         status = cli_ntcreate(cli, filename, 0, desired_access,
     360             :                               0, FILE_SHARE_READ|FILE_SHARE_WRITE,
     361             :                               FILE_OPEN, 0x0, 0x0, &fnum, NULL);
     362        2794 :         if (!NT_STATUS_IS_OK(status)) {
     363           0 :                 printf("Failed to open %s: %s\n", filename, nt_errstr(status));
     364           0 :                 return NULL;
     365             :         }
     366             : 
     367        2794 :         status = cli_query_security_descriptor(cli, fnum, sec_info,
     368             :                                                ctx, &sd);
     369             : 
     370        2794 :         cli_close(cli, fnum);
     371             : 
     372        2794 :         if (!NT_STATUS_IS_OK(status)) {
     373           0 :                 printf("Failed to get security descriptor: %s\n",
     374             :                        nt_errstr(status));
     375           0 :                 return NULL;
     376             :         }
     377        2794 :         return sd;
     378             : }
     379             : 
     380        1816 : static struct security_descriptor *get_secdesc(struct cli_state *cli,
     381             :                                                const char *filename)
     382             : {
     383        1816 :         return get_secdesc_with_ctx(talloc_tos(), cli, filename);
     384             : }
     385             : /*****************************************************
     386             : set sec desc for filename
     387             : *******************************************************/
     388        1830 : static bool set_secdesc(struct cli_state *cli, const char *filename,
     389             :                         struct security_descriptor *sd)
     390             : {
     391        1830 :         uint16_t fnum = (uint16_t)-1;
     392        1830 :         bool result=true;
     393             :         NTSTATUS status;
     394        1830 :         uint32_t desired_access = 0;
     395             :         uint32_t sec_info;
     396             : 
     397        1830 :         if (set_sec_info == -1) {
     398        1830 :                 sec_info = 0;
     399             : 
     400        1830 :                 if (sd->dacl || (sd->type & SEC_DESC_DACL_PRESENT)) {
     401        1792 :                         sec_info |= SECINFO_DACL;
     402             :                 }
     403        1830 :                 if (sd->sacl || (sd->type & SEC_DESC_SACL_PRESENT)) {
     404           0 :                         sec_info |= SECINFO_SACL;
     405             :                 }
     406        1830 :                 if (sd->owner_sid) {
     407        1758 :                         sec_info |= SECINFO_OWNER;
     408             :                 }
     409        1830 :                 if (sd->group_sid) {
     410        1728 :                         sec_info |= SECINFO_GROUP;
     411             :                 }
     412             :         } else {
     413           0 :                 sec_info = set_sec_info;
     414             :         }
     415             : 
     416             :         /* Make the desired_access more specific. */
     417        1830 :         if (sec_info & SECINFO_DACL) {
     418        1792 :                 desired_access |= SEC_STD_WRITE_DAC;
     419             :         }
     420        1830 :         if (sec_info & SECINFO_SACL) {
     421           0 :                 desired_access |= SEC_FLAG_SYSTEM_SECURITY;
     422             :         }
     423        1830 :         if (sec_info & (SECINFO_OWNER | SECINFO_GROUP)) {
     424        1762 :                 desired_access |= SEC_STD_WRITE_OWNER;
     425             :         }
     426             : 
     427        1830 :         status = cli_ntcreate(cli, filename, 0,
     428             :                               desired_access,
     429             :                               0, FILE_SHARE_READ|FILE_SHARE_WRITE,
     430             :                               FILE_OPEN, 0x0, 0x0, &fnum, NULL);
     431        1830 :         if (!NT_STATUS_IS_OK(status)) {
     432           0 :                 printf("Failed to open %s: %s\n", filename, nt_errstr(status));
     433           0 :                 return false;
     434             :         }
     435             : 
     436        1830 :         status = cli_set_security_descriptor(cli, fnum, sec_info, sd);
     437        1830 :         if (!NT_STATUS_IS_OK(status)) {
     438           2 :                 printf("ERROR: security descriptor set failed: %s\n",
     439             :                        nt_errstr(status));
     440           2 :                 result=false;
     441             :         }
     442             : 
     443        1830 :         cli_close(cli, fnum);
     444        1830 :         return result;
     445             : }
     446             : 
     447             : /*****************************************************
     448             : get maximum access for a file
     449             : *******************************************************/
     450           4 : static int cacl_mxac(struct cli_state *cli, const char *filename)
     451             : {
     452             :         NTSTATUS status;
     453             :         uint32_t mxac;
     454             : 
     455           4 :         status = cli_query_mxac(cli, filename, &mxac);
     456           4 :         if (!NT_STATUS_IS_OK(status)) {
     457           0 :                 printf("Failed to get mxac: %s\n", nt_errstr(status));
     458           0 :                 return EXIT_FAILED;
     459             :         }
     460             : 
     461           4 :         printf("Maximum access: 0x%x\n", mxac);
     462             : 
     463           4 :         return EXIT_OK;
     464             : }
     465             : 
     466             : 
     467             : /*****************************************************
     468             : dump the acls for a file
     469             : *******************************************************/
     470         638 : static int cacl_dump(struct cli_state *cli, const char *filename, bool numeric)
     471             : {
     472             :         struct security_descriptor *sd;
     473             :         int ret;
     474             : 
     475         638 :         if (test_args) {
     476           0 :                 return EXIT_OK;
     477             :         }
     478             : 
     479         638 :         sd = get_secdesc(cli, filename);
     480         638 :         if (sd == NULL) {
     481           0 :                 return EXIT_FAILED;
     482             :         }
     483             : 
     484         638 :         if (sddl) {
     485           4 :                 char *str = sddl_encode(talloc_tos(), sd, get_domain_sid(cli));
     486           4 :                 if (str == NULL) {
     487           0 :                         return EXIT_FAILED;
     488             :                 }
     489           4 :                 printf("%s\n", str);
     490           4 :                 TALLOC_FREE(str);
     491             :         } else {
     492         634 :                 sec_desc_print(cli, stdout, sd, numeric);
     493             :         }
     494             : 
     495         638 :         if (want_mxac) {
     496           4 :                 ret = cacl_mxac(cli, filename);
     497           4 :                 if (ret != EXIT_OK) {
     498           0 :                         return ret;
     499             :                 }
     500             :         }
     501             : 
     502         638 :         return EXIT_OK;
     503             : }
     504             : 
     505             : /***************************************************** 
     506             : Change the ownership or group ownership of a file. Just
     507             : because the NT docs say this can't be done :-). JRA.
     508             : *******************************************************/
     509             : 
     510          38 : static int owner_set(struct cli_state *cli, enum chown_mode change_mode, 
     511             :                         const char *filename, const char *new_username)
     512             : {
     513             :         struct dom_sid sid;
     514             :         struct security_descriptor *sd;
     515             :         size_t sd_size;
     516             : 
     517          38 :         if (!StringToSid(cli, &sid, new_username))
     518           0 :                 return EXIT_PARSE_ERROR;
     519             : 
     520          38 :         sd = make_sec_desc(talloc_tos(),
     521             :                            SECURITY_DESCRIPTOR_REVISION_1,
     522             :                            SEC_DESC_SELF_RELATIVE,
     523             :                            (change_mode == REQUEST_CHOWN) ? &sid : NULL,
     524             :                            (change_mode == REQUEST_CHGRP) ? &sid : NULL,
     525             :                            NULL, NULL, &sd_size);
     526             : 
     527          38 :         if (!set_secdesc(cli, filename, sd)) {
     528           2 :                 return EXIT_FAILED;
     529             :         }
     530             : 
     531          36 :         return EXIT_OK;
     532             : }
     533             : 
     534             : 
     535             : /* The MSDN is contradictory over the ordering of ACE entries in an
     536             :    ACL.  However NT4 gives a "The information may have been modified
     537             :    by a computer running Windows NT 5.0" if denied ACEs do not appear
     538             :    before allowed ACEs. At
     539             :    http://technet.microsoft.com/en-us/library/cc781716.aspx the
     540             :    canonical order is specified as "Explicit Deny, Explicit Allow,
     541             :    Inherited ACEs unchanged" */
     542             : 
     543       19250 : static int ace_compare(struct security_ace *ace1, struct security_ace *ace2)
     544             : {
     545       19250 :         if (security_ace_equal(ace1, ace2))
     546         364 :                 return 0;
     547             : 
     548       24478 :         if ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) &&
     549        5592 :                         !(ace2->flags & SEC_ACE_FLAG_INHERITED_ACE))
     550        1696 :                 return 1;
     551       30484 :         if (!(ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) &&
     552       13294 :                         (ace2->flags & SEC_ACE_FLAG_INHERITED_ACE))
     553        2622 :                 return -1;
     554       18464 :         if ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) &&
     555        3896 :                         (ace2->flags & SEC_ACE_FLAG_INHERITED_ACE))
     556        3896 :                 return ace1 - ace2;
     557             : 
     558       10672 :         if (ace1->type != ace2->type)
     559           0 :                 return ace2->type - ace1->type;
     560             : 
     561       10672 :         if (dom_sid_compare(&ace1->trustee, &ace2->trustee))
     562       10476 :                 return dom_sid_compare(&ace1->trustee, &ace2->trustee);
     563             : 
     564         196 :         if (ace1->flags != ace2->flags)
     565         196 :                 return ace1->flags - ace2->flags;
     566             : 
     567           0 :         if (ace1->access_mask != ace2->access_mask)
     568           0 :                 return ace1->access_mask - ace2->access_mask;
     569             : 
     570           0 :         if (ace1->size != ace2->size)
     571           0 :                 return ace1->size - ace2->size;
     572             : 
     573           0 :         return memcmp(ace1, ace2, sizeof(struct security_ace));
     574             : }
     575             : 
     576        1792 : static void sort_acl(struct security_acl *the_acl)
     577             : {
     578             :         uint32_t i;
     579        1792 :         if (!the_acl) return;
     580             : 
     581        1792 :         TYPESAFE_QSORT(the_acl->aces, the_acl->num_aces, ace_compare);
     582             : 
     583       13084 :         for (i=1;i<the_acl->num_aces;) {
     584        9500 :                 if (security_ace_equal(&the_acl->aces[i-1],
     585        9500 :                                        &the_acl->aces[i])) {
     586          46 :                         ARRAY_DEL_ELEMENT(
     587             :                                 the_acl->aces, i, the_acl->num_aces);
     588          46 :                         the_acl->num_aces--;
     589             :                 } else {
     590        9454 :                         i++;
     591             :                 }
     592             :         }
     593             : }
     594             : 
     595             : /***************************************************** 
     596             : set the ACLs on a file given a security descriptor
     597             : *******************************************************/
     598             : 
     599        1774 : static int cacl_set_from_sd(struct cli_state *cli, const char *filename,
     600             :                             struct security_descriptor *sd, enum acl_mode mode,
     601             :                             bool numeric)
     602             : {
     603        1774 :         struct security_descriptor *old = NULL;
     604             :         uint32_t i, j;
     605             :         size_t sd_size;
     606        1774 :         int result = EXIT_OK;
     607             : 
     608        1774 :         if (!sd) return EXIT_PARSE_ERROR;
     609        1774 :         if (test_args) return EXIT_OK;
     610             : 
     611        1774 :         if (mode != SMB_ACL_SET) {
     612             :                 /*
     613             :                  * Do not fetch old ACL when it will be overwritten
     614             :                  * completely with a new one.
     615             :                  */
     616        1160 :                 old = get_secdesc(cli, filename);
     617             : 
     618        1160 :                 if (!old) {
     619           0 :                         return EXIT_FAILED;
     620             :                 }
     621             :         }
     622             : 
     623             :         /* the logic here is rather more complex than I would like */
     624        1774 :         switch (mode) {
     625          66 :         case SMB_ACL_DELETE:
     626         172 :                 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
     627          66 :                         bool found = False;
     628             : 
     629         316 :                         for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
     630         290 :                                 if (security_ace_equal(&sd->dacl->aces[i],
     631         290 :                                                        &old->dacl->aces[j])) {
     632             :                                         uint32_t k;
     633          84 :                                         for (k=j; k<old->dacl->num_aces-1;k++) {
     634          44 :                                                 old->dacl->aces[k] = old->dacl->aces[k+1];
     635             :                                         }
     636          40 :                                         old->dacl->num_aces--;
     637          40 :                                         found = True;
     638          40 :                                         break;
     639             :                                 }
     640             :                         }
     641             : 
     642          66 :                         if (!found) {
     643          26 :                                 printf("ACL for ACE:");
     644          26 :                                 print_ace(cli, stdout, &sd->dacl->aces[i],
     645             :                                           numeric);
     646          26 :                                 printf(" not found\n");
     647             :                         }
     648             :                 }
     649          66 :                 break;
     650             : 
     651         820 :         case SMB_ACL_MODIFY:
     652        2460 :                 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
     653         820 :                         bool found = False;
     654             : 
     655        4492 :                         for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
     656        3672 :                                 if (dom_sid_equal(&sd->dacl->aces[i].trustee,
     657        3672 :                                               &old->dacl->aces[j].trustee)) {
     658         856 :                                         old->dacl->aces[j] = sd->dacl->aces[i];
     659         856 :                                         found = True;
     660             :                                 }
     661             :                         }
     662             : 
     663         820 :                         if (!found) {
     664             :                                 fstring str;
     665             : 
     666           0 :                                 SidToString(cli, str,
     667           0 :                                             &sd->dacl->aces[i].trustee,
     668             :                                             numeric);
     669           0 :                                 printf("ACL for SID %s not found\n", str);
     670             :                         }
     671             :                 }
     672             : 
     673         820 :                 if (sd->owner_sid) {
     674           0 :                         old->owner_sid = sd->owner_sid;
     675             :                 }
     676             : 
     677         820 :                 if (sd->group_sid) {
     678           0 :                         old->group_sid = sd->group_sid;
     679             :                 }
     680             : 
     681         820 :                 break;
     682             : 
     683         274 :         case SMB_ACL_ADD:
     684         548 :                 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
     685         274 :                         add_ace(&old->dacl, &sd->dacl->aces[i]);
     686             :                 }
     687         274 :                 break;
     688             : 
     689         614 :         case SMB_ACL_SET:
     690         614 :                 old = sd;
     691         614 :                 break;
     692             :         }
     693             : 
     694             :         /* Denied ACE entries must come before allowed ones */
     695        1774 :         sort_acl(old->dacl);
     696             : 
     697             :         /* Create new security descriptor and set it */
     698             : 
     699             :         /* We used to just have "WRITE_DAC_ACCESS" without WRITE_OWNER.
     700             :            But if we're sending an owner, even if it's the same as the one
     701             :            that already exists then W2K3 insists we open with WRITE_OWNER access.
     702             :            I need to check that setting a SD with no owner set works against WNT
     703             :            and W2K. JRA.
     704             :         */
     705             : 
     706        3548 :         sd = make_sec_desc(talloc_tos(),old->revision, old->type,
     707        1774 :                            old->owner_sid, old->group_sid,
     708             :                            NULL, old->dacl, &sd_size);
     709             : 
     710        1774 :         if (!set_secdesc(cli, filename, sd)) {
     711           0 :                 result = EXIT_FAILED;
     712             :         }
     713             : 
     714        1774 :         return result;
     715             : }
     716             : 
     717             : /*****************************************************
     718             : set the ACLs on a file given an ascii description
     719             : *******************************************************/
     720             : 
     721        1132 : static int cacl_set(struct cli_state *cli, const char *filename,
     722             :                     char *the_acl, enum acl_mode mode, bool numeric)
     723             : {
     724        1132 :         struct security_descriptor *sd = NULL;
     725             : 
     726        1132 :         if (sddl) {
     727           4 :                 sd = sddl_decode(talloc_tos(), the_acl, get_global_sam_sid());
     728             :         } else {
     729        1128 :                 sd = sec_desc_parse(talloc_tos(), cli, the_acl);
     730             :         }
     731             : 
     732        1132 :         if (sd == NULL) {
     733           0 :                 return EXIT_PARSE_ERROR;
     734             :         }
     735        1132 :         if (test_args) {
     736           0 :                 return EXIT_OK;
     737             :         }
     738        1132 :         return cacl_set_from_sd(cli, filename, sd, mode, numeric);
     739             : }
     740             : 
     741             : /*****************************************************
     742             : set the inherit on a file
     743             : *******************************************************/
     744          18 : static int inherit(struct cli_state *cli, const char *filename,
     745             :                    const char *type)
     746             : {
     747             :         struct security_descriptor *old,*sd;
     748             :         uint32_t oldattr;
     749             :         size_t sd_size;
     750          18 :         int result = EXIT_OK;
     751             : 
     752          18 :         old = get_secdesc(cli, filename);
     753             : 
     754          18 :         if (!old) {
     755           0 :                 return EXIT_FAILED;
     756             :         }
     757             : 
     758          18 :         oldattr = get_fileinfo(cli,filename);
     759             : 
     760          18 :         if (strcmp(type,"allow")==0) {
     761           0 :                 if ((old->type & SEC_DESC_DACL_PROTECTED) ==
     762             :                     SEC_DESC_DACL_PROTECTED) {
     763             :                         uint32_t i;
     764             :                         char *parentname,*temp;
     765             :                         struct security_descriptor *parent;
     766           0 :                         temp = talloc_strdup(talloc_tos(), filename);
     767             : 
     768           0 :                         old->type=old->type & (~SEC_DESC_DACL_PROTECTED);
     769             : 
     770             :                         /* look at parent and copy in all its inheritable ACL's. */
     771           0 :                         string_replace(temp, '\\', '/');
     772           0 :                         if (!parent_dirname(talloc_tos(),temp,&parentname,NULL)) {
     773           0 :                                 return EXIT_FAILED;
     774             :                         }
     775           0 :                         string_replace(parentname, '/', '\\');
     776           0 :                         parent = get_secdesc(cli,parentname);
     777           0 :                         if (parent == NULL) {
     778           0 :                                 return EXIT_FAILED;
     779             :                         }
     780           0 :                         for (i=0;i<parent->dacl->num_aces;i++) {
     781           0 :                                 struct security_ace *ace=&parent->dacl->aces[i];
     782             :                                 /* Add inherited flag to all aces */
     783           0 :                                 ace->flags=ace->flags|
     784             :                                            SEC_ACE_FLAG_INHERITED_ACE;
     785           0 :                                 if ((oldattr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
     786           0 :                                         if ((ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) ==
     787             :                                             SEC_ACE_FLAG_CONTAINER_INHERIT) {
     788           0 :                                                 add_ace(&old->dacl, ace);
     789             :                                         }
     790             :                                 } else {
     791           0 :                                         if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) ==
     792             :                                             SEC_ACE_FLAG_OBJECT_INHERIT) {
     793             :                                                 /* clear flags for files */
     794           0 :                                                 ace->flags=0;
     795           0 :                                                 add_ace(&old->dacl, ace);
     796             :                                         }
     797             :                                 }
     798             :                         }
     799             :                 } else {
     800           0 :                         printf("Already set to inheritable permissions.\n");
     801           0 :                         return EXIT_FAILED;
     802             :                 }
     803          18 :         } else if (strcmp(type,"remove")==0) {
     804           0 :                 if ((old->type & SEC_DESC_DACL_PROTECTED) !=
     805             :                     SEC_DESC_DACL_PROTECTED) {
     806           0 :                         old->type=old->type | SEC_DESC_DACL_PROTECTED;
     807             : 
     808             :                         /* remove all inherited ACL's. */
     809           0 :                         if (old->dacl) {
     810             :                                 int i;
     811           0 :                                 struct security_acl *temp=old->dacl;
     812           0 :                                 old->dacl=make_sec_acl(talloc_tos(), 3, 0, NULL);
     813           0 :                                 for (i=temp->num_aces-1;i>=0;i--) {
     814           0 :                                         struct security_ace *ace=&temp->aces[i];
     815             :                                         /* Remove all ace with INHERITED flag set */
     816           0 :                                         if ((ace->flags & SEC_ACE_FLAG_INHERITED_ACE) !=
     817             :                                             SEC_ACE_FLAG_INHERITED_ACE) {
     818           0 :                                                 add_ace(&old->dacl,ace);
     819             :                                         }
     820             :                                 }
     821             :                         }
     822             :                 } else {
     823           0 :                         printf("Already set to no inheritable permissions.\n");
     824           0 :                         return EXIT_FAILED;
     825             :                 }
     826          18 :         } else if (strcmp(type,"copy")==0) {
     827          18 :                 if ((old->type & SEC_DESC_DACL_PROTECTED) !=
     828             :                     SEC_DESC_DACL_PROTECTED) {
     829          18 :                         old->type=old->type | SEC_DESC_DACL_PROTECTED;
     830             : 
     831             :                         /*
     832             :                          * convert all inherited ACL's to non
     833             :                          * inherited ACL's.
     834             :                          */
     835          18 :                         if (old->dacl) {
     836             :                                 uint32_t i;
     837         108 :                                 for (i=0;i<old->dacl->num_aces;i++) {
     838          90 :                                         struct security_ace *ace=&old->dacl->aces[i];
     839             :                                         /* Remove INHERITED FLAG from all aces */
     840          90 :                                         ace->flags=ace->flags&(~SEC_ACE_FLAG_INHERITED_ACE);
     841             :                                 }
     842             :                         }
     843             :                 } else {
     844           0 :                         printf("Already set to no inheritable permissions.\n");
     845           0 :                         return EXIT_FAILED;
     846             :                 }
     847             :         }
     848             : 
     849             :         /* Denied ACE entries must come before allowed ones */
     850          18 :         sort_acl(old->dacl);
     851             : 
     852          36 :         sd = make_sec_desc(talloc_tos(),old->revision, old->type,
     853          18 :                            old->owner_sid, old->group_sid,
     854             :                            NULL, old->dacl, &sd_size);
     855             : 
     856          18 :         if (!set_secdesc(cli, filename, sd)) {
     857           0 :                 result = EXIT_FAILED;
     858             :         }
     859             : 
     860          18 :         return result;
     861             : }
     862             : 
     863             : /*****************************************************
     864             :  Return a connection to a server.
     865             : *******************************************************/
     866        1940 : static struct cli_state *connect_one(struct cli_credentials *creds,
     867             :                                      const char *server, const char *share)
     868             : {
     869        1940 :         struct cli_state *c = NULL;
     870             :         NTSTATUS nt_status;
     871        1940 :         uint32_t flags = 0;
     872             : 
     873        1940 :         nt_status = cli_full_connection_creds(&c, lp_netbios_name(), server,
     874             :                                 NULL, 0,
     875             :                                 share, "?????",
     876             :                                 creds,
     877             :                                 flags);
     878        1940 :         if (!NT_STATUS_IS_OK(nt_status)) {
     879           0 :                 DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
     880           0 :                 return NULL;
     881             :         }
     882             : 
     883        1940 :         return c;
     884             : }
     885             : 
     886             : /*
     887             :  * Process resulting combination of mask & fname ensuring
     888             :  * terminated with wildcard
     889             :  */
     890         216 : static char *build_dirname(TALLOC_CTX *ctx,
     891             :         const char *mask, char *dir, char *fname)
     892             : {
     893         216 :         char *mask2 = NULL;
     894         216 :         char *p = NULL;
     895             : 
     896         216 :         mask2 = talloc_strdup(ctx, mask);
     897         216 :         if (!mask2) {
     898           0 :                 return NULL;
     899             :         }
     900         216 :         p = strrchr_m(mask2, DIRSEP_CHAR);
     901         216 :         if (p) {
     902         216 :                 p[1] = 0;
     903             :         } else {
     904           0 :                 mask2[0] = '\0';
     905             :         }
     906         216 :         mask2 = talloc_asprintf_append(mask2,
     907             :                                 "%s\\*",
     908             :                                 fname);
     909         216 :         return mask2;
     910             : }
     911             : 
     912             : /*
     913             :  * Returns the a copy of the ACL flags in ace modified according
     914             :  * to some inheritance rules.
     915             :  *   a) SEC_ACE_FLAG_INHERITED_ACE is propagated to children
     916             :  *   b) SEC_ACE_FLAG_INHERIT_ONLY is set on container children for OI (only)
     917             :  *   c) SEC_ACE_FLAG_OBJECT_INHERIT & SEC_ACE_FLAG_CONTAINER_INHERIT are
     918             :  *      stripped from flags to be propagated to non-container children
     919             :  *   d) SEC_ACE_FLAG_OBJECT_INHERIT & SEC_ACE_FLAG_CONTAINER_INHERIT are
     920             :  *      stripped from flags to be propagated if the NP flag
     921             :  *      SEC_ACE_FLAG_NO_PROPAGATE_INHERIT is present
     922             :  */
     923             : 
     924        3270 : static uint8_t get_flags_to_propagate(bool is_container,
     925             :                                 struct security_ace *ace)
     926             : {
     927        3270 :         uint8_t newflags = ace->flags;
     928             :         /* OBJECT inheritance */
     929        3270 :         bool acl_objinherit = (ace->flags &
     930             :                 SEC_ACE_FLAG_OBJECT_INHERIT) == SEC_ACE_FLAG_OBJECT_INHERIT;
     931             :         /* CONTAINER inheritance */
     932        3270 :         bool acl_cntrinherit = (ace->flags &
     933             :                 SEC_ACE_FLAG_CONTAINER_INHERIT) ==
     934             :                         SEC_ACE_FLAG_CONTAINER_INHERIT;
     935             :         /* PROHIBIT inheritance */
     936        3270 :         bool prohibit_inheritance = ((ace->flags &
     937             :                 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) ==
     938             :                         SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
     939             : 
     940             :         /* Assume we are not propagating the ACE */
     941             : 
     942        3270 :         newflags &= ~SEC_ACE_FLAG_INHERITED_ACE;
     943             :         /* all children need to have the SEC_ACE_FLAG_INHERITED_ACE set */
     944        3270 :         if (acl_cntrinherit || acl_objinherit) {
     945             :                 /*
     946             :                  * object inherit ( alone ) on a container needs
     947             :                  * SEC_ACE_FLAG_INHERIT_ONLY
     948             :                  */
     949        3270 :                 if (is_container) {
     950        1128 :                         if (acl_objinherit && !acl_cntrinherit) {
     951          30 :                                 newflags |= SEC_ACE_FLAG_INHERIT_ONLY;
     952             :                         }
     953             :                         /*
     954             :                          * this is tricky, the only time we would not
     955             :                          * propagate the ace for a container is if
     956             :                          * prohibit_inheritance is set and object inheritance
     957             :                          * alone is set
     958             :                          */
     959        1128 :                         if ((prohibit_inheritance
     960          18 :                             && acl_objinherit
     961        1140 :                             && !acl_cntrinherit) == false) {
     962        1122 :                                 newflags |= SEC_ACE_FLAG_INHERITED_ACE;
     963             :                         }
     964             :                 } else {
     965             :                         /*
     966             :                          * don't apply object/container inheritance flags to
     967             :                          * non dirs
     968             :                          */
     969        2142 :                         newflags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT
     970             :                                         | SEC_ACE_FLAG_CONTAINER_INHERIT
     971             :                                         | SEC_ACE_FLAG_INHERIT_ONLY);
     972             :                         /*
     973             :                          * only apply ace to file if object inherit
     974             :                          */
     975        2142 :                         if (acl_objinherit) {
     976        2142 :                                 newflags |= SEC_ACE_FLAG_INHERITED_ACE;
     977             :                         }
     978             :                 }
     979             : 
     980             :                 /* if NP is specified strip NP and all OI/CI INHERIT flags */
     981        3270 :                 if (prohibit_inheritance) {
     982          30 :                         newflags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT
     983             :                                         | SEC_ACE_FLAG_CONTAINER_INHERIT
     984             :                                         | SEC_ACE_FLAG_INHERIT_ONLY
     985             :                                         | SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
     986             :                 }
     987             :         }
     988        3270 :         return newflags;
     989             : }
     990             : 
     991             : /*
     992             :  * This function builds a new acl for 'caclfile', first it removes any
     993             :  * existing inheritable ace(s) from the current acl of caclfile, secondly it
     994             :  * applies any inheritable acls of the parent of caclfile ( inheritable acls of
     995             :  * caclfile's parent are passed via acl_to_add member of cbstate )
     996             :  *
     997             :  */
     998         540 : static NTSTATUS propagate_inherited_aces(char *caclfile,
     999             :                         struct cacl_callback_state *cbstate)
    1000             : {
    1001         540 :         TALLOC_CTX *aclctx = NULL;
    1002             :         NTSTATUS status;
    1003             :         int result;
    1004             :         int fileattr;
    1005         540 :         struct security_descriptor *old = NULL;
    1006         540 :         bool is_container = false;
    1007         540 :         struct security_acl *acl_to_add = cbstate->acl_to_add;
    1008         540 :         struct security_acl *acl_to_remove = NULL;
    1009             :         uint32_t i, j;
    1010             : 
    1011         540 :         aclctx = talloc_new(NULL);
    1012         540 :         if (aclctx == NULL) {
    1013           0 :                 return NT_STATUS_NO_MEMORY;
    1014             :         }
    1015         540 :         old = get_secdesc_with_ctx(aclctx, cbstate->cli, caclfile);
    1016             : 
    1017         540 :         if (!old) {
    1018           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    1019           0 :                 goto out;
    1020             :         }
    1021             : 
    1022             :         /* inhibit propagation? */
    1023         540 :         if ((old->type & SEC_DESC_DACL_PROTECTED) ==
    1024             :                 SEC_DESC_DACL_PROTECTED){
    1025           6 :                 status = NT_STATUS_OK;
    1026           6 :                 goto out;
    1027             :         }
    1028             : 
    1029         534 :         fileattr = get_fileinfo(cbstate->cli, caclfile);
    1030         534 :         is_container = (fileattr & FILE_ATTRIBUTE_DIRECTORY);
    1031             : 
    1032             :         /* find acl(s) that are inherited */
    1033        2930 :         for (j = 0; old->dacl && j < old->dacl->num_aces; j++) {
    1034             : 
    1035        2396 :                 if (old->dacl->aces[j].flags & SEC_ACE_FLAG_INHERITED_ACE) {
    1036         842 :                         if (!add_ace_with_ctx(aclctx, &acl_to_remove,
    1037         842 :                                               &old->dacl->aces[j])) {
    1038           0 :                                 status = NT_STATUS_NO_MEMORY;
    1039           0 :                                 goto out;
    1040             :                         }
    1041             :                 }
    1042             :         }
    1043             : 
    1044             :         /* remove any acl(s) that are inherited */
    1045         534 :         if (acl_to_remove) {
    1046        1376 :                 for (i = 0; i < acl_to_remove->num_aces; i++) {
    1047         842 :                         struct security_ace ace = acl_to_remove->aces[i];
    1048        3714 :                         for (j = 0; old->dacl && j < old->dacl->num_aces; j++) {
    1049             : 
    1050        3714 :                                 if (security_ace_equal(&ace,
    1051        3714 :                                                   &old->dacl->aces[j])) {
    1052             :                                         uint32_t k;
    1053        2472 :                                         for (k = j; k < old->dacl->num_aces-1;
    1054         788 :                                                 k++) {
    1055         788 :                                                 old->dacl->aces[k] =
    1056         788 :                                                         old->dacl->aces[k+1];
    1057             :                                         }
    1058         842 :                                         old->dacl->num_aces--;
    1059         842 :                                         break;
    1060             :                                 }
    1061             :                         }
    1062             :                 }
    1063             :         }
    1064             :         /* propagate any inheritable ace to be added */
    1065         534 :         if (acl_to_add) {
    1066        3864 :                 for (i = 0; i < acl_to_add->num_aces; i++) {
    1067        3330 :                         struct security_ace ace = acl_to_add->aces[i];
    1068        3330 :                         bool is_objectinherit = (ace.flags &
    1069             :                                 SEC_ACE_FLAG_OBJECT_INHERIT) ==
    1070             :                                         SEC_ACE_FLAG_OBJECT_INHERIT;
    1071             :                         bool is_inherited;
    1072             :                         /* don't propagate flags to a file unless OI */
    1073        3330 :                         if (!is_objectinherit && !is_container) {
    1074         126 :                                 continue;
    1075             :                         }
    1076             :                         /*
    1077             :                          * adjust flags according to inheritance
    1078             :                          * rules
    1079             :                          */
    1080        3270 :                         ace.flags = get_flags_to_propagate(is_container, &ace);
    1081        3270 :                         is_inherited = (ace.flags &
    1082             :                                 SEC_ACE_FLAG_INHERITED_ACE) ==
    1083             :                                         SEC_ACE_FLAG_INHERITED_ACE;
    1084             :                         /* don't propagate non inherited flags */
    1085        3270 :                         if (!is_inherited) {
    1086           6 :                                 continue;
    1087             :                         }
    1088        3264 :                         if (!add_ace_with_ctx(aclctx, &old->dacl, &ace)) {
    1089           0 :                                 status = NT_STATUS_NO_MEMORY;
    1090           0 :                                 goto out;
    1091             :                         }
    1092             :                 }
    1093             :         }
    1094             : 
    1095         534 :         result = cacl_set_from_sd(cbstate->cli, caclfile,
    1096             :                                   old,
    1097         534 :                                   SMB_ACL_SET, cbstate->numeric);
    1098         534 :         if (result != EXIT_OK) {
    1099           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    1100           0 :                 goto out;
    1101             :         }
    1102             : 
    1103         534 :         status = NT_STATUS_OK;
    1104         540 : out:
    1105         540 :         TALLOC_FREE(aclctx);
    1106         540 :         return status;
    1107             : }
    1108             : 
    1109             : /*
    1110             :  * Returns true if 'ace' contains SEC_ACE_FLAG_OBJECT_INHERIT or
    1111             :  * SEC_ACE_FLAG_CONTAINER_INHERIT
    1112             :  */
    1113        2682 : static bool is_inheritable_ace(struct security_ace *ace)
    1114             : {
    1115        2682 :         uint8_t flags = ace->flags;
    1116        2682 :         if (flags & (SEC_ACE_FLAG_OBJECT_INHERIT
    1117             :                         | SEC_ACE_FLAG_CONTAINER_INHERIT)) {
    1118        2310 :                 return true;
    1119             :         }
    1120         372 :         return false;
    1121             : }
    1122             : 
    1123             : /* This method does some basic sanity checking with respect to automatic
    1124             :  * inheritance. e.g. it checks if it is possible to do a set, it detects illegal
    1125             :  * attempts to set inherited permissions directly. Additionally this method
    1126             :  * does some basic initialisation for instance it parses the ACL passed on the
    1127             :  * command line.
    1128             :  */
    1129         114 : static NTSTATUS prepare_inheritance_propagation(TALLOC_CTX *ctx, char *filename,
    1130             :                         struct cacl_callback_state *cbstate)
    1131             : {
    1132             :         NTSTATUS result;
    1133         114 :         char *the_acl = cbstate->the_acl;
    1134         114 :         struct cli_state *cli = cbstate->cli;
    1135         114 :         enum acl_mode mode = cbstate->mode;
    1136         114 :         struct security_descriptor *sd = NULL;
    1137         114 :         struct security_descriptor *old = NULL;
    1138             :         uint32_t j;
    1139         114 :         bool propagate = false;
    1140             : 
    1141         114 :         old = get_secdesc_with_ctx(ctx, cli, filename);
    1142         114 :         if (old == NULL) {
    1143           0 :                 return NT_STATUS_NO_MEMORY;
    1144             :         }
    1145             : 
    1146             :         /* parse acl passed on the command line */
    1147         114 :         if (sddl) {
    1148           0 :                 cbstate->aclsd = sddl_decode(ctx, the_acl,
    1149           0 :                                              get_global_sam_sid());
    1150             :         } else {
    1151         114 :                 cbstate->aclsd = sec_desc_parse(ctx, cli, the_acl);
    1152             :         }
    1153             : 
    1154         114 :         if (!cbstate->aclsd) {
    1155           0 :                 result = NT_STATUS_UNSUCCESSFUL;
    1156           0 :                 goto out;
    1157             :         }
    1158             : 
    1159         114 :         sd = cbstate->aclsd;
    1160             : 
    1161             :         /* set operation if inheritance is enabled doesn't make sense */
    1162         114 :         if (mode == SMB_ACL_SET && ((old->type & SEC_DESC_DACL_PROTECTED) !=
    1163             :                 SEC_DESC_DACL_PROTECTED)){
    1164           6 :                 d_printf("Inheritance enabled at %s, can't apply set operation\n",filename);
    1165           6 :                 result = NT_STATUS_UNSUCCESSFUL;
    1166           6 :                 goto out;
    1167             : 
    1168             :         }
    1169             : 
    1170             :         /*
    1171             :          * search command line acl for any illegal SEC_ACE_FLAG_INHERITED_ACE
    1172             :          * flags that are set
    1173             :          */
    1174         216 :         for (j = 0; sd->dacl && j < sd->dacl->num_aces; j++) {
    1175         108 :                 struct security_ace *ace = &sd->dacl->aces[j];
    1176         108 :                 if (ace->flags & SEC_ACE_FLAG_INHERITED_ACE) {
    1177           0 :                         d_printf("Illegal paramater %s\n", the_acl);
    1178           0 :                         result = NT_STATUS_UNSUCCESSFUL;
    1179           0 :                         goto out;
    1180             :                 }
    1181         108 :                 if (!propagate) {
    1182         108 :                         if (is_inheritable_ace(ace)) {
    1183         108 :                                 propagate = true;
    1184             :                         }
    1185             :                 }
    1186             :         }
    1187             : 
    1188         108 :         result = NT_STATUS_OK;
    1189         114 : out:
    1190         114 :         cbstate->acl_no_propagate = !propagate;
    1191         114 :         return result;
    1192             : }
    1193             : 
    1194             : /*
    1195             :  * This method builds inheritable ace(s) from filename (which should be
    1196             :  * a container) that need propagating to children in order to provide
    1197             :  * automatic inheritance. Those inheritable ace(s) are stored in
    1198             :  * acl_to_add member of cbstate for later processing
    1199             :  * (see propagate_inherited_aces)
    1200             :  */
    1201         324 : static NTSTATUS get_inheritable_aces(TALLOC_CTX *ctx, char *filename,
    1202             :                         struct cacl_callback_state *cbstate)
    1203             : {
    1204             :         NTSTATUS result;
    1205         324 :         struct cli_state *cli = NULL;
    1206         324 :         struct security_descriptor *sd = NULL;
    1207         324 :         struct security_acl *acl_to_add = NULL;
    1208             :         uint32_t j;
    1209             : 
    1210         324 :         cli = cbstate->cli;
    1211         324 :         sd = get_secdesc_with_ctx(ctx, cli, filename);
    1212             : 
    1213         324 :         if (sd == NULL) {
    1214           0 :                 return NT_STATUS_NO_MEMORY;
    1215             :         }
    1216             : 
    1217             :         /*
    1218             :          * Check if any inheritance related flags are used, if not then
    1219             :          * nothing to do. At the same time populate acls for inheritance
    1220             :          * related ace(s) that need to be added to or deleted from children as
    1221             :          * a result of inheritance propagation.
    1222             :          */
    1223             : 
    1224        2898 :         for (j = 0; sd->dacl && j < sd->dacl->num_aces; j++) {
    1225        2574 :                 struct security_ace *ace = &sd->dacl->aces[j];
    1226        2574 :                 if (is_inheritable_ace(ace)) {
    1227        2202 :                         bool added = add_ace_with_ctx(ctx, &acl_to_add, ace);
    1228        2202 :                         if (!added) {
    1229           0 :                                 result = NT_STATUS_NO_MEMORY;
    1230           0 :                                 goto out;
    1231             :                         }
    1232             :                 }
    1233             :         }
    1234         324 :         cbstate->acl_to_add = acl_to_add;
    1235         324 :         result = NT_STATUS_OK;
    1236         324 : out:
    1237         324 :         return result;
    1238             : }
    1239             : 
    1240             : /*
    1241             :  * Callback handler to handle child elements processed by cli_list,  we attempt
    1242             :  * to propagate inheritable ace(s) to each child via the function
    1243             :  * propagate_inherited_aces. Children that are themselves directories are passed
    1244             :  * to cli_list again ( to decend the directory structure )
    1245             :  */
    1246        1188 : static NTSTATUS cacl_set_cb(struct file_info *f,
    1247             :                            const char *mask, void *state)
    1248             : {
    1249        1188 :         struct cacl_callback_state *cbstate =
    1250             :                 (struct cacl_callback_state *)state;
    1251        1188 :         struct cli_state *cli = NULL;
    1252        1188 :         struct cli_credentials *creds = NULL;
    1253             : 
    1254        1188 :         TALLOC_CTX *dirctx = NULL;
    1255             :         NTSTATUS status;
    1256        1188 :         struct cli_state *targetcli = NULL;
    1257             : 
    1258        1188 :         char *dir = NULL;
    1259        1188 :         char *dir_end = NULL;
    1260        1188 :         char *mask2 = NULL;
    1261        1188 :         char *targetpath = NULL;
    1262        1188 :         char *caclfile = NULL;
    1263             : 
    1264        1188 :         dirctx = talloc_new(NULL);
    1265        1188 :         if (!dirctx) {
    1266           0 :                 status = NT_STATUS_NO_MEMORY;
    1267           0 :                 goto out;
    1268             :         }
    1269             : 
    1270        1188 :         cli = cbstate->cli;
    1271        1188 :         creds = cbstate->creds;
    1272             : 
    1273             :         /* Work out the directory. */
    1274        1188 :         dir = talloc_strdup(dirctx, mask);
    1275        1188 :         if (!dir) {
    1276           0 :                 status = NT_STATUS_NO_MEMORY;
    1277           0 :                 goto out;
    1278             :         }
    1279             : 
    1280        1188 :         dir_end = strrchr(dir, DIRSEP_CHAR);
    1281        1188 :         if (dir_end != NULL) {
    1282        1188 :                 *dir_end = '\0';
    1283             :         }
    1284             : 
    1285        1188 :         if (!f->name || !f->name[0]) {
    1286           0 :                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
    1287           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    1288           0 :                 goto out;
    1289             :         }
    1290             : 
    1291        1188 :         if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
    1292             :                 struct cacl_callback_state dir_cbstate;
    1293         864 :                 uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY
    1294             :                         | FILE_ATTRIBUTE_SYSTEM
    1295             :                         | FILE_ATTRIBUTE_HIDDEN;
    1296         864 :                 dir_end = NULL;
    1297             : 
    1298             :                 /* ignore special '.' & '..' */
    1299         864 :                 if ((f->name == NULL) || ISDOT(f->name) || ISDOTDOT(f->name)) {
    1300         648 :                         status = NT_STATUS_OK;
    1301        1296 :                         goto out;
    1302             :                 }
    1303             : 
    1304         216 :                 mask2 = build_dirname(dirctx, mask, dir, f->name);
    1305         216 :                 if (mask2 == NULL) {
    1306           0 :                         status = NT_STATUS_NO_MEMORY;
    1307           0 :                         goto out;
    1308             :                 }
    1309             : 
    1310             :                 /* check for dfs */
    1311         216 :                 status = local_cli_resolve_path(dirctx, "", creds, cli,
    1312             :                         mask2, &targetcli, &targetpath);
    1313         216 :                 if (!NT_STATUS_IS_OK(status)) {
    1314           0 :                         goto out;
    1315             :                 }
    1316             : 
    1317             :                 /*
    1318             :                  * prepare path to caclfile, remove any existing wildcard
    1319             :                  * chars and convert path separators.
    1320             :                  */
    1321             : 
    1322         216 :                 caclfile = talloc_strdup(dirctx, targetpath);
    1323         216 :                 if (!caclfile) {
    1324           0 :                         status = NT_STATUS_NO_MEMORY;
    1325           0 :                         goto out;
    1326             :                 }
    1327         216 :                 dir_end = strrchr(caclfile, '*');
    1328         216 :                 if (dir_end != NULL) {
    1329         216 :                         *dir_end = '\0';
    1330             :                 }
    1331             : 
    1332         216 :                 string_replace(caclfile, '/', '\\');
    1333             :                 /*
    1334             :                  * make directory specific copy of cbstate here
    1335             :                  * (for this directory level) to be available as
    1336             :                  * the parent cbstate for the children of this directory.
    1337             :                  * Note: cbstate is overwritten for the current file being
    1338             :                  *       processed.
    1339             :                  */
    1340         216 :                 dir_cbstate = *cbstate;
    1341         216 :                 dir_cbstate.cli = targetcli;
    1342             : 
    1343             :                 /*
    1344             :                  * propagate any inherited ace from our parent
    1345             :                  */
    1346         216 :                 status = propagate_inherited_aces(caclfile, &dir_cbstate);
    1347         216 :                 if (!NT_STATUS_IS_OK(status)) {
    1348           0 :                         goto out;
    1349             :                 }
    1350             : 
    1351             :                 /*
    1352             :                  * get inheritable ace(s) for this dir/container
    1353             :                  * that will be propagated to its children
    1354             :                  */
    1355         216 :                 status = get_inheritable_aces(dirctx, caclfile,
    1356             :                                                       &dir_cbstate);
    1357         216 :                 if (!NT_STATUS_IS_OK(status)) {
    1358           0 :                         goto out;
    1359             :                 }
    1360             : 
    1361             :                 /*
    1362             :                  * ensure cacl_set_cb gets called for children
    1363             :                  * of this directory (targetpath)
    1364             :                  */
    1365         216 :                 status = cli_list(targetcli, targetpath,
    1366             :                         attribute, cacl_set_cb,
    1367             :                         (void *)&dir_cbstate);
    1368             : 
    1369         216 :                 if (!NT_STATUS_IS_OK(status)) {
    1370           0 :                         goto out;
    1371             :                 }
    1372             : 
    1373             :         } else {
    1374             :                 /*
    1375             :                  * build full path to caclfile and replace '/' with '\' so
    1376             :                  * other utility functions can deal with it
    1377             :                  */
    1378             : 
    1379         324 :                 targetpath = talloc_asprintf(dirctx, "%s/%s", dir, f->name);
    1380         324 :                 if (!targetpath) {
    1381           0 :                         status = NT_STATUS_NO_MEMORY;
    1382           0 :                         goto out;
    1383             :                 }
    1384         324 :                 string_replace(targetpath, '/', '\\');
    1385             : 
    1386             :                 /* attempt to propagate any inherited ace to file caclfile */
    1387         324 :                 status = propagate_inherited_aces(targetpath, cbstate);
    1388             : 
    1389         324 :                 if (!NT_STATUS_IS_OK(status)) {
    1390           0 :                         goto out;
    1391             :                 }
    1392             :         }
    1393         540 :         status = NT_STATUS_OK;
    1394        1188 : out:
    1395        1188 :         if (!NT_STATUS_IS_OK(status)) {
    1396           0 :                 d_printf("error %s: processing %s\n",
    1397             :                         nt_errstr(status),
    1398             :                         targetpath);
    1399             :         }
    1400        1188 :         TALLOC_FREE(dirctx);
    1401        1188 :         return status;
    1402             : }
    1403             : 
    1404             : 
    1405             : /*
    1406             :  * Wrapper around cl_list to decend the directory tree pointed to by 'filename',
    1407             :  * helper callback function 'cacl_set_cb' handles the child elements processed
    1408             :  * by cli_list.
    1409             :  */
    1410         114 : static int inheritance_cacl_set(char *filename,
    1411             :                         struct cacl_callback_state *cbstate)
    1412             : {
    1413             :         int result;
    1414             :         NTSTATUS ntstatus;
    1415             :         int fileattr;
    1416         114 :         char *mask = NULL;
    1417         114 :         struct cli_state *cli = cbstate->cli;
    1418         114 :         TALLOC_CTX *ctx = NULL;
    1419         114 :         bool isdirectory = false;
    1420         114 :         uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM
    1421             :                                 | FILE_ATTRIBUTE_HIDDEN;
    1422         114 :         char *save_share = NULL;
    1423         114 :         ctx = talloc_init("inherit_set");
    1424         114 :         if (ctx == NULL) {
    1425           0 :                 d_printf("out of memory\n");
    1426           0 :                 result = EXIT_FAILED;
    1427           0 :                 goto out;
    1428             :         }
    1429             : 
    1430             :         /* ensure we have a filename that starts with '\' */
    1431         114 :         if (!filename || *filename != DIRSEP_CHAR) {
    1432             :                 /* illegal or no filename */
    1433           0 :                 result = EXIT_FAILED;
    1434           0 :                 d_printf("illegal or missing name '%s'\n", filename);
    1435           0 :                 goto out;
    1436             :         }
    1437             : 
    1438             : 
    1439         114 :         fileattr = get_fileinfo(cli, filename);
    1440         114 :         isdirectory = (fileattr & FILE_ATTRIBUTE_DIRECTORY)
    1441             :                 == FILE_ATTRIBUTE_DIRECTORY;
    1442             : 
    1443             :         /*
    1444             :          * if we've got as far as here then we have already evaluated
    1445             :          * the args.
    1446             :          */
    1447         114 :         if (test_args) {
    1448           0 :                 result = EXIT_OK;
    1449           0 :                 goto out;
    1450             :         }
    1451             : 
    1452         114 :         mask = NULL;
    1453             :         /* make sure we have a trailing '\*' for directory */
    1454         114 :         if (!isdirectory) {
    1455           0 :                 mask = talloc_strdup(ctx, filename);
    1456         114 :         } else if (strlen(filename) > 1) {
    1457             :                 /*
    1458             :                  * if the passed file name doesn't have a trailing '\'
    1459             :                  * append it.
    1460             :                  */
    1461         114 :                 char *name_end = strrchr(filename, DIRSEP_CHAR);
    1462         114 :                 if (name_end != filename + strlen(filename) + 1) {
    1463         114 :                         mask = talloc_asprintf(ctx, "%s\\*", filename);
    1464             :                 } else {
    1465           0 :                         mask = talloc_strdup(ctx, filename);
    1466             :                 }
    1467             :         } else {
    1468             :                 /* filename is a single '\', just append '*' */
    1469           0 :                 mask = talloc_asprintf_append(mask, "%s*", filename);
    1470             :         }
    1471             : 
    1472         114 :         if (!mask) {
    1473           0 :                 result = EXIT_FAILED;
    1474           0 :                 goto out;
    1475             :         }
    1476             : 
    1477             :         /*
    1478             :          * prepare for automatic propagation of the acl passed on the
    1479             :          * cmdline.
    1480             :          */
    1481         114 :         save_share = talloc_strdup(ctx, cli->share);
    1482         114 :         if (save_share == NULL) {
    1483           0 :                 result = EXIT_FAILED;
    1484           0 :                 goto out;
    1485             :         }
    1486             : 
    1487         114 :         ntstatus = prepare_inheritance_propagation(ctx, filename,
    1488             :                                                            cbstate);
    1489         114 :         if (!NT_STATUS_IS_OK(ntstatus)) {
    1490           6 :                 d_printf("error: %s processing %s\n",
    1491             :                          nt_errstr(ntstatus), filename);
    1492           6 :                 result = EXIT_FAILED;
    1493           6 :                 goto out;
    1494             :         }
    1495             : 
    1496             :         /*
    1497             :          * sec_desc_parse ends up calling a bunch of functions one of which
    1498             :          * connects to IPC$ (which overwrites cli->share)
    1499             :          * we need a new connection to the share here.
    1500             :          * Note: This only is an issue when the share is a msdfs root
    1501             :          *       because the presence of cli->share gets expanded out
    1502             :          *       later on by cli_resolve_path (when it is constructing a path)
    1503             :          */
    1504         108 :         ntstatus = cli_tree_connect_creds(cli,
    1505             :                           save_share,
    1506             :                           "?????",
    1507             :                           cbstate->creds);
    1508             : 
    1509         108 :         if (!NT_STATUS_IS_OK(ntstatus)) {
    1510           0 :                 d_printf("error: %s processing %s\n",
    1511             :                          nt_errstr(ntstatus), filename);
    1512           0 :                 result = EXIT_FAILED;
    1513           0 :                 goto out;
    1514             :         }
    1515         108 :         result = cacl_set_from_sd(cli, filename, cbstate->aclsd,
    1516         108 :                                 cbstate->mode, cbstate->numeric);
    1517             : 
    1518             :         /*
    1519             :          * strictly speaking it could be considered an error if a file was
    1520             :          * specificied with '--propagate-inheritance'. However we really want
    1521             :          * to eventually get rid of '--propagate-inheritance' so we will be
    1522             :          * more forgiving here and instead just exit early.
    1523             :          */
    1524         216 :         if (!isdirectory || (result != EXIT_OK)) {
    1525             :                 goto out;
    1526             :         }
    1527             : 
    1528             :         /* check if there is actually any need to propagate */
    1529         108 :         if (cbstate->acl_no_propagate) {
    1530           0 :                 goto out;
    1531             :         }
    1532             :         /* get inheritable attributes this parent container (e.g. filename) */
    1533         108 :         ntstatus = get_inheritable_aces(ctx, filename, cbstate);
    1534         108 :         if (NT_STATUS_IS_OK(ntstatus)) {
    1535             :                 /* process children */
    1536         108 :                 ntstatus = cli_list(cli, mask, attribute,
    1537             :                                 cacl_set_cb,
    1538             :                                 (void *)cbstate);
    1539             :         }
    1540             : 
    1541         108 :         if (!NT_STATUS_IS_OK(ntstatus)) {
    1542           0 :                 d_printf("error: %s processing %s\n",
    1543             :                          nt_errstr(ntstatus), filename);
    1544           0 :                 result = EXIT_FAILED;
    1545           0 :                 goto out;
    1546             :         }
    1547             : 
    1548         222 : out:
    1549         114 :         TALLOC_FREE(ctx);
    1550         114 :         return result;
    1551             : }
    1552             : 
    1553             : /****************************************************************************
    1554             :   main program
    1555             : ****************************************************************************/
    1556        1940 : int main(int argc, char *argv[])
    1557             : {
    1558        1940 :         const char **argv_const = discard_const_p(const char *, argv);
    1559             :         char *share;
    1560             :         int opt;
    1561        1940 :         enum acl_mode mode = SMB_ACL_SET;
    1562             :         static char *the_acl = NULL;
    1563        1940 :         enum chown_mode change_mode = REQUEST_NONE;
    1564             :         int result;
    1565             :         char *path;
    1566        1940 :         char *filename = NULL;
    1567             :         poptContext pc;
    1568             :         /* numeric is set when the user wants numeric SIDs and ACEs rather
    1569             :            than going via LSA calls to resolve them */
    1570        1940 :         int numeric = 0;
    1571        1940 :         struct cli_state *targetcli = NULL;
    1572        1940 :         struct cli_credentials *creds = NULL;
    1573        1940 :         char *targetfile = NULL;
    1574             :         NTSTATUS status;
    1575             :         bool ok;
    1576             : 
    1577       11640 :         struct poptOption long_options[] = {
    1578             :                 POPT_AUTOHELP
    1579             :                 {
    1580             :                         .longName   = "delete",
    1581             :                         .shortName  = 'D',
    1582             :                         .argInfo    = POPT_ARG_STRING,
    1583             :                         .arg        = NULL,
    1584             :                         .val        = 'D',
    1585             :                         .descrip    = "Delete an acl",
    1586             :                         .argDescrip = "ACL",
    1587             :                 },
    1588             :                 {
    1589             :                         .longName   = "modify",
    1590             :                         .shortName  = 'M',
    1591             :                         .argInfo    = POPT_ARG_STRING,
    1592             :                         .arg        = NULL,
    1593             :                         .val        = 'M',
    1594             :                         .descrip    = "Modify an acl",
    1595             :                         .argDescrip = "ACL",
    1596             :                 },
    1597             :                 {
    1598             :                         .longName   = "add",
    1599             :                         .shortName  = 'a',
    1600             :                         .argInfo    = POPT_ARG_STRING,
    1601             :                         .arg        = NULL,
    1602             :                         .val        = 'a',
    1603             :                         .descrip    = "Add an acl",
    1604             :                         .argDescrip = "ACL",
    1605             :                 },
    1606             :                 {
    1607             :                         .longName   = "set",
    1608             :                         .shortName  = 'S',
    1609             :                         .argInfo    = POPT_ARG_STRING,
    1610             :                         .arg        = NULL,
    1611             :                         .val        = 'S',
    1612             :                         .descrip    = "Set acls",
    1613             :                         .argDescrip = "ACLS",
    1614             :                 },
    1615             :                 {
    1616             :                         .longName   = "chown",
    1617             :                         .shortName  = 'C',
    1618             :                         .argInfo    = POPT_ARG_STRING,
    1619             :                         .arg        = NULL,
    1620             :                         .val        = 'C',
    1621             :                         .descrip    = "Change ownership of a file",
    1622             :                         .argDescrip = "USERNAME",
    1623             :                 },
    1624             :                 {
    1625             :                         .longName   = "chgrp",
    1626             :                         .shortName  = 'G',
    1627             :                         .argInfo    = POPT_ARG_STRING,
    1628             :                         .arg        = NULL,
    1629             :                         .val        = 'G',
    1630             :                         .descrip    = "Change group ownership of a file",
    1631             :                         .argDescrip = "GROUPNAME",
    1632             :                 },
    1633             :                 {
    1634             :                         .longName   = "inherit",
    1635             :                         .shortName  = 'I',
    1636             :                         .argInfo    = POPT_ARG_STRING,
    1637             :                         .arg        = NULL,
    1638             :                         .val        = 'I',
    1639             :                         .descrip    = "Inherit allow|remove|copy",
    1640             :                 },
    1641             :                 {
    1642             :                         .longName   = "propagate-inheritance",
    1643             :                         .shortName  = 0,
    1644             :                         .argInfo    = POPT_ARG_NONE,
    1645             :                         .arg        = &inheritance,
    1646             :                         .val        = 1,
    1647             :                         .descrip    = "Supports propagation of inheritable ACE(s) when used in conjunction with add, delete, set or modify",
    1648             :                 },
    1649             :                 {
    1650             :                         .longName   = "numeric",
    1651             :                         .shortName  = 0,
    1652             :                         .argInfo    = POPT_ARG_NONE,
    1653             :                         .arg        = &numeric,
    1654             :                         .val        = 1,
    1655             :                         .descrip    = "Don't resolve sids or masks to names",
    1656             :                 },
    1657             :                 {
    1658             :                         .longName   = "sddl",
    1659             :                         .shortName  = 0,
    1660             :                         .argInfo    = POPT_ARG_NONE,
    1661             :                         .arg        = &sddl,
    1662             :                         .val        = 1,
    1663             :                         .descrip    = "Output and input acls in sddl format",
    1664             :                 },
    1665             :                 {
    1666             :                         .longName   = "query-security-info",
    1667             :                         .shortName  = 0,
    1668             :                         .argInfo    = POPT_ARG_INT,
    1669             :                         .arg        = &query_sec_info,
    1670             :                         .val        = 1,
    1671             :                         .descrip    = "The security-info flags for queries"
    1672             :                 },
    1673             :                 {
    1674             :                         .longName   = "set-security-info",
    1675             :                         .shortName  = 0,
    1676             :                         .argInfo    = POPT_ARG_INT,
    1677             :                         .arg        = &set_sec_info,
    1678             :                         .val        = 1,
    1679             :                         .descrip    = "The security-info flags for modifications"
    1680             :                 },
    1681             :                 {
    1682             :                         .longName   = "test-args",
    1683             :                         .shortName  = 't',
    1684             :                         .argInfo    = POPT_ARG_NONE,
    1685             :                         .arg        = &test_args,
    1686             :                         .val        = 1,
    1687             :                         .descrip    = "Test arguments"
    1688             :                 },
    1689             :                 {
    1690             :                         .longName   = "domain-sid",
    1691             :                         .shortName  = 0,
    1692             :                         .argInfo    = POPT_ARG_STRING,
    1693             :                         .arg        = &domain_sid,
    1694             :                         .val        = 0,
    1695             :                         .descrip    = "Domain SID for sddl",
    1696             :                         .argDescrip = "SID"},
    1697             :                 {
    1698             :                         .longName   = "maximum-access",
    1699             :                         .shortName  = 'x',
    1700             :                         .argInfo    = POPT_ARG_NONE,
    1701             :                         .arg        = NULL,
    1702             :                         .val        = 'x',
    1703             :                         .descrip    = "Query maximum persmissions",
    1704             :                 },
    1705        1940 :                 POPT_COMMON_SAMBA
    1706        1940 :                 POPT_COMMON_CONNECTION
    1707        1940 :                 POPT_COMMON_CREDENTIALS
    1708        1940 :                 POPT_LEGACY_S3
    1709        1940 :                 POPT_COMMON_VERSION
    1710             :                 POPT_TABLEEND
    1711             :         };
    1712             : 
    1713             :         struct cli_state *cli;
    1714        1940 :         TALLOC_CTX *frame = talloc_stackframe();
    1715        1940 :         const char *owner_username = "";
    1716             :         char *server;
    1717             : 
    1718        1940 :         smb_init_locale();
    1719             : 
    1720        1940 :         ok = samba_cmdline_init(frame,
    1721             :                                 SAMBA_CMDLINE_CONFIG_CLIENT,
    1722             :                                 false /* require_smbconf */);
    1723        1940 :         if (!ok) {
    1724           0 :                 DBG_ERR("Failed to init cmdline parser!\n");
    1725           0 :                 TALLOC_FREE(frame);
    1726           0 :                 exit(1);
    1727             :         }
    1728             :         /* set default debug level to 1 regardless of what smb.conf sets */
    1729        1940 :         lp_set_cmdline("log level", "1");
    1730             : 
    1731        1940 :         setlinebuf(stdout);
    1732             : 
    1733        1940 :         pc = samba_popt_get_context(getprogname(),
    1734             :                                     argc,
    1735             :                                     argv_const,
    1736             :                                     long_options,
    1737             :                                     0);
    1738        1940 :         if (pc == NULL) {
    1739           0 :                 DBG_ERR("Failed to setup popt context!\n");
    1740           0 :                 TALLOC_FREE(frame);
    1741           0 :                 exit(1);
    1742             :         }
    1743             : 
    1744        1940 :         poptSetOtherOptionHelp(pc, "//server1/share1 filename\nACLs look like: "
    1745             :                 "'ACL:user:[ALLOWED|DENIED]/flags/permissions'");
    1746             : 
    1747        1940 :         while ((opt = poptGetNextOpt(pc)) != -1) {
    1748        1432 :                 switch (opt) {
    1749          86 :                 case 'S':
    1750          86 :                         the_acl = smb_xstrdup(poptGetOptArg(pc));
    1751          86 :                         mode = SMB_ACL_SET;
    1752          86 :                         break;
    1753             : 
    1754          66 :                 case 'D':
    1755          66 :                         the_acl = smb_xstrdup(poptGetOptArg(pc));
    1756          66 :                         mode = SMB_ACL_DELETE;
    1757          66 :                         break;
    1758             : 
    1759         820 :                 case 'M':
    1760         820 :                         the_acl = smb_xstrdup(poptGetOptArg(pc));
    1761         820 :                         mode = SMB_ACL_MODIFY;
    1762         820 :                         break;
    1763             : 
    1764         274 :                 case 'a':
    1765         274 :                         the_acl = smb_xstrdup(poptGetOptArg(pc));
    1766         274 :                         mode = SMB_ACL_ADD;
    1767         274 :                         break;
    1768             : 
    1769          34 :                 case 'C':
    1770          34 :                         owner_username = poptGetOptArg(pc);
    1771          34 :                         change_mode = REQUEST_CHOWN;
    1772          34 :                         break;
    1773             : 
    1774           4 :                 case 'G':
    1775           4 :                         owner_username = poptGetOptArg(pc);
    1776           4 :                         change_mode = REQUEST_CHGRP;
    1777           4 :                         break;
    1778             : 
    1779          18 :                 case 'I':
    1780          18 :                         owner_username = poptGetOptArg(pc);
    1781          18 :                         change_mode = REQUEST_INHERIT;
    1782          18 :                         break;
    1783           0 :                 case 'm':
    1784           0 :                         lp_set_cmdline("client max protocol", poptGetOptArg(pc));
    1785           0 :                         break;
    1786           4 :                 case 'x':
    1787           4 :                         want_mxac = true;
    1788           4 :                         break;
    1789           0 :                 case POPT_ERROR_BADOPT:
    1790           0 :                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
    1791             :                                 poptBadOption(pc, 0), poptStrerror(opt));
    1792           0 :                         poptPrintUsage(pc, stderr, 0);
    1793           0 :                         exit(1);
    1794             :                 }
    1795             :         }
    1796        1940 :         if (inheritance && !the_acl) {
    1797           0 :                 poptPrintUsage(pc, stderr, 0);
    1798           0 :                 return -1;
    1799             :         }
    1800             : 
    1801        1940 :         if(!poptPeekArg(pc)) {
    1802           0 :                 poptPrintUsage(pc, stderr, 0);
    1803           0 :                 return -1;
    1804             :         }
    1805             : 
    1806        1940 :         path = talloc_strdup(frame, poptGetArg(pc));
    1807        1940 :         if (!path) {
    1808           0 :                 return -1;
    1809             :         }
    1810             : 
    1811        1940 :         if(!poptPeekArg(pc)) {
    1812           0 :                 poptPrintUsage(pc, stderr, 0);
    1813           0 :                 return -1;
    1814             :         }
    1815             : 
    1816        1940 :         filename = talloc_strdup(frame, poptGetArg(pc));
    1817        1940 :         if (!filename) {
    1818           0 :                 return -1;
    1819             :         }
    1820             : 
    1821        1940 :         poptFreeContext(pc);
    1822        1940 :         samba_cmdline_burn(argc, argv);
    1823             : 
    1824        1940 :         string_replace(path,'/','\\');
    1825             : 
    1826        1940 :         server = talloc_strdup(frame, path+2);
    1827        1940 :         if (!server) {
    1828           0 :                 return -1;
    1829             :         }
    1830        1940 :         share = strchr_m(server,'\\');
    1831        1940 :         if (share == NULL) {
    1832           0 :                 printf("Invalid argument\n");
    1833           0 :                 return -1;
    1834             :         }
    1835             : 
    1836        1940 :         *share = 0;
    1837        1940 :         share++;
    1838             : 
    1839        1940 :         creds = samba_cmdline_get_creds();
    1840             : 
    1841             :         /* Make connection to server */
    1842        1940 :         if (!test_args) {
    1843        1940 :                 cli = connect_one(creds, server, share);
    1844        1940 :                 if (!cli) {
    1845           0 :                         exit(EXIT_FAILED);
    1846             :                 }
    1847             :         } else {
    1848           0 :                 exit(0);
    1849             :         }
    1850             : 
    1851        1940 :         string_replace(filename, '/', '\\');
    1852        1940 :         if (filename[0] != '\\') {
    1853        1932 :                 filename = talloc_asprintf(frame,
    1854             :                                 "\\%s",
    1855             :                                 filename);
    1856        1932 :                 if (!filename) {
    1857           0 :                         return -1;
    1858             :                 }
    1859             :         }
    1860             : 
    1861        1940 :         status = local_cli_resolve_path(frame,
    1862             :                                   "",
    1863             :                                   creds,
    1864             :                                   cli,
    1865             :                                   filename,
    1866             :                                   &targetcli,
    1867             :                                   &targetfile);
    1868        1940 :         if (!NT_STATUS_IS_OK(status)) {
    1869           0 :                 DEBUG(0,("cli_resolve_path failed for %s! (%s)\n", filename, nt_errstr(status)));
    1870           0 :                 return -1;
    1871             :         }
    1872             : 
    1873             :         /* Perform requested action */
    1874             : 
    1875        1940 :         if (change_mode == REQUEST_INHERIT) {
    1876          18 :                 result = inherit(targetcli, targetfile, owner_username);
    1877        1922 :         } else if (change_mode != REQUEST_NONE) {
    1878          38 :                 result = owner_set(targetcli, change_mode, targetfile, owner_username);
    1879        1884 :         } else if (the_acl) {
    1880        1246 :                 if (inheritance) {
    1881         114 :                         struct cacl_callback_state cbstate = {
    1882             :                                 .creds = creds,
    1883             :                                 .cli = targetcli,
    1884             :                                 .mode = mode,
    1885             :                                 .the_acl = the_acl,
    1886             :                                 .numeric = numeric,
    1887             :                         };
    1888         114 :                         result = inheritance_cacl_set(targetfile, &cbstate);
    1889             :                 } else {
    1890        1132 :                         result =  cacl_set(targetcli,
    1891             :                                            targetfile,
    1892             :                                            the_acl,
    1893             :                                            mode,
    1894             :                                            numeric);
    1895             :                 }
    1896             :         } else {
    1897         638 :                 result = cacl_dump(targetcli, targetfile, numeric);
    1898             :         }
    1899             : 
    1900        1940 :         TALLOC_FREE(frame);
    1901             : 
    1902        1940 :         return result;
    1903             : }

Generated by: LCOV version 1.13