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

Generated by: LCOV version 1.14