2011-01-15 18:07:31 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-12-03 14:05:11 +03:00
ACL get / set utility
2011-01-15 18:07:31 +03:00
2000-12-03 05:19:27 +03:00
Copyright ( C ) Andrew Tridgell 2000
2000-12-14 06:27:53 +03:00
Copyright ( C ) Tim Potter 2000
2000-12-16 03:08:05 +03:00
Copyright ( C ) Jeremy Allison 2000
2003-04-14 07:59:04 +04:00
Copyright ( C ) Jelmer Vernooij 2003
2013-11-14 21:45:07 +04:00
Copyright ( C ) Noel Power < noel . power @ suse . com > 2013
2011-01-15 18:07:31 +03:00
2000-12-03 05:19:27 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-12-03 05:19:27 +03:00
( at your option ) any later version .
2011-01-15 18:07:31 +03:00
2000-12-03 05:19:27 +03:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2011-01-15 18:07:31 +03:00
2000-12-03 05:19:27 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-12-03 05:19:27 +03:00
*/
# include "includes.h"
2021-01-13 16:04:04 +03:00
# include "lib/cmdline/cmdline.h"
2011-02-28 12:19:44 +03:00
# include "rpc_client/cli_pipe.h"
2010-05-05 03:39:16 +04:00
# include "../librpc/gen_ndr/ndr_lsa.h"
2010-05-18 20:26:16 +04:00
# include "rpc_client/cli_lsarpc.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-02-24 12:46:55 +03:00
# include "libsmb/clirap.h"
2011-03-22 18:50:02 +03:00
# include "passdb/machine_sid.h"
2011-06-09 16:32:27 +04:00
# include "../librpc/gen_ndr/ndr_lsa_c.h"
2015-04-24 18:37:13 +03:00
# include "util_sd.h"
2023-08-07 07:25:28 +03:00
# include "lib/param/param.h"
2000-12-03 05:19:27 +03:00
2013-11-14 21:45:07 +04:00
static char DIRSEP_CHAR = ' \\ ' ;
static int inheritance = 0 ;
2022-08-11 17:26:01 +03:00
static const char * save_file = NULL ;
static const char * restore_file = NULL ;
2022-08-17 17:39:19 +03:00
static int recurse ;
2008-10-15 03:09:17 +04:00
static int test_args ;
2010-03-01 00:20:03 +03:00
static int sddl ;
2012-11-30 17:36:07 +04:00
static int query_sec_info = - 1 ;
static int set_sec_info = - 1 ;
2019-02-27 18:45:07 +03:00
static bool want_mxac ;
2010-03-01 00:20:03 +03:00
2011-06-09 17:29:32 +04:00
static const char * domain_sid = NULL ;
2001-04-11 05:34:37 +04:00
enum acl_mode { SMB_ACL_SET , SMB_ACL_DELETE , SMB_ACL_MODIFY , SMB_ACL_ADD } ;
2010-05-06 09:35:02 +04:00
enum chown_mode { REQUEST_NONE , REQUEST_CHOWN , REQUEST_CHGRP , REQUEST_INHERIT } ;
2000-12-22 02:36:25 +03:00
enum exit_values { EXIT_OK , EXIT_FAILED , EXIT_PARSE_ERROR } ;
2000-12-03 15:41:28 +03:00
2013-11-14 21:45:07 +04:00
struct cacl_callback_state {
2021-01-13 16:07:02 +03:00
struct cli_credentials * creds ;
2013-11-14 21:45:07 +04:00
struct cli_state * cli ;
struct security_descriptor * aclsd ;
struct security_acl * acl_to_add ;
enum acl_mode mode ;
char * the_acl ;
bool acl_no_propagate ;
bool numeric ;
} ;
2011-06-09 16:32:27 +04:00
static NTSTATUS cli_lsa_lookup_domain_sid ( struct cli_state * cli ,
struct dom_sid * sid )
{
union lsa_PolicyInformation * info = NULL ;
2017-06-14 02:56:48 +03:00
struct smbXcli_tcon * orig_tcon = NULL ;
2022-08-24 03:37:48 +03:00
char * orig_share = NULL ;
2011-06-09 16:32:27 +04:00
struct rpc_pipe_client * rpc_pipe = NULL ;
struct policy_handle handle ;
NTSTATUS status , result ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2017-06-14 02:56:48 +03:00
if ( cli_state_has_tcon ( cli ) ) {
2022-08-24 03:37:48 +03:00
cli_state_save_tcon_share ( cli , & orig_tcon , & orig_share ) ;
2017-06-14 02:56:48 +03:00
}
2016-12-08 09:13:57 +03:00
status = cli_tree_connect ( cli , " IPC$ " , " ????? " , NULL ) ;
2011-06-09 16:32:27 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
2013-05-24 15:29:28 +04:00
status = cli_rpc_pipe_open_noauth ( cli , & ndr_table_lsarpc , & rpc_pipe ) ;
2011-06-09 16:32:27 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto tdis ;
}
status = rpccli_lsa_open_policy ( rpc_pipe , frame , True ,
GENERIC_EXECUTE_ACCESS , & handle ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto tdis ;
}
status = dcerpc_lsa_QueryInfoPolicy2 ( rpc_pipe - > binding_handle ,
frame , & handle ,
LSA_POLICY_INFO_DOMAIN ,
& info , & result ) ;
if ( any_nt_status_not_ok ( status , result , & status ) ) {
goto tdis ;
}
* sid = * info - > domain . sid ;
tdis :
TALLOC_FREE ( rpc_pipe ) ;
cli_tdis ( cli ) ;
done :
2022-08-24 03:37:48 +03:00
cli_state_restore_tcon_share ( cli , orig_tcon , orig_share ) ;
2011-06-09 16:32:27 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
2011-10-12 16:34:45 +04:00
static struct dom_sid * get_domain_sid ( struct cli_state * cli )
{
2011-06-09 16:32:27 +04:00
NTSTATUS status ;
2018-12-10 14:51:56 +03:00
struct dom_sid_buf buf ;
2011-06-09 16:32:27 +04:00
struct dom_sid * sid = talloc ( talloc_tos ( ) , struct dom_sid ) ;
if ( sid = = NULL ) {
DEBUG ( 0 , ( " Out of memory \n " ) ) ;
return NULL ;
}
2011-06-09 17:29:32 +04:00
if ( domain_sid ) {
if ( ! dom_sid_parse ( domain_sid , sid ) ) {
DEBUG ( 0 , ( " failed to parse domain sid \n " ) ) ;
TALLOC_FREE ( sid ) ;
}
2011-06-09 16:32:27 +04:00
} else {
2011-06-09 17:29:32 +04:00
status = cli_lsa_lookup_domain_sid ( cli , sid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " failed to lookup domain sid: %s \n " , nt_errstr ( status ) ) ) ;
TALLOC_FREE ( sid ) ;
}
2011-06-09 16:32:27 +04:00
}
2018-12-10 14:51:56 +03:00
DEBUG ( 2 , ( " Domain SID: %s \n " , dom_sid_str_buf ( sid , & buf ) ) ) ;
2011-06-09 16:32:27 +04:00
return sid ;
}
2010-05-18 05:30:40 +04:00
/* add an ACE to a list of ACEs in a struct security_acl */
2013-11-14 21:45:07 +04:00
static bool add_ace_with_ctx ( TALLOC_CTX * ctx , struct security_acl * * the_acl ,
2021-01-14 23:45:36 +03:00
const struct security_ace * ace )
2013-11-14 21:45:07 +04:00
2000-12-03 10:36:15 +03:00
{
2021-01-14 23:45:36 +03:00
struct security_acl * acl = * the_acl ;
if ( acl = = NULL ) {
acl = make_sec_acl ( ctx , 3 , 0 , NULL ) ;
if ( acl = = NULL ) {
return false ;
}
2000-12-03 10:36:15 +03:00
}
2021-01-14 23:45:36 +03:00
if ( acl - > num_aces = = UINT32_MAX ) {
return false ;
2006-06-20 13:16:53 +04:00
}
2021-01-14 23:45:36 +03:00
ADD_TO_ARRAY (
acl , struct security_ace , * ace , & acl - > aces , & acl - > num_aces ) ;
* the_acl = acl ;
2000-12-03 10:36:15 +03:00
return True ;
}
2013-11-14 21:45:07 +04:00
static bool add_ace ( struct security_acl * * the_acl , struct security_ace * ace )
{
return add_ace_with_ctx ( talloc_tos ( ) , the_acl , ace ) ;
}
2000-12-03 10:36:15 +03:00
/* parse a ascii version of a security descriptor */
2010-05-18 12:29:34 +04:00
static struct security_descriptor * sec_desc_parse ( TALLOC_CTX * ctx , struct cli_state * cli , char * str )
2000-12-03 10:36:15 +03:00
{
2002-11-13 02:20:50 +03:00
const char * p = str ;
2007-12-08 04:32:32 +03:00
char * tok ;
2010-05-18 12:29:34 +04:00
struct security_descriptor * ret = NULL ;
2001-06-20 21:49:38 +04:00
size_t sd_size ;
2021-01-14 22:49:00 +03:00
struct dom_sid owner_sid = { . num_auths = 0 } ;
bool have_owner = false ;
struct dom_sid group_sid = { . num_auths = 0 } ;
bool have_group = false ;
2010-05-18 05:30:40 +04:00
struct security_acl * dacl = NULL ;
2000-12-03 14:05:11 +03:00
int revision = 1 ;
2000-12-03 10:36:15 +03:00
2007-12-08 04:32:32 +03:00
while ( next_token_talloc ( ctx , & p , & tok , " \t , \r \n " ) ) {
2000-12-03 10:36:15 +03:00
if ( strncmp ( tok , " REVISION: " , 9 ) = = 0 ) {
2000-12-03 14:05:11 +03:00
revision = strtol ( tok + 9 , NULL , 16 ) ;
2000-12-12 09:06:10 +03:00
continue ;
2000-12-03 10:36:15 +03:00
}
if ( strncmp ( tok , " OWNER: " , 6 ) = = 0 ) {
2021-01-14 22:49:00 +03:00
if ( have_owner ) {
2006-03-13 04:32:30 +03:00
printf ( " Only specify owner once \n " ) ;
goto done ;
}
2021-01-14 22:49:00 +03:00
if ( ! StringToSid ( cli , & owner_sid , tok + 6 ) ) {
2000-12-03 10:36:15 +03:00
printf ( " Failed to parse owner sid \n " ) ;
2006-03-13 03:35:33 +03:00
goto done ;
2000-12-03 10:36:15 +03:00
}
2021-01-14 22:49:00 +03:00
have_owner = true ;
2000-12-12 09:06:10 +03:00
continue ;
2000-12-03 10:36:15 +03:00
}
if ( strncmp ( tok , " GROUP: " , 6 ) = = 0 ) {
2021-01-14 22:49:00 +03:00
if ( have_group ) {
2006-03-13 04:32:30 +03:00
printf ( " Only specify group once \n " ) ;
goto done ;
}
2021-01-14 22:49:00 +03:00
if ( ! StringToSid ( cli , & group_sid , tok + 6 ) ) {
2000-12-03 10:36:15 +03:00
printf ( " Failed to parse group sid \n " ) ;
2006-03-13 03:35:33 +03:00
goto done ;
2000-12-03 10:36:15 +03:00
}
2021-01-14 22:49:00 +03:00
have_group = true ;
2000-12-12 09:06:10 +03:00
continue ;
2000-12-03 10:36:15 +03:00
}
2000-12-04 07:58:40 +03:00
if ( strncmp ( tok , " ACL: " , 4 ) = = 0 ) {
2010-05-18 05:25:38 +04:00
struct security_ace ace ;
2007-10-10 18:57:34 +04:00
if ( ! parse_ace ( cli , & ace , tok + 4 ) ) {
2006-03-13 03:35:33 +03:00
goto done ;
2000-12-15 04:02:11 +03:00
}
if ( ! add_ace ( & dacl , & ace ) ) {
printf ( " Failed to add ACL %s \n " , tok ) ;
2006-03-13 03:35:33 +03:00
goto done ;
2000-12-03 10:36:15 +03:00
}
2000-12-12 09:06:10 +03:00
continue ;
2000-12-03 10:36:15 +03:00
}
2000-12-12 09:06:10 +03:00
2005-11-02 05:13:08 +03:00
printf ( " Failed to parse token '%s' in security descriptor, \n " , tok ) ;
2006-03-13 03:35:33 +03:00
goto done ;
2000-12-03 10:36:15 +03:00
}
2021-01-14 22:49:00 +03:00
ret = make_sec_desc (
ctx ,
revision ,
SEC_DESC_SELF_RELATIVE ,
have_owner ? & owner_sid : NULL ,
have_group ? & group_sid : NULL ,
NULL ,
dacl ,
& sd_size ) ;
2000-12-03 10:36:15 +03:00
2021-01-14 22:49:00 +03:00
done :
2000-12-03 10:36:15 +03:00
return ret ;
}
2010-05-06 09:35:02 +04:00
/*****************************************************
get fileinfo for filename
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-05-07 03:00:06 +03:00
static uint16_t get_fileinfo ( struct cli_state * cli , const char * filename )
2010-05-06 09:35:02 +04:00
{
uint16_t fnum = ( uint16_t ) - 1 ;
2011-01-15 18:32:00 +03:00
NTSTATUS status ;
s3/utils: smbcacls failed to detect DIRECTORIES using SMB2 (windows only)
uint16_t get_fileinfo(...) returns file attributes, this function
called
cli_qfileinfo_basic(cli, fnum, &mode, NULL, NULL, NULL,
NULL, NULL, NULL);
which was failing with NT_STATUS_ACCESS_DENIED errors when fnum above
was obtained via (when using protocol > SMB). Note: This only seems to be
an issue when run against a windows server, with smbd SMB1 & SMB2 work fine.
status = cli_ntcreate(cli, filename, 0, CREATE_ACCESS_READ,
0, FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN, 0x0, 0x0, &fnum, NULL);
The failing cli_qfileinfo_basic call above is unnecessary as we can already
obtain the required information from the cli_ntcreate call
Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: David Disseldorp <ddiss@samba.org>
2017-07-20 15:01:50 +03:00
struct smb_create_returns cr = { 0 } ;
2010-05-06 09:35:02 +04:00
/* The desired access below is the only one I could find that works
with NT4 , W2KP and Samba */
2020-05-26 09:07:41 +03:00
status = cli_ntcreate (
cli , /* cli */
filename , /* fname */
0 , /* CreatFlags */
2020-05-26 09:04:52 +03:00
READ_CONTROL_ACCESS , /* CreatFlags */
2020-05-26 09:07:41 +03:00
0 , /* FileAttributes */
FILE_SHARE_READ |
FILE_SHARE_WRITE , /* ShareAccess */
FILE_OPEN , /* CreateDisposition */
0x0 , /* CreateOptions */
0x0 , /* SecurityFlags */
& fnum , /* pfid */
& cr ) ; /* cr */
2011-01-15 18:32:00 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to open %s: %s \n " , filename , nt_errstr ( status ) ) ;
return 0 ;
2010-05-06 09:35:02 +04:00
}
cli_close ( cli , fnum ) ;
s3/utils: smbcacls failed to detect DIRECTORIES using SMB2 (windows only)
uint16_t get_fileinfo(...) returns file attributes, this function
called
cli_qfileinfo_basic(cli, fnum, &mode, NULL, NULL, NULL,
NULL, NULL, NULL);
which was failing with NT_STATUS_ACCESS_DENIED errors when fnum above
was obtained via (when using protocol > SMB). Note: This only seems to be
an issue when run against a windows server, with smbd SMB1 & SMB2 work fine.
status = cli_ntcreate(cli, filename, 0, CREATE_ACCESS_READ,
0, FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN, 0x0, 0x0, &fnum, NULL);
The failing cli_qfileinfo_basic call above is unnecessary as we can already
obtain the required information from the cli_ntcreate call
Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: David Disseldorp <ddiss@samba.org>
2017-07-20 15:01:50 +03:00
return cr . file_attributes ;
2010-05-06 09:35:02 +04:00
}
2010-05-03 05:08:29 +04:00
/*****************************************************
get sec desc for filename
2000-12-03 05:19:27 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-11-14 21:45:07 +04:00
static struct security_descriptor * get_secdesc_with_ctx ( TALLOC_CTX * ctx ,
struct cli_state * cli ,
const char * filename )
2000-12-03 05:19:27 +03:00
{
2009-05-01 02:26:43 +04:00
uint16_t fnum = ( uint16_t ) - 1 ;
2010-05-18 12:29:34 +04:00
struct security_descriptor * sd ;
2011-01-15 18:32:00 +03:00
NTSTATUS status ;
2012-11-30 17:36:07 +04:00
uint32_t sec_info ;
uint32_t desired_access = 0 ;
2000-12-03 05:19:27 +03:00
2012-11-30 17:36:07 +04:00
if ( query_sec_info = = - 1 ) {
sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL ;
} else {
sec_info = query_sec_info ;
}
2000-12-07 09:05:57 +03:00
2012-11-30 17:36:07 +04:00
if ( sec_info & ( SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL ) ) {
desired_access | = SEC_STD_READ_CONTROL ;
}
if ( sec_info & SECINFO_SACL ) {
desired_access | = SEC_FLAG_SYSTEM_SECURITY ;
}
if ( desired_access = = 0 ) {
desired_access | = SEC_STD_READ_CONTROL ;
}
status = cli_ntcreate ( cli , filename , 0 , desired_access ,
2011-01-15 18:32:00 +03:00
0 , FILE_SHARE_READ | FILE_SHARE_WRITE ,
2014-05-09 07:55:57 +04:00
FILE_OPEN , 0x0 , 0x0 , & fnum , NULL ) ;
2011-01-15 18:32:00 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to open %s: %s \n " , filename , nt_errstr ( status ) ) ;
2010-05-03 05:08:29 +04:00
return NULL ;
2000-12-03 05:19:27 +03:00
}
2012-11-30 17:36:07 +04:00
status = cli_query_security_descriptor ( cli , fnum , sec_info ,
2013-11-14 21:45:07 +04:00
ctx , & sd ) ;
2000-12-03 08:24:16 +03:00
2010-05-03 05:08:29 +04:00
cli_close ( cli , fnum ) ;
2011-07-22 18:56:04 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to get security descriptor: %s \n " ,
nt_errstr ( status ) ) ;
2010-05-03 05:08:29 +04:00
return NULL ;
2000-12-03 08:24:16 +03:00
}
2010-05-03 05:08:29 +04:00
return sd ;
}
2000-12-03 08:24:16 +03:00
2013-11-14 21:45:07 +04:00
static struct security_descriptor * get_secdesc ( struct cli_state * cli ,
const char * filename )
{
return get_secdesc_with_ctx ( talloc_tos ( ) , cli , filename ) ;
}
2010-05-06 09:26:15 +04:00
/*****************************************************
set sec desc for filename
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool set_secdesc ( struct cli_state * cli , const char * filename ,
2010-05-18 12:29:34 +04:00
struct security_descriptor * sd )
2010-05-06 09:26:15 +04:00
{
uint16_t fnum = ( uint16_t ) - 1 ;
bool result = true ;
2011-01-15 18:20:37 +03:00
NTSTATUS status ;
2012-02-03 04:28:39 +04:00
uint32_t desired_access = 0 ;
2012-11-30 17:36:07 +04:00
uint32_t sec_info ;
if ( set_sec_info = = - 1 ) {
sec_info = 0 ;
if ( sd - > dacl | | ( sd - > type & SEC_DESC_DACL_PRESENT ) ) {
sec_info | = SECINFO_DACL ;
}
if ( sd - > sacl | | ( sd - > type & SEC_DESC_SACL_PRESENT ) ) {
sec_info | = SECINFO_SACL ;
}
if ( sd - > owner_sid ) {
sec_info | = SECINFO_OWNER ;
}
if ( sd - > group_sid ) {
sec_info | = SECINFO_GROUP ;
}
} else {
sec_info = set_sec_info ;
}
2010-05-06 09:26:15 +04:00
2012-02-03 04:28:39 +04:00
/* Make the desired_access more specific. */
2012-11-30 17:36:07 +04:00
if ( sec_info & SECINFO_DACL ) {
desired_access | = SEC_STD_WRITE_DAC ;
2012-02-03 04:28:39 +04:00
}
2012-11-30 17:36:07 +04:00
if ( sec_info & SECINFO_SACL ) {
2012-02-03 04:28:39 +04:00
desired_access | = SEC_FLAG_SYSTEM_SECURITY ;
}
2012-11-30 17:36:07 +04:00
if ( sec_info & ( SECINFO_OWNER | SECINFO_GROUP ) ) {
desired_access | = SEC_STD_WRITE_OWNER ;
2012-02-03 04:28:39 +04:00
}
2010-05-06 09:26:15 +04:00
2011-01-15 18:32:00 +03:00
status = cli_ntcreate ( cli , filename , 0 ,
2012-02-03 04:28:39 +04:00
desired_access ,
2011-01-15 18:32:00 +03:00
0 , FILE_SHARE_READ | FILE_SHARE_WRITE ,
2014-05-09 07:55:57 +04:00
FILE_OPEN , 0x0 , 0x0 , & fnum , NULL ) ;
2011-01-15 18:32:00 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to open %s: %s \n " , filename , nt_errstr ( status ) ) ;
2010-05-06 09:26:15 +04:00
return false ;
}
2012-11-30 17:36:07 +04:00
status = cli_set_security_descriptor ( cli , fnum , sec_info , sd ) ;
2011-01-15 18:20:37 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2017-09-19 22:31:55 +03:00
printf ( " ERROR: security descriptor set failed: %s \n " ,
2011-01-15 18:20:37 +03:00
nt_errstr ( status ) ) ;
2010-05-06 09:26:15 +04:00
result = false ;
}
cli_close ( cli , fnum ) ;
return result ;
}
2019-02-27 18:45:07 +03:00
/*****************************************************
get maximum access for a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int cacl_mxac ( struct cli_state * cli , const char * filename )
{
NTSTATUS status ;
uint32_t mxac ;
status = cli_query_mxac ( cli , filename , & mxac ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to get mxac: %s \n " , nt_errstr ( status ) ) ;
return EXIT_FAILED ;
}
printf ( " Maximum access: 0x%x \n " , mxac ) ;
return EXIT_OK ;
}
2010-05-03 05:08:29 +04:00
/*****************************************************
dump the acls for a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-04-24 18:31:41 +03:00
static int cacl_dump ( struct cli_state * cli , const char * filename , bool numeric )
2010-05-03 05:08:29 +04:00
{
2010-05-18 12:29:34 +04:00
struct security_descriptor * sd ;
2019-02-27 18:45:07 +03:00
int ret ;
2000-12-03 05:19:27 +03:00
2011-06-14 15:56:22 +04:00
if ( test_args ) {
2010-05-03 05:08:29 +04:00
return EXIT_OK ;
2011-06-14 15:56:22 +04:00
}
2000-12-22 02:36:25 +03:00
2010-05-03 05:08:29 +04:00
sd = get_secdesc ( cli , filename ) ;
2011-06-14 15:56:22 +04:00
if ( sd = = NULL ) {
return EXIT_FAILED ;
}
2010-05-03 05:08:29 +04:00
2011-06-14 15:56:22 +04:00
if ( sddl ) {
char * str = sddl_encode ( talloc_tos ( ) , sd , get_domain_sid ( cli ) ) ;
if ( str = = NULL ) {
return EXIT_FAILED ;
2010-05-03 05:08:29 +04:00
}
2011-06-14 15:56:22 +04:00
printf ( " %s \n " , str ) ;
TALLOC_FREE ( str ) ;
} else {
2015-04-24 18:31:41 +03:00
sec_desc_print ( cli , stdout , sd , numeric ) ;
2010-05-03 05:08:29 +04:00
}
2002-12-20 04:35:21 +03:00
2019-02-27 18:45:07 +03:00
if ( want_mxac ) {
ret = cacl_mxac ( cli , filename ) ;
if ( ret ! = EXIT_OK ) {
return ret ;
}
}
2011-06-14 15:56:22 +04:00
return EXIT_OK ;
2000-12-03 05:19:27 +03:00
}
2023-08-07 07:26:40 +03:00
/*****************************************************
2000-12-16 03:08:05 +03:00
Change the ownership or group ownership of a file . Just
because the NT docs say this can ' t be done : - ) . JRA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2023-08-07 07:26:40 +03:00
static int owner_set ( struct cli_state * cli , enum chown_mode change_mode ,
2007-12-04 05:48:41 +03:00
const char * filename , const char * new_username )
2000-12-16 03:08:05 +03:00
{
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2017-10-06 09:01:46 +03:00
struct security_descriptor * sd ;
2000-12-16 03:08:05 +03:00
size_t sd_size ;
2007-10-10 18:57:34 +04:00
if ( ! StringToSid ( cli , & sid , new_username ) )
2000-12-22 02:36:25 +03:00
return EXIT_PARSE_ERROR ;
2000-12-16 03:08:05 +03:00
2017-10-06 09:01:46 +03:00
sd = make_sec_desc ( talloc_tos ( ) ,
SECURITY_DESCRIPTOR_REVISION_1 ,
SEC_DESC_SELF_RELATIVE ,
( change_mode = = REQUEST_CHOWN ) ? & sid : NULL ,
( change_mode = = REQUEST_CHGRP ) ? & sid : NULL ,
2003-06-24 05:09:36 +04:00
NULL , NULL , & sd_size ) ;
2000-12-16 03:08:05 +03:00
2010-05-06 09:26:15 +04:00
if ( ! set_secdesc ( cli , filename , sd ) ) {
2001-02-22 06:40:01 +03:00
return EXIT_FAILED ;
}
2000-12-22 02:36:25 +03:00
return EXIT_OK ;
2000-12-16 03:08:05 +03:00
}
2001-02-23 10:20:11 +03:00
2008-10-15 03:09:17 +04:00
/* The MSDN is contradictory over the ordering of ACE entries in an
ACL . However NT4 gives a " The information may have been modified
by a computer running Windows NT 5.0 " if denied ACEs do not appear
before allowed ACEs . At
http : //technet.microsoft.com/en-us/library/cc781716.aspx the
canonical order is specified as " Explicit Deny, Explicit Allow,
Inherited ACEs unchanged " */
2000-12-21 09:21:26 +03:00
2010-05-18 05:25:38 +04:00
static int ace_compare ( struct security_ace * ace1 , struct security_ace * ace2 )
2000-12-21 09:21:26 +03:00
{
2014-05-28 19:44:43 +04:00
if ( security_ace_equal ( ace1 , ace2 ) )
2001-11-30 04:04:15 +03:00
return 0 ;
2008-10-15 03:09:17 +04:00
if ( ( ace1 - > flags & SEC_ACE_FLAG_INHERITED_ACE ) & &
! ( ace2 - > flags & SEC_ACE_FLAG_INHERITED_ACE ) )
return 1 ;
if ( ! ( ace1 - > flags & SEC_ACE_FLAG_INHERITED_ACE ) & &
( ace2 - > flags & SEC_ACE_FLAG_INHERITED_ACE ) )
return - 1 ;
if ( ( ace1 - > flags & SEC_ACE_FLAG_INHERITED_ACE ) & &
( ace2 - > flags & SEC_ACE_FLAG_INHERITED_ACE ) )
return ace1 - ace2 ;
if ( ace1 - > type ! = ace2 - > type )
2001-11-30 04:04:15 +03:00
return ace2 - > type - ace1 - > type ;
2010-08-26 17:48:50 +04:00
if ( dom_sid_compare ( & ace1 - > trustee , & ace2 - > trustee ) )
return dom_sid_compare ( & ace1 - > trustee , & ace2 - > trustee ) ;
2001-11-30 04:04:15 +03:00
2008-10-15 03:09:17 +04:00
if ( ace1 - > flags ! = ace2 - > flags )
2001-11-30 04:04:15 +03:00
return ace1 - > flags - ace2 - > flags ;
2008-10-15 03:09:17 +04:00
if ( ace1 - > access_mask ! = ace2 - > access_mask )
2006-09-21 02:23:12 +04:00
return ace1 - > access_mask - ace2 - > access_mask ;
2001-11-30 04:04:15 +03:00
2008-10-15 03:09:17 +04:00
if ( ace1 - > size ! = ace2 - > size )
2001-11-30 04:04:15 +03:00
return ace1 - > size - ace2 - > size ;
2010-05-18 05:25:38 +04:00
return memcmp ( ace1 , ace2 , sizeof ( struct security_ace ) ) ;
2001-02-23 10:20:11 +03:00
}
2000-12-21 09:21:26 +03:00
2010-05-18 05:30:40 +04:00
static void sort_acl ( struct security_acl * the_acl )
2001-02-23 10:20:11 +03:00
{
2015-05-07 03:00:06 +03:00
uint32_t i ;
2001-02-22 09:35:54 +03:00
if ( ! the_acl ) return ;
2010-02-14 02:03:55 +03:00
TYPESAFE_QSORT ( the_acl - > aces , the_acl - > num_aces , ace_compare ) ;
2000-12-21 09:21:26 +03:00
2001-02-23 10:20:11 +03:00
for ( i = 1 ; i < the_acl - > num_aces ; ) {
2014-05-28 19:44:43 +04:00
if ( security_ace_equal ( & the_acl - > aces [ i - 1 ] ,
& the_acl - > aces [ i ] ) ) {
2020-03-26 13:39:56 +03:00
ARRAY_DEL_ELEMENT (
the_acl - > aces , i , the_acl - > num_aces ) ;
2001-02-23 10:20:11 +03:00
the_acl - > num_aces - - ;
} else {
i + + ;
2000-12-21 09:21:26 +03:00
}
}
}
2023-08-07 07:26:40 +03:00
/*****************************************************
2013-11-14 21:45:07 +04:00
set the ACLs on a file given a security descriptor
2000-12-03 10:36:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-10-15 03:09:17 +04:00
2013-11-14 21:45:07 +04:00
static int cacl_set_from_sd ( struct cli_state * cli , const char * filename ,
struct security_descriptor * sd , enum acl_mode mode ,
bool numeric )
2000-12-03 10:36:15 +03:00
{
2013-11-14 21:45:07 +04:00
struct security_descriptor * old = NULL ;
2015-05-07 03:00:06 +03:00
uint32_t i , j ;
2000-12-16 03:08:05 +03:00
size_t sd_size ;
2000-12-22 02:36:25 +03:00
int result = EXIT_OK ;
2000-12-03 10:36:15 +03:00
2000-12-22 02:36:25 +03:00
if ( ! sd ) return EXIT_PARSE_ERROR ;
if ( test_args ) return EXIT_OK ;
2000-12-07 09:05:57 +03:00
2016-04-30 01:12:38 +03:00
if ( mode ! = SMB_ACL_SET ) {
/*
* Do not fetch old ACL when it will be overwritten
* completely with a new one .
*/
old = get_secdesc ( cli , filename ) ;
if ( ! old ) {
return EXIT_FAILED ;
}
2001-02-22 06:40:01 +03:00
}
2000-12-03 15:41:28 +03:00
/* the logic here is rather more complex than I would like */
switch ( mode ) {
2001-04-11 05:34:37 +04:00
case SMB_ACL_DELETE :
2000-12-03 15:41:28 +03:00
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
2007-10-19 04:40:25 +04:00
bool found = False ;
2000-12-12 09:06:10 +03:00
2000-12-03 15:41:28 +03:00
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
2014-05-28 19:44:43 +04:00
if ( security_ace_equal ( & sd - > dacl - > aces [ i ] ,
& old - > dacl - > aces [ j ] ) ) {
2015-05-07 03:00:06 +03:00
uint32_t k ;
2001-02-23 10:20:11 +03:00
for ( k = j ; k < old - > dacl - > num_aces - 1 ; k + + ) {
2006-09-21 02:23:12 +04:00
old - > dacl - > aces [ k ] = old - > dacl - > aces [ k + 1 ] ;
2000-12-04 03:33:08 +03:00
}
old - > dacl - > num_aces - - ;
2000-12-12 09:06:10 +03:00
found = True ;
2000-12-04 03:33:08 +03:00
break ;
2000-12-03 15:41:28 +03:00
}
}
2000-12-12 09:06:10 +03:00
if ( ! found ) {
2008-10-15 03:09:17 +04:00
printf ( " ACL for ACE: " ) ;
2015-04-24 18:31:41 +03:00
print_ace ( cli , stdout , & sd - > dacl - > aces [ i ] ,
numeric ) ;
2001-02-23 10:20:11 +03:00
printf ( " not found \n " ) ;
2000-12-12 09:06:10 +03:00
}
2000-12-03 15:41:28 +03:00
}
break ;
2001-04-11 05:34:37 +04:00
case SMB_ACL_MODIFY :
2000-12-03 15:41:28 +03:00
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
2007-10-19 04:40:25 +04:00
bool found = False ;
2000-12-04 09:43:36 +03:00
2000-12-03 15:41:28 +03:00
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
2010-08-26 17:48:50 +04:00
if ( dom_sid_equal ( & sd - > dacl - > aces [ i ] . trustee ,
2006-09-21 02:23:12 +04:00
& old - > dacl - > aces [ j ] . trustee ) ) {
old - > dacl - > aces [ j ] = sd - > dacl - > aces [ i ] ;
2000-12-04 09:43:36 +03:00
found = True ;
2000-12-03 15:41:28 +03:00
}
}
2000-12-04 09:43:36 +03:00
if ( ! found ) {
fstring str ;
2007-10-10 18:57:34 +04:00
SidToString ( cli , str ,
2015-04-24 18:31:41 +03:00
& sd - > dacl - > aces [ i ] . trustee ,
numeric ) ;
2000-12-04 09:43:36 +03:00
printf ( " ACL for SID %s not found \n " , str ) ;
}
2000-12-03 15:41:28 +03:00
}
2000-12-04 09:43:36 +03:00
2004-11-23 04:05:31 +03:00
if ( sd - > owner_sid ) {
old - > owner_sid = sd - > owner_sid ;
}
2008-10-15 03:09:17 +04:00
if ( sd - > group_sid ) {
2006-09-21 02:23:12 +04:00
old - > group_sid = sd - > group_sid ;
2004-11-23 04:05:31 +03:00
}
2000-12-03 15:41:28 +03:00
break ;
2001-04-11 05:34:37 +04:00
case SMB_ACL_ADD :
2000-12-03 15:41:28 +03:00
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
2006-09-21 02:23:12 +04:00
add_ace ( & old - > dacl , & sd - > dacl - > aces [ i ] ) ;
2000-12-03 15:41:28 +03:00
}
break ;
2001-04-11 05:34:37 +04:00
case SMB_ACL_SET :
2000-12-12 09:06:10 +03:00
old = sd ;
2000-12-03 15:41:28 +03:00
break ;
}
2000-12-03 10:36:15 +03:00
2000-12-21 09:21:26 +03:00
/* Denied ACE entries must come before allowed ones */
sort_acl ( old - > dacl ) ;
/* Create new security descriptor and set it */
2007-07-10 02:15:22 +04:00
2005-11-02 05:35:48 +03:00
/* We used to just have "WRITE_DAC_ACCESS" without WRITE_OWNER.
But if we ' re sending an owner , even if it ' s the same as the one
that already exists then W2K3 insists we open with WRITE_OWNER access .
I need to check that setting a SD with no owner set works against WNT
and W2K . JRA .
*/
2007-10-10 18:57:34 +04:00
sd = make_sec_desc ( talloc_tos ( ) , old - > revision , old - > type ,
old - > owner_sid , old - > group_sid ,
2000-12-04 07:58:40 +03:00
NULL , old - > dacl , & sd_size ) ;
2000-12-04 03:33:08 +03:00
2010-05-06 09:26:15 +04:00
if ( ! set_secdesc ( cli , filename , sd ) ) {
2000-12-22 02:36:25 +03:00
result = EXIT_FAILED ;
2000-12-03 10:36:15 +03:00
}
2000-12-22 02:36:25 +03:00
return result ;
2000-12-03 10:36:15 +03:00
}
2013-11-14 21:45:07 +04:00
/*****************************************************
set the ACLs on a file given an ascii description
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int cacl_set ( struct cli_state * cli , const char * filename ,
char * the_acl , enum acl_mode mode , bool numeric )
{
struct security_descriptor * sd = NULL ;
if ( sddl ) {
2022-08-26 16:17:07 +03:00
sd = sddl_decode ( talloc_tos ( ) , the_acl , get_domain_sid ( cli ) ) ;
2013-11-14 21:45:07 +04:00
} else {
sd = sec_desc_parse ( talloc_tos ( ) , cli , the_acl ) ;
}
if ( sd = = NULL ) {
return EXIT_PARSE_ERROR ;
}
if ( test_args ) {
return EXIT_OK ;
}
return cacl_set_from_sd ( cli , filename , sd , mode , numeric ) ;
}
2010-05-06 09:35:02 +04:00
/*****************************************************
set the inherit on a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int inherit ( struct cli_state * cli , const char * filename ,
const char * type )
{
2010-05-18 12:29:34 +04:00
struct security_descriptor * old , * sd ;
2015-05-07 03:00:06 +03:00
uint32_t oldattr ;
2010-05-06 09:35:02 +04:00
size_t sd_size ;
int result = EXIT_OK ;
old = get_secdesc ( cli , filename ) ;
if ( ! old ) {
return EXIT_FAILED ;
}
oldattr = get_fileinfo ( cli , filename ) ;
if ( strcmp ( type , " allow " ) = = 0 ) {
if ( ( old - > type & SEC_DESC_DACL_PROTECTED ) = =
SEC_DESC_DACL_PROTECTED ) {
2020-05-26 09:16:32 +03:00
uint32_t i ;
2010-05-06 09:35:02 +04:00
char * parentname , * temp ;
2010-05-18 12:29:34 +04:00
struct security_descriptor * parent ;
2010-05-06 09:35:02 +04:00
temp = talloc_strdup ( talloc_tos ( ) , filename ) ;
old - > type = old - > type & ( ~ SEC_DESC_DACL_PROTECTED ) ;
/* look at parent and copy in all its inheritable ACL's. */
string_replace ( temp , ' \\ ' , ' / ' ) ;
if ( ! parent_dirname ( talloc_tos ( ) , temp , & parentname , NULL ) ) {
return EXIT_FAILED ;
}
string_replace ( parentname , ' / ' , ' \\ ' ) ;
parent = get_secdesc ( cli , parentname ) ;
2011-03-23 15:11:26 +03:00
if ( parent = = NULL ) {
return EXIT_FAILED ;
}
2010-05-06 09:35:02 +04:00
for ( i = 0 ; i < parent - > dacl - > num_aces ; i + + ) {
2010-05-18 05:25:38 +04:00
struct security_ace * ace = & parent - > dacl - > aces [ i ] ;
2010-06-05 04:48:40 +04:00
/* Add inherited flag to all aces */
ace - > flags = ace - > flags |
SEC_ACE_FLAG_INHERITED_ACE ;
2011-04-29 05:57:02 +04:00
if ( ( oldattr & FILE_ATTRIBUTE_DIRECTORY ) = = FILE_ATTRIBUTE_DIRECTORY ) {
2010-05-06 09:35:02 +04:00
if ( ( ace - > flags & SEC_ACE_FLAG_CONTAINER_INHERIT ) = =
SEC_ACE_FLAG_CONTAINER_INHERIT ) {
add_ace ( & old - > dacl , ace ) ;
}
} else {
if ( ( ace - > flags & SEC_ACE_FLAG_OBJECT_INHERIT ) = =
SEC_ACE_FLAG_OBJECT_INHERIT ) {
2010-06-05 04:48:40 +04:00
/* clear flags for files */
ace - > flags = 0 ;
2010-05-06 09:35:02 +04:00
add_ace ( & old - > dacl , ace ) ;
}
}
}
} else {
printf ( " Already set to inheritable permissions. \n " ) ;
return EXIT_FAILED ;
}
} else if ( strcmp ( type , " remove " ) = = 0 ) {
if ( ( old - > type & SEC_DESC_DACL_PROTECTED ) ! =
SEC_DESC_DACL_PROTECTED ) {
old - > type = old - > type | SEC_DESC_DACL_PROTECTED ;
/* remove all inherited ACL's. */
if ( old - > dacl ) {
int i ;
2010-05-18 05:30:40 +04:00
struct security_acl * temp = old - > dacl ;
2010-05-06 09:35:02 +04:00
old - > dacl = make_sec_acl ( talloc_tos ( ) , 3 , 0 , NULL ) ;
for ( i = temp - > num_aces - 1 ; i > = 0 ; i - - ) {
2010-05-18 05:25:38 +04:00
struct security_ace * ace = & temp - > aces [ i ] ;
2010-05-06 09:35:02 +04:00
/* Remove all ace with INHERITED flag set */
if ( ( ace - > flags & SEC_ACE_FLAG_INHERITED_ACE ) ! =
SEC_ACE_FLAG_INHERITED_ACE ) {
add_ace ( & old - > dacl , ace ) ;
}
}
}
} else {
printf ( " Already set to no inheritable permissions. \n " ) ;
return EXIT_FAILED ;
}
} else if ( strcmp ( type , " copy " ) = = 0 ) {
if ( ( old - > type & SEC_DESC_DACL_PROTECTED ) ! =
SEC_DESC_DACL_PROTECTED ) {
old - > type = old - > type | SEC_DESC_DACL_PROTECTED ;
2020-05-26 09:17:14 +03:00
/*
* convert all inherited ACL ' s to non
* inherited ACL ' s .
*/
2010-05-06 09:35:02 +04:00
if ( old - > dacl ) {
2020-05-26 09:16:32 +03:00
uint32_t i ;
2010-05-06 09:35:02 +04:00
for ( i = 0 ; i < old - > dacl - > num_aces ; i + + ) {
2010-05-18 05:25:38 +04:00
struct security_ace * ace = & old - > dacl - > aces [ i ] ;
2010-05-06 09:35:02 +04:00
/* Remove INHERITED FLAG from all aces */
ace - > flags = ace - > flags & ( ~ SEC_ACE_FLAG_INHERITED_ACE ) ;
}
}
} else {
printf ( " Already set to no inheritable permissions. \n " ) ;
return EXIT_FAILED ;
}
}
/* Denied ACE entries must come before allowed ones */
sort_acl ( old - > dacl ) ;
sd = make_sec_desc ( talloc_tos ( ) , old - > revision , old - > type ,
old - > owner_sid , old - > group_sid ,
NULL , old - > dacl , & sd_size ) ;
if ( ! set_secdesc ( cli , filename , sd ) ) {
result = EXIT_FAILED ;
}
return result ;
}
2000-12-03 05:19:27 +03:00
2007-10-25 01:16:54 +04:00
/*****************************************************
Return a connection to a server .
2000-12-03 05:19:27 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-01-13 16:00:56 +03:00
static struct cli_state * connect_one ( struct cli_credentials * creds ,
2008-12-14 15:06:19 +03:00
const char * server , const char * share )
2000-12-03 05:19:27 +03:00
{
2008-01-05 11:23:35 +03:00
struct cli_state * c = NULL ;
2002-07-15 14:35:28 +04:00
NTSTATUS nt_status ;
2008-05-05 18:58:24 +04:00
uint32_t flags = 0 ;
2019-11-11 16:48:12 +03:00
nt_status = cli_full_connection_creds ( & c , lp_netbios_name ( ) , server ,
2011-07-22 14:29:57 +04:00
NULL , 0 ,
2008-01-05 11:23:35 +03:00
share , " ????? " ,
2021-01-13 16:00:56 +03:00
creds ,
2020-06-04 15:59:14 +03:00
flags ) ;
2008-01-05 11:23:35 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 0 , ( " cli_full_connection failed! (%s) \n " , nt_errstr ( nt_status ) ) ) ;
2000-12-03 05:19:27 +03:00
return NULL ;
}
2008-01-05 11:23:35 +03:00
return c ;
2000-12-03 05:19:27 +03:00
}
2013-11-14 21:45:07 +04:00
/*
* Process resulting combination of mask & fname ensuring
* terminated with wildcard
*/
static char * build_dirname ( TALLOC_CTX * ctx ,
const char * mask , char * dir , char * fname )
{
char * mask2 = NULL ;
char * p = NULL ;
mask2 = talloc_strdup ( ctx , mask ) ;
if ( ! mask2 ) {
return NULL ;
}
p = strrchr_m ( mask2 , DIRSEP_CHAR ) ;
if ( p ) {
p [ 1 ] = 0 ;
} else {
mask2 [ 0 ] = ' \0 ' ;
}
mask2 = talloc_asprintf_append ( mask2 ,
" %s \\ * " ,
fname ) ;
return mask2 ;
}
/*
2023-09-05 07:04:18 +03:00
* Returns a copy of the ACL flags in ace modified according
2013-11-14 21:45:07 +04:00
* to some inheritance rules .
* a ) SEC_ACE_FLAG_INHERITED_ACE is propagated to children
* b ) SEC_ACE_FLAG_INHERIT_ONLY is set on container children for OI ( only )
* c ) SEC_ACE_FLAG_OBJECT_INHERIT & SEC_ACE_FLAG_CONTAINER_INHERIT are
* stripped from flags to be propagated to non - container children
* d ) SEC_ACE_FLAG_OBJECT_INHERIT & SEC_ACE_FLAG_CONTAINER_INHERIT are
* stripped from flags to be propagated if the NP flag
* SEC_ACE_FLAG_NO_PROPAGATE_INHERIT is present
*/
static uint8_t get_flags_to_propagate ( bool is_container ,
struct security_ace * ace )
{
uint8_t newflags = ace - > flags ;
/* OBJECT inheritance */
bool acl_objinherit = ( ace - > flags &
SEC_ACE_FLAG_OBJECT_INHERIT ) = = SEC_ACE_FLAG_OBJECT_INHERIT ;
/* CONTAINER inheritance */
bool acl_cntrinherit = ( ace - > flags &
SEC_ACE_FLAG_CONTAINER_INHERIT ) = =
SEC_ACE_FLAG_CONTAINER_INHERIT ;
/* PROHIBIT inheritance */
bool prohibit_inheritance = ( ( ace - > flags &
SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) = =
SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) ;
/* Assume we are not propagating the ACE */
newflags & = ~ SEC_ACE_FLAG_INHERITED_ACE ;
/* all children need to have the SEC_ACE_FLAG_INHERITED_ACE set */
if ( acl_cntrinherit | | acl_objinherit ) {
/*
* object inherit ( alone ) on a container needs
* SEC_ACE_FLAG_INHERIT_ONLY
*/
if ( is_container ) {
if ( acl_objinherit & & ! acl_cntrinherit ) {
newflags | = SEC_ACE_FLAG_INHERIT_ONLY ;
}
/*
* this is tricky , the only time we would not
* propagate the ace for a container is if
* prohibit_inheritance is set and object inheritance
* alone is set
*/
if ( ( prohibit_inheritance
& & acl_objinherit
& & ! acl_cntrinherit ) = = false ) {
newflags | = SEC_ACE_FLAG_INHERITED_ACE ;
}
} else {
/*
* don ' t apply object / container inheritance flags to
* non dirs
*/
newflags & = ~ ( SEC_ACE_FLAG_OBJECT_INHERIT
| SEC_ACE_FLAG_CONTAINER_INHERIT
| SEC_ACE_FLAG_INHERIT_ONLY ) ;
/*
* only apply ace to file if object inherit
*/
if ( acl_objinherit ) {
newflags | = SEC_ACE_FLAG_INHERITED_ACE ;
}
}
/* if NP is specified strip NP and all OI/CI INHERIT flags */
if ( prohibit_inheritance ) {
newflags & = ~ ( SEC_ACE_FLAG_OBJECT_INHERIT
| SEC_ACE_FLAG_CONTAINER_INHERIT
| SEC_ACE_FLAG_INHERIT_ONLY
| SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) ;
}
}
return newflags ;
}
/*
* This function builds a new acl for ' caclfile ' , first it removes any
* existing inheritable ace ( s ) from the current acl of caclfile , secondly it
* applies any inheritable acls of the parent of caclfile ( inheritable acls of
* caclfile ' s parent are passed via acl_to_add member of cbstate )
*
*/
static NTSTATUS propagate_inherited_aces ( char * caclfile ,
struct cacl_callback_state * cbstate )
{
TALLOC_CTX * aclctx = NULL ;
NTSTATUS status ;
int result ;
int fileattr ;
struct security_descriptor * old = NULL ;
bool is_container = false ;
struct security_acl * acl_to_add = cbstate - > acl_to_add ;
struct security_acl * acl_to_remove = NULL ;
uint32_t i , j ;
aclctx = talloc_new ( NULL ) ;
if ( aclctx = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
old = get_secdesc_with_ctx ( aclctx , cbstate - > cli , caclfile ) ;
if ( ! old ) {
status = NT_STATUS_UNSUCCESSFUL ;
goto out ;
}
/* inhibit propagation? */
if ( ( old - > type & SEC_DESC_DACL_PROTECTED ) = =
SEC_DESC_DACL_PROTECTED ) {
status = NT_STATUS_OK ;
goto out ;
}
fileattr = get_fileinfo ( cbstate - > cli , caclfile ) ;
is_container = ( fileattr & FILE_ATTRIBUTE_DIRECTORY ) ;
/* find acl(s) that are inherited */
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
if ( old - > dacl - > aces [ j ] . flags & SEC_ACE_FLAG_INHERITED_ACE ) {
if ( ! add_ace_with_ctx ( aclctx , & acl_to_remove ,
& old - > dacl - > aces [ j ] ) ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
}
}
/* remove any acl(s) that are inherited */
if ( acl_to_remove ) {
for ( i = 0 ; i < acl_to_remove - > num_aces ; i + + ) {
struct security_ace ace = acl_to_remove - > aces [ i ] ;
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
if ( security_ace_equal ( & ace ,
& old - > dacl - > aces [ j ] ) ) {
uint32_t k ;
for ( k = j ; k < old - > dacl - > num_aces - 1 ;
k + + ) {
old - > dacl - > aces [ k ] =
old - > dacl - > aces [ k + 1 ] ;
}
old - > dacl - > num_aces - - ;
break ;
}
}
}
}
/* propagate any inheritable ace to be added */
if ( acl_to_add ) {
for ( i = 0 ; i < acl_to_add - > num_aces ; i + + ) {
struct security_ace ace = acl_to_add - > aces [ i ] ;
bool is_objectinherit = ( ace . flags &
SEC_ACE_FLAG_OBJECT_INHERIT ) = =
SEC_ACE_FLAG_OBJECT_INHERIT ;
bool is_inherited ;
/* don't propagate flags to a file unless OI */
if ( ! is_objectinherit & & ! is_container ) {
continue ;
}
/*
* adjust flags according to inheritance
* rules
*/
ace . flags = get_flags_to_propagate ( is_container , & ace ) ;
is_inherited = ( ace . flags &
SEC_ACE_FLAG_INHERITED_ACE ) = =
SEC_ACE_FLAG_INHERITED_ACE ;
/* don't propagate non inherited flags */
if ( ! is_inherited ) {
continue ;
}
if ( ! add_ace_with_ctx ( aclctx , & old - > dacl , & ace ) ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
}
}
result = cacl_set_from_sd ( cbstate - > cli , caclfile ,
old ,
SMB_ACL_SET , cbstate - > numeric ) ;
if ( result ! = EXIT_OK ) {
status = NT_STATUS_UNSUCCESSFUL ;
goto out ;
}
status = NT_STATUS_OK ;
out :
TALLOC_FREE ( aclctx ) ;
return status ;
}
/*
* Returns true if ' ace ' contains SEC_ACE_FLAG_OBJECT_INHERIT or
* SEC_ACE_FLAG_CONTAINER_INHERIT
*/
static bool is_inheritable_ace ( struct security_ace * ace )
{
uint8_t flags = ace - > flags ;
if ( flags & ( SEC_ACE_FLAG_OBJECT_INHERIT
| SEC_ACE_FLAG_CONTAINER_INHERIT ) ) {
return true ;
}
return false ;
}
/* This method does some basic sanity checking with respect to automatic
* inheritance . e . g . it checks if it is possible to do a set , it detects illegal
* attempts to set inherited permissions directly . Additionally this method
* does some basic initialisation for instance it parses the ACL passed on the
* command line .
*/
static NTSTATUS prepare_inheritance_propagation ( TALLOC_CTX * ctx , char * filename ,
struct cacl_callback_state * cbstate )
{
NTSTATUS result ;
char * the_acl = cbstate - > the_acl ;
struct cli_state * cli = cbstate - > cli ;
enum acl_mode mode = cbstate - > mode ;
struct security_descriptor * sd = NULL ;
struct security_descriptor * old = NULL ;
uint32_t j ;
bool propagate = false ;
old = get_secdesc_with_ctx ( ctx , cli , filename ) ;
if ( old = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/* parse acl passed on the command line */
if ( sddl ) {
cbstate - > aclsd = sddl_decode ( ctx , the_acl ,
2022-08-26 16:17:07 +03:00
get_domain_sid ( cli ) ) ;
2013-11-14 21:45:07 +04:00
} else {
cbstate - > aclsd = sec_desc_parse ( ctx , cli , the_acl ) ;
}
if ( ! cbstate - > aclsd ) {
result = NT_STATUS_UNSUCCESSFUL ;
goto out ;
}
sd = cbstate - > aclsd ;
/* set operation if inheritance is enabled doesn't make sense */
if ( mode = = SMB_ACL_SET & & ( ( old - > type & SEC_DESC_DACL_PROTECTED ) ! =
SEC_DESC_DACL_PROTECTED ) ) {
d_printf ( " Inheritance enabled at %s, can't apply set operation \n " , filename ) ;
result = NT_STATUS_UNSUCCESSFUL ;
goto out ;
}
/*
* search command line acl for any illegal SEC_ACE_FLAG_INHERITED_ACE
* flags that are set
*/
for ( j = 0 ; sd - > dacl & & j < sd - > dacl - > num_aces ; j + + ) {
struct security_ace * ace = & sd - > dacl - > aces [ j ] ;
if ( ace - > flags & SEC_ACE_FLAG_INHERITED_ACE ) {
2022-04-01 10:07:47 +03:00
d_printf ( " Illegal parameter %s \n " , the_acl ) ;
2013-11-14 21:45:07 +04:00
result = NT_STATUS_UNSUCCESSFUL ;
goto out ;
}
if ( ! propagate ) {
if ( is_inheritable_ace ( ace ) ) {
propagate = true ;
}
}
}
result = NT_STATUS_OK ;
out :
cbstate - > acl_no_propagate = ! propagate ;
return result ;
}
/*
* This method builds inheritable ace ( s ) from filename ( which should be
* a container ) that need propagating to children in order to provide
* automatic inheritance . Those inheritable ace ( s ) are stored in
* acl_to_add member of cbstate for later processing
* ( see propagate_inherited_aces )
*/
static NTSTATUS get_inheritable_aces ( TALLOC_CTX * ctx , char * filename ,
struct cacl_callback_state * cbstate )
{
NTSTATUS result ;
struct cli_state * cli = NULL ;
struct security_descriptor * sd = NULL ;
struct security_acl * acl_to_add = NULL ;
uint32_t j ;
cli = cbstate - > cli ;
sd = get_secdesc_with_ctx ( ctx , cli , filename ) ;
if ( sd = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/*
* Check if any inheritance related flags are used , if not then
* nothing to do . At the same time populate acls for inheritance
* related ace ( s ) that need to be added to or deleted from children as
* a result of inheritance propagation .
*/
for ( j = 0 ; sd - > dacl & & j < sd - > dacl - > num_aces ; j + + ) {
struct security_ace * ace = & sd - > dacl - > aces [ j ] ;
if ( is_inheritable_ace ( ace ) ) {
bool added = add_ace_with_ctx ( ctx , & acl_to_add , ace ) ;
if ( ! added ) {
result = NT_STATUS_NO_MEMORY ;
goto out ;
}
}
}
cbstate - > acl_to_add = acl_to_add ;
result = NT_STATUS_OK ;
out :
return result ;
}
/*
* Callback handler to handle child elements processed by cli_list , we attempt
* to propagate inheritable ace ( s ) to each child via the function
* propagate_inherited_aces . Children that are themselves directories are passed
2023-07-18 12:36:49 +03:00
* to cli_list again ( to descend the directory structure )
2013-11-14 21:45:07 +04:00
*/
2020-10-19 11:09:23 +03:00
static NTSTATUS cacl_set_cb ( struct file_info * f ,
2013-11-14 21:45:07 +04:00
const char * mask , void * state )
{
struct cacl_callback_state * cbstate =
( struct cacl_callback_state * ) state ;
struct cli_state * cli = NULL ;
2020-08-18 18:42:25 +03:00
struct cli_credentials * creds = NULL ;
2013-11-14 21:45:07 +04:00
TALLOC_CTX * dirctx = NULL ;
NTSTATUS status ;
struct cli_state * targetcli = NULL ;
char * dir = NULL ;
char * dir_end = NULL ;
char * mask2 = NULL ;
char * targetpath = NULL ;
char * caclfile = NULL ;
dirctx = talloc_new ( NULL ) ;
if ( ! dirctx ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
cli = cbstate - > cli ;
2021-01-13 16:07:02 +03:00
creds = cbstate - > creds ;
2013-11-14 21:45:07 +04:00
/* Work out the directory. */
dir = talloc_strdup ( dirctx , mask ) ;
if ( ! dir ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
dir_end = strrchr ( dir , DIRSEP_CHAR ) ;
if ( dir_end ! = NULL ) {
* dir_end = ' \0 ' ;
}
if ( ! f - > name | | ! f - > name [ 0 ] ) {
d_printf ( " Empty dir name returned. Possible server misconfiguration. \n " ) ;
status = NT_STATUS_UNSUCCESSFUL ;
goto out ;
}
if ( f - > attr & FILE_ATTRIBUTE_DIRECTORY ) {
struct cacl_callback_state dir_cbstate ;
uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY
| FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN ;
dir_end = NULL ;
/* ignore special '.' & '..' */
2020-10-20 10:07:29 +03:00
if ( ( f - > name = = NULL ) | | ISDOT ( f - > name ) | | ISDOTDOT ( f - > name ) ) {
2013-11-14 21:45:07 +04:00
status = NT_STATUS_OK ;
goto out ;
}
mask2 = build_dirname ( dirctx , mask , dir , f - > name ) ;
if ( mask2 = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
/* check for dfs */
2022-09-02 21:46:08 +03:00
status = cli_resolve_path ( dirctx , " " , creds , cli ,
2013-11-14 21:45:07 +04:00
mask2 , & targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
/*
* prepare path to caclfile , remove any existing wildcard
* chars and convert path separators .
*/
caclfile = talloc_strdup ( dirctx , targetpath ) ;
if ( ! caclfile ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
dir_end = strrchr ( caclfile , ' * ' ) ;
if ( dir_end ! = NULL ) {
* dir_end = ' \0 ' ;
}
string_replace ( caclfile , ' / ' , ' \\ ' ) ;
/*
* make directory specific copy of cbstate here
* ( for this directory level ) to be available as
* the parent cbstate for the children of this directory .
* Note : cbstate is overwritten for the current file being
* processed .
*/
dir_cbstate = * cbstate ;
dir_cbstate . cli = targetcli ;
/*
* propagate any inherited ace from our parent
*/
status = propagate_inherited_aces ( caclfile , & dir_cbstate ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
/*
* get inheritable ace ( s ) for this dir / container
* that will be propagated to its children
*/
status = get_inheritable_aces ( dirctx , caclfile ,
& dir_cbstate ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
/*
* ensure cacl_set_cb gets called for children
* of this directory ( targetpath )
*/
status = cli_list ( targetcli , targetpath ,
attribute , cacl_set_cb ,
( void * ) & dir_cbstate ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
} else {
/*
* build full path to caclfile and replace ' / ' with ' \ ' so
* other utility functions can deal with it
*/
targetpath = talloc_asprintf ( dirctx , " %s/%s " , dir , f - > name ) ;
if ( ! targetpath ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
string_replace ( targetpath , ' / ' , ' \\ ' ) ;
/* attempt to propagate any inherited ace to file caclfile */
status = propagate_inherited_aces ( targetpath , cbstate ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
}
status = NT_STATUS_OK ;
out :
if ( ! NT_STATUS_IS_OK ( status ) ) {
d_printf ( " error %s: processing %s \n " ,
nt_errstr ( status ) ,
targetpath ) ;
}
TALLOC_FREE ( dirctx ) ;
return status ;
}
/*
2023-07-18 12:36:49 +03:00
* Wrapper around cl_list to descend the directory tree pointed to by ' filename ' ,
2013-11-14 21:45:07 +04:00
* helper callback function ' cacl_set_cb ' handles the child elements processed
* by cli_list .
*/
static int inheritance_cacl_set ( char * filename ,
struct cacl_callback_state * cbstate )
{
int result ;
NTSTATUS ntstatus ;
int fileattr ;
char * mask = NULL ;
struct cli_state * cli = cbstate - > cli ;
TALLOC_CTX * ctx = NULL ;
bool isdirectory = false ;
uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN ;
ctx = talloc_init ( " inherit_set " ) ;
if ( ctx = = NULL ) {
d_printf ( " out of memory \n " ) ;
result = EXIT_FAILED ;
goto out ;
}
/* ensure we have a filename that starts with '\' */
if ( ! filename | | * filename ! = DIRSEP_CHAR ) {
/* illegal or no filename */
result = EXIT_FAILED ;
d_printf ( " illegal or missing name '%s' \n " , filename ) ;
goto out ;
}
fileattr = get_fileinfo ( cli , filename ) ;
isdirectory = ( fileattr & FILE_ATTRIBUTE_DIRECTORY )
= = FILE_ATTRIBUTE_DIRECTORY ;
/*
* if we ' ve got as far as here then we have already evaluated
* the args .
*/
if ( test_args ) {
result = EXIT_OK ;
goto out ;
}
mask = NULL ;
/* make sure we have a trailing '\*' for directory */
if ( ! isdirectory ) {
mask = talloc_strdup ( ctx , filename ) ;
} else if ( strlen ( filename ) > 1 ) {
/*
* if the passed file name doesn ' t have a trailing ' \ '
* append it .
*/
char * name_end = strrchr ( filename , DIRSEP_CHAR ) ;
if ( name_end ! = filename + strlen ( filename ) + 1 ) {
mask = talloc_asprintf ( ctx , " %s \\ * " , filename ) ;
} else {
mask = talloc_strdup ( ctx , filename ) ;
}
} else {
/* filename is a single '\', just append '*' */
mask = talloc_asprintf_append ( mask , " %s* " , filename ) ;
}
if ( ! mask ) {
result = EXIT_FAILED ;
goto out ;
}
/*
* prepare for automatic propagation of the acl passed on the
* cmdline .
*/
2020-07-24 17:32:11 +03:00
2013-11-14 21:45:07 +04:00
ntstatus = prepare_inheritance_propagation ( ctx , filename ,
cbstate ) ;
if ( ! NT_STATUS_IS_OK ( ntstatus ) ) {
d_printf ( " error: %s processing %s \n " ,
nt_errstr ( ntstatus ) , filename ) ;
result = EXIT_FAILED ;
goto out ;
}
2020-07-24 17:32:11 +03:00
2013-11-14 21:45:07 +04:00
result = cacl_set_from_sd ( cli , filename , cbstate - > aclsd ,
cbstate - > mode , cbstate - > numeric ) ;
/*
* strictly speaking it could be considered an error if a file was
2023-07-18 12:36:49 +03:00
* specified with ' - - propagate - inheritance ' . However we really want
2013-11-14 21:45:07 +04:00
* to eventually get rid of ' - - propagate - inheritance ' so we will be
* more forgiving here and instead just exit early .
*/
if ( ! isdirectory | | ( result ! = EXIT_OK ) ) {
goto out ;
}
/* check if there is actually any need to propagate */
if ( cbstate - > acl_no_propagate ) {
goto out ;
}
/* get inheritable attributes this parent container (e.g. filename) */
ntstatus = get_inheritable_aces ( ctx , filename , cbstate ) ;
if ( NT_STATUS_IS_OK ( ntstatus ) ) {
/* process children */
ntstatus = cli_list ( cli , mask , attribute ,
cacl_set_cb ,
( void * ) cbstate ) ;
}
if ( ! NT_STATUS_IS_OK ( ntstatus ) ) {
d_printf ( " error: %s processing %s \n " ,
nt_errstr ( ntstatus ) , filename ) ;
result = EXIT_FAILED ;
goto out ;
}
out :
TALLOC_FREE ( ctx ) ;
return result ;
}
2022-08-12 13:27:58 +03:00
struct diritem {
struct diritem * prev , * next ;
/*
* dirname and targetpath below are sanitized ,
* e . g .
* + start and end with ' \ '
* + have no trailing ' * '
* + all ' / ' have been converted to ' \ '
*/
char * dirname ;
char * targetpath ;
struct cli_state * targetcli ;
} ;
struct save_restore_stats
{
int success ;
int failure ;
} ;
struct dump_context {
struct diritem * list ;
struct cli_credentials * creds ;
struct cli_state * cli ;
struct save_restore_stats * stats ;
int save_fd ;
struct diritem * dir ;
NTSTATUS status ;
} ;
static int write_dacl ( struct dump_context * ctx ,
struct cli_state * cli ,
const char * filename ,
const char * origfname )
{
struct security_descriptor * sd = NULL ;
char * str = NULL ;
const char * output_fmt = " %s \r \n %s \r \n " ;
const char * tmp = NULL ;
char * out_str = NULL ;
uint8_t * dest = NULL ;
ssize_t s_len ;
size_t d_len ;
bool ok ;
int result ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( test_args ) {
return EXIT_OK ;
}
if ( ctx - > save_fd < 0 ) {
DBG_ERR ( " error processing %s no file descriptor \n " , filename ) ;
result = EXIT_FAILED ;
goto out ;
}
sd = get_secdesc ( cli , filename ) ;
if ( sd = = NULL ) {
result = EXIT_FAILED ;
goto out ;
}
sd - > owner_sid = NULL ;
sd - > group_sid = NULL ;
str = sddl_encode ( frame , sd , get_domain_sid ( cli ) ) ;
if ( str = = NULL ) {
DBG_ERR ( " error processing %s couldn't encode DACL \n " , filename ) ;
result = EXIT_FAILED ;
goto out ;
}
/*
* format of icacls save file is
* a line containing the path of the file / dir
* followed by a line containing the sddl format
* of the dacl .
* The format of the strings are null terminated
* 16 - bit Unicode . Each line is terminated by " \r \n "
*/
tmp = origfname ;
/* skip leading '\' */
if ( tmp [ 0 ] = = ' \\ ' ) {
tmp + + ;
}
out_str = talloc_asprintf ( frame , output_fmt , tmp , str ) ;
if ( out_str = = NULL ) {
result = EXIT_FAILED ;
goto out ;
}
s_len = strlen ( out_str ) ;
ok = convert_string_talloc ( out_str ,
CH_UNIX ,
CH_UTF16 ,
out_str ,
s_len , ( void * * ) ( void * ) & dest , & d_len ) ;
if ( ! ok ) {
DBG_ERR ( " error processing %s out of memory \n " , tmp ) ;
result = EXIT_FAILED ;
goto out ;
}
if ( write ( ctx - > save_fd , dest , d_len ) ! = d_len ) {
DBG_ERR ( " error processing %s failed to write to file. \n " , tmp ) ;
result = EXIT_FAILED ;
goto out ;
}
fsync ( ctx - > save_fd ) ;
result = EXIT_OK ;
ctx - > stats - > success + = 1 ;
fprintf ( stdout , " Successfully processed file: %s \n " , tmp ) ;
out :
TALLOC_FREE ( frame ) ;
if ( result ! = EXIT_OK ) {
ctx - > stats - > failure + = 1 ;
}
return result ;
}
/*
* Sanitize directory name .
* Given a directory name ' dir ' ensure it ;
* o starts with ' \ '
* o ends with ' \ '
* o doesn ' t end with trailing ' * '
* o ensure all ' / ' are converted to ' \ '
*/
static char * sanitize_dirname ( TALLOC_CTX * ctx ,
const char * dir )
{
char * mask = NULL ;
char * name_end = NULL ;
mask = talloc_strdup ( ctx , dir ) ;
name_end = strrchr ( mask , ' * ' ) ;
if ( name_end ) {
* name_end = ' \0 ' ;
}
name_end = strrchr ( mask , DIRSEP_CHAR ) ;
if ( strlen ( mask ) > 0 & & name_end ! = mask + ( strlen ( mask ) - 1 ) ) {
mask = talloc_asprintf ( ctx , " %s \\ " , mask ) ;
}
string_replace ( mask , ' / ' , ' \\ ' ) ;
return mask ;
}
/*
* Process each entry ( child ) of a directory .
* Each entry , regardless of whether it is itself a file or directory
* has it ' s dacl written to the restore / save file .
* Each directory is saved to context - > list ( for further processing )
* write_dacl will update the stats ( success / fail )
*/
static NTSTATUS cacl_dump_dacl_cb ( struct file_info * f ,
const char * mask , void * state )
{
struct dump_context * ctx = talloc_get_type_abort ( state ,
struct dump_context ) ;
NTSTATUS status ;
char * mask2 = NULL ;
char * targetpath = NULL ;
char * unresolved = NULL ;
/*
* if we have already encountered an error
* bail out
*/
if ( ! NT_STATUS_IS_OK ( ctx - > status ) ) {
return ctx - > status ;
}
if ( ! f - > name | | ! f - > name [ 0 ] ) {
DBG_ERR ( " Empty dir name returned. Possible server "
" misconfiguration. \n " ) ;
status = NT_STATUS_UNSUCCESSFUL ;
goto out ;
}
mask2 = sanitize_dirname ( ctx , mask ) ;
if ( ! mask2 ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
if ( f - > attr & FILE_ATTRIBUTE_DIRECTORY ) {
struct diritem * item = NULL ;
/* ignore special '.' & '..' */
if ( ( f - > name = = NULL ) | | ISDOT ( f - > name ) | | ISDOTDOT ( f - > name ) ) {
status = NT_STATUS_OK ;
goto out ;
}
/* Work out the directory. */
unresolved = sanitize_dirname ( ctx , ctx - > dir - > dirname ) ;
if ( ! unresolved ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
unresolved = talloc_asprintf ( ctx , " %s%s " , unresolved , f - > name ) ;
if ( unresolved = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
item = talloc_zero ( ctx , struct diritem ) ;
if ( item = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
item - > dirname = unresolved ;
mask2 = talloc_asprintf ( ctx , " %s%s " , mask2 , f - > name ) ;
if ( ! mask2 ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
status = cli_resolve_path ( ctx , " " , ctx - > creds , ctx - > cli ,
mask2 , & item - > targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " error failed to resolve: %s \n " ,
nt_errstr ( status ) ) ;
goto out ;
}
item - > targetpath = sanitize_dirname ( ctx , targetpath ) ;
if ( ! item - > targetpath ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
if ( write_dacl ( ctx ,
item - > targetcli ,
item - > targetpath , unresolved ) ! = EXIT_OK ) {
status = NT_STATUS_UNSUCCESSFUL ;
/*
* cli_list happily ignores error encountered
* when processing the callback so we need
* to save any error status encountered while
* processing directories ( so we can stop recursing
* those as soon as possible ) .
* Changing the current behaviour of the callback
* handling by cli_list would be I think be too
* risky .
*/
ctx - > status = status ;
goto out ;
}
DLIST_ADD_END ( ctx - > list , item ) ;
} else {
unresolved = sanitize_dirname ( ctx , ctx - > dir - > dirname ) ;
if ( ! unresolved ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
unresolved = talloc_asprintf ( ctx , " %s%s " , unresolved , f - > name ) ;
if ( ! unresolved ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
/*
* build full path to the file and replace ' / ' with ' \ ' so
* other utility functions can deal with it
*/
targetpath = talloc_asprintf ( ctx , " %s%s " , mask2 , f - > name ) ;
if ( ! targetpath ) {
status = NT_STATUS_NO_MEMORY ;
goto out ;
}
if ( write_dacl ( ctx ,
ctx - > dir - > targetcli ,
targetpath , unresolved ) ! = EXIT_OK ) {
status = NT_STATUS_UNSUCCESSFUL ;
/*
* cli_list happily ignores error encountered
* when processing the callback so we need
* to save any error status encountered while
* processing directories ( so we can stop recursing
* those as soon as possible ) .
* Changing the current behaviour of the callback
* handling by cli_list would be I think be too
* risky .
*/
ctx - > status = status ;
goto out ;
}
}
status = NT_STATUS_OK ;
out :
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " error %s: processing %s \n " ,
nt_errstr ( status ) , targetpath ) ;
}
return status ;
}
/*
* dump_ctx contains a list of directories to be processed
* + each directory ' dir ' is scanned by cli_list , the cli_list
* callback ' cacl_dump_dacl_cb ' writes out the dacl of each
* child of ' dir ' ( regardless of whether it is a dir or file )
* to the restore / save file . Additionally any directories encountered
* are returned in the passed in dump_ctx - > list member
* + the directory list returned from cli_list is passed and processed
* by recursively calling dump_dacl_dirtree
*
*/
static int dump_dacl_dirtree ( struct dump_context * dump_ctx )
{
struct diritem * item = NULL ;
struct dump_context * new_dump_ctx = NULL ;
int result ;
for ( item = dump_ctx - > list ; item ; item = item - > next ) {
uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY
| FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ;
NTSTATUS status ;
char * mask = NULL ;
new_dump_ctx = talloc_zero ( dump_ctx , struct dump_context ) ;
if ( new_dump_ctx = = NULL ) {
DBG_ERR ( " out of memory \n " ) ;
result = EXIT_FAILED ;
goto out ;
}
if ( item - > targetcli = = NULL ) {
status = cli_resolve_path ( new_dump_ctx ,
" " ,
dump_ctx - > creds ,
dump_ctx - > cli ,
item - > dirname ,
& item - > targetcli ,
& item - > targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " failed to resolve path %s "
" error: %s \n " ,
item - > dirname , nt_errstr ( status ) ) ;
result = EXIT_FAILED ;
goto out ;
}
}
new_dump_ctx - > creds = dump_ctx - > creds ;
new_dump_ctx - > save_fd = dump_ctx - > save_fd ;
new_dump_ctx - > stats = dump_ctx - > stats ;
new_dump_ctx - > dir = item ;
new_dump_ctx - > cli = item - > targetcli ;
mask = talloc_asprintf ( new_dump_ctx , " %s* " ,
new_dump_ctx - > dir - > targetpath ) ;
status = cli_list ( new_dump_ctx - > dir - > targetcli ,
mask ,
attribute , cacl_dump_dacl_cb , new_dump_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) | |
! NT_STATUS_IS_OK ( new_dump_ctx - > status ) ) {
NTSTATUS tmpstatus ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* cli_list failed for some reason
* so we need to update the failure stat
*/
new_dump_ctx - > stats - > failure + = 1 ;
tmpstatus = status ;
} else {
/* cacl_dump_dacl_cb should have updated stat */
tmpstatus = new_dump_ctx - > status ;
}
DBG_ERR ( " error %s: processing %s \n " ,
nt_errstr ( tmpstatus ) , item - > dirname ) ;
result = EXIT_FAILED ;
goto out ;
}
result = dump_dacl_dirtree ( new_dump_ctx ) ;
if ( result ! = EXIT_OK ) {
goto out ;
}
}
result = EXIT_OK ;
out :
TALLOC_FREE ( new_dump_ctx ) ;
return result ;
}
static int cacl_dump_dacl ( struct cli_state * cli ,
struct cli_credentials * creds ,
char * filename )
{
int fileattr ;
char * mask = NULL ;
TALLOC_CTX * ctx = NULL ;
bool isdirectory = false ;
int result ;
struct dump_context * dump_ctx = NULL ;
struct save_restore_stats stats = { 0 } ;
struct diritem * item = NULL ;
struct cli_state * targetcli = NULL ;
char * targetpath = NULL ;
NTSTATUS status ;
ctx = talloc_init ( " cacl_dump " ) ;
if ( ctx = = NULL ) {
DBG_ERR ( " out of memory \n " ) ;
result = EXIT_FAILED ;
goto out ;
}
dump_ctx = talloc_zero ( ctx , struct dump_context ) ;
if ( dump_ctx = = NULL ) {
DBG_ERR ( " out of memory \n " ) ;
result = EXIT_FAILED ;
goto out ;
}
dump_ctx - > save_fd = open ( save_file ,
O_CREAT | O_RDWR | O_TRUNC , S_IRUSR | S_IWUSR ) ;
if ( dump_ctx - > save_fd < 0 ) {
result = EXIT_FAILED ;
goto out ;
}
dump_ctx - > creds = creds ;
dump_ctx - > cli = cli ;
dump_ctx - > stats = & stats ;
/* ensure we have a filename that starts with '\' */
if ( ! filename | | * filename ! = DIRSEP_CHAR ) {
/* illegal or no filename */
result = EXIT_FAILED ;
DBG_ERR ( " illegal or missing name '%s' \n " , filename ) ;
goto out ;
}
status = cli_resolve_path ( dump_ctx , " " ,
dump_ctx - > creds ,
dump_ctx - > cli ,
filename , & targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " failed resolve %s \n " , filename ) ;
result = EXIT_FAILED ;
goto out ;
}
fileattr = get_fileinfo ( targetcli , targetpath ) ;
isdirectory = ( fileattr & FILE_ATTRIBUTE_DIRECTORY )
= = FILE_ATTRIBUTE_DIRECTORY ;
/*
* if we ' ve got as far as here then we have already evaluated
* the args .
*/
if ( test_args ) {
result = EXIT_OK ;
goto out ;
}
mask = NULL ;
/* make sure we have a trailing '\*' for directory */
if ( ! isdirectory ) {
mask = talloc_strdup ( ctx , filename ) ;
} else if ( strlen ( filename ) > 1 ) {
mask = sanitize_dirname ( ctx , filename ) ;
} else {
/* filename is a single '\' */
mask = talloc_strdup ( ctx , filename ) ;
}
if ( ! mask ) {
result = EXIT_FAILED ;
goto out ;
}
write_dacl ( dump_ctx , targetcli , targetpath , filename ) ;
if ( isdirectory & & recurse ) {
item = talloc_zero ( dump_ctx , struct diritem ) ;
if ( ! item ) {
result = EXIT_FAILED ;
goto out ;
}
item - > dirname = mask ;
DLIST_ADD_END ( dump_ctx - > list , item ) ;
dump_dacl_dirtree ( dump_ctx ) ;
}
fprintf ( stdout , " Successfully processed %d files: "
" Failed processing %d files \n " ,
dump_ctx - > stats - > success , dump_ctx - > stats - > failure ) ;
result = EXIT_OK ;
out :
if ( dump_ctx & & dump_ctx - > save_fd ) {
close ( dump_ctx - > save_fd ) ;
}
TALLOC_FREE ( ctx ) ;
return result ;
}
2023-11-14 12:12:01 +03:00
struct restore_dacl {
const char * path ;
struct security_descriptor * sd ;
} ;
/*
* Restore dacls from ' savefile ' produced by
* ' icacls name / save ' or ' smbcacls - - save '
*/
static int cacl_restore ( struct cli_state * cli ,
struct cli_credentials * creds ,
bool numeric , const char * restorefile )
{
int restore_fd ;
int result ;
struct save_restore_stats stats = { 0 } ;
char * * lines = NULL ;
char * content = NULL ;
char * convert_content = NULL ;
size_t content_size ;
struct restore_dacl * entries = NULL ;
int numlines , i = 0 ;
bool ok ;
struct dom_sid * sid = NULL ;
if ( restorefile = = NULL ) {
DBG_ERR ( " No restore file specified \n " ) ;
result = EXIT_FAILED ;
goto out ;
}
if ( test_args ) {
result = EXIT_OK ;
goto out ;
}
restore_fd = open ( restorefile , O_RDONLY , S_IRUSR | S_IWUSR ) ;
if ( restore_fd < 0 ) {
DBG_ERR ( " Failed to open %s. \n " , restorefile ) ;
result = EXIT_FAILED ;
goto out ;
}
content = fd_load ( restore_fd , & content_size , 0 , talloc_tos ( ) ) ;
close ( restore_fd ) ;
if ( content = = NULL ) {
DBG_ERR ( " Failed to load content from %s. \n " , restorefile ) ;
result = EXIT_FAILED ;
goto out ;
}
ok = convert_string_talloc ( talloc_tos ( ) ,
CH_UTF16 ,
CH_UNIX ,
content ,
utf16_len_n ( content , content_size ) ,
( void * * ) ( void * ) & convert_content ,
& content_size ) ;
TALLOC_FREE ( content ) ;
if ( ! ok ) {
DBG_ERR ( " Failed to convert content from %s "
" to CH_UNIX. \n " , restorefile ) ;
result = EXIT_FAILED ;
goto out ;
}
lines = file_lines_parse ( convert_content ,
content_size , & numlines , talloc_tos ( ) ) ;
if ( lines = = NULL ) {
DBG_ERR ( " Failed to parse lines from content of %s. " ,
restorefile ) ;
result = EXIT_FAILED ;
goto out ;
}
entries = talloc_zero_array ( lines , struct restore_dacl , numlines / 2 ) ;
if ( entries = = NULL ) {
DBG_ERR ( " error processing %s, out of memory \n " , restorefile ) ;
result = EXIT_FAILED ;
goto out ;
}
sid = get_domain_sid ( cli ) ;
while ( i < numlines ) {
int index = i / 2 ;
int first_line = ( i % 2 ) = = 0 ;
if ( first_line ) {
char * tmp = NULL ;
tmp = lines [ i ] ;
/* line can be blank if root of share */
if ( strlen ( tmp ) = = 0 ) {
entries [ index ] . path = talloc_strdup ( lines ,
" \\ " ) ;
} else {
entries [ index ] . path = lines [ i ] ;
}
} else {
entries [ index ] . sd = sddl_decode ( lines , lines [ i ] , sid ) ;
entries [ index ] . sd - > type | =
SEC_DESC_DACL_AUTO_INHERIT_REQ ;
entries [ index ] . sd - > type | = SEC_DESC_SACL_AUTO_INHERITED ;
}
i + + ;
}
for ( i = 0 ; i < ( numlines / 2 ) ; i + + ) {
int mode = SMB_ACL_SET ;
int set_result ;
struct cli_state * targetcli = NULL ;
char * targetpath = NULL ;
NTSTATUS status ;
/* check for dfs */
status = cli_resolve_path ( talloc_tos ( ) ,
" " ,
creds ,
cli ,
entries [ i ] . path ,
& targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Error failed to process file: %s \n " ,
entries [ i ] . path ) ;
stats . failure + = 1 ;
continue ;
}
set_result = cacl_set_from_sd ( targetcli ,
targetpath ,
entries [ i ] . sd , mode , numeric ) ;
if ( set_result = = EXIT_OK ) {
printf ( " Successfully processed file: %s \n " ,
entries [ i ] . path ) ;
stats . success + = 1 ;
} else {
printf ( " Error failed to process file: %s \n " ,
entries [ i ] . path ) ;
stats . failure + = 1 ;
}
}
result = EXIT_OK ;
out :
TALLOC_FREE ( lines ) ;
fprintf ( stdout , " Successfully processed %d files: "
" Failed processing %d files \n " , stats . success , stats . failure ) ;
return result ;
}
2000-12-03 05:19:27 +03:00
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-26 23:16:26 +04:00
int main ( int argc , char * argv [ ] )
2000-12-03 05:19:27 +03:00
{
2014-02-26 23:16:26 +04:00
const char * * argv_const = discard_const_p ( const char * , argv ) ;
2000-12-03 05:19:27 +03:00
char * share ;
int opt ;
2001-06-19 04:44:23 +04:00
enum acl_mode mode = SMB_ACL_SET ;
2003-04-14 07:59:04 +04:00
static char * the_acl = NULL ;
2000-12-16 03:08:05 +03:00
enum chown_mode change_mode = REQUEST_NONE ;
2000-12-22 02:36:25 +03:00
int result ;
2007-12-04 05:48:41 +03:00
char * path ;
char * filename = NULL ;
2003-04-14 07:59:04 +04:00
poptContext pc ;
2015-04-24 18:31:41 +03:00
/* numeric is set when the user wants numeric SIDs and ACEs rather
than going via LSA calls to resolve them */
2016-01-20 10:34:26 +03:00
int numeric = 0 ;
2020-06-07 22:09:59 +03:00
struct cli_state * targetcli = NULL ;
2020-08-18 18:42:25 +03:00
struct cli_credentials * creds = NULL ;
2020-06-07 22:09:59 +03:00
char * targetfile = NULL ;
NTSTATUS status ;
2021-01-13 16:04:04 +03:00
bool ok ;
2023-08-07 07:25:28 +03:00
struct loadparm_context * lp_ctx = NULL ;
2015-04-24 18:31:41 +03:00
2003-04-14 07:59:04 +04:00
struct poptOption long_options [ ] = {
POPT_AUTOHELP
2019-01-11 17:26:38 +03:00
{
. longName = " delete " ,
. shortName = ' D ' ,
. argInfo = POPT_ARG_STRING ,
. arg = NULL ,
. val = ' D ' ,
. descrip = " Delete an acl " ,
. argDescrip = " ACL " ,
2012-11-30 17:36:07 +04:00
} ,
2019-01-11 17:26:38 +03:00
{
. longName = " modify " ,
. shortName = ' M ' ,
. argInfo = POPT_ARG_STRING ,
. arg = NULL ,
. val = ' M ' ,
. descrip = " Modify an acl " ,
. argDescrip = " ACL " ,
} ,
{
. longName = " add " ,
. shortName = ' a ' ,
. argInfo = POPT_ARG_STRING ,
. arg = NULL ,
. val = ' a ' ,
. descrip = " Add an acl " ,
. argDescrip = " ACL " ,
} ,
{
. longName = " set " ,
. shortName = ' S ' ,
. argInfo = POPT_ARG_STRING ,
. arg = NULL ,
. val = ' S ' ,
. descrip = " Set acls " ,
. argDescrip = " ACLS " ,
} ,
{
. longName = " chown " ,
. shortName = ' C ' ,
. argInfo = POPT_ARG_STRING ,
. arg = NULL ,
. val = ' C ' ,
. descrip = " Change ownership of a file " ,
. argDescrip = " USERNAME " ,
} ,
{
. longName = " chgrp " ,
. shortName = ' G ' ,
. argInfo = POPT_ARG_STRING ,
. arg = NULL ,
. val = ' G ' ,
. descrip = " Change group ownership of a file " ,
. argDescrip = " GROUPNAME " ,
} ,
{
. longName = " inherit " ,
. shortName = ' I ' ,
. argInfo = POPT_ARG_STRING ,
. arg = NULL ,
. val = ' I ' ,
. descrip = " Inherit allow|remove|copy " ,
} ,
2013-11-14 21:45:07 +04:00
{
. longName = " propagate-inheritance " ,
. shortName = 0 ,
. argInfo = POPT_ARG_NONE ,
. arg = & inheritance ,
. val = 1 ,
. descrip = " Supports propagation of inheritable ACE(s) when used in conjunction with add, delete, set or modify " ,
} ,
2022-08-11 17:26:01 +03:00
{
. longName = " save " ,
. shortName = 0 ,
. argInfo = POPT_ARG_STRING ,
. arg = & save_file ,
. val = 1 ,
. descrip = " stores the DACLs in sddl format of the "
" specified file or folder for later use "
" with restore. SACLS, owner or integrity "
" labels are not stored " ,
} ,
{
. longName = " restore " ,
. shortName = 0 ,
. argInfo = POPT_ARG_STRING ,
. arg = & restore_file ,
. val = 1 ,
. descrip = " applies the stored DACLS to files in "
" directory. " ,
} ,
2022-08-17 17:39:19 +03:00
{
. longName = " recurse " ,
. shortName = 0 ,
. argInfo = POPT_ARG_NONE ,
. arg = & recurse ,
. val = 1 ,
. descrip = " indicates the operation is performed "
" on directory and all files/directories "
" below. (only applies to save option) " ,
} ,
2019-01-11 17:26:38 +03:00
{
. longName = " numeric " ,
. shortName = 0 ,
. argInfo = POPT_ARG_NONE ,
. arg = & numeric ,
. val = 1 ,
. descrip = " Don't resolve sids or masks to names " ,
} ,
{
. longName = " sddl " ,
. shortName = 0 ,
. argInfo = POPT_ARG_NONE ,
. arg = & sddl ,
. val = 1 ,
. descrip = " Output and input acls in sddl format " ,
} ,
{
. longName = " query-security-info " ,
. shortName = 0 ,
. argInfo = POPT_ARG_INT ,
. arg = & query_sec_info ,
. val = 1 ,
. descrip = " The security-info flags for queries "
} ,
{
. longName = " set-security-info " ,
. shortName = 0 ,
. argInfo = POPT_ARG_INT ,
. arg = & set_sec_info ,
. val = 1 ,
. descrip = " The security-info flags for modifications "
} ,
{
. longName = " test-args " ,
. shortName = ' t ' ,
. argInfo = POPT_ARG_NONE ,
. arg = & test_args ,
. val = 1 ,
. descrip = " Test arguments "
} ,
{
. longName = " domain-sid " ,
. shortName = 0 ,
. argInfo = POPT_ARG_STRING ,
. arg = & domain_sid ,
. val = 0 ,
. descrip = " Domain SID for sddl " ,
. argDescrip = " SID " } ,
2019-02-27 18:45:07 +03:00
{
. longName = " maximum-access " ,
. shortName = ' x ' ,
. argInfo = POPT_ARG_NONE ,
. arg = NULL ,
. val = ' x ' ,
2019-10-23 10:56:51 +03:00
. descrip = " Query maximum permissions " ,
2019-02-27 18:45:07 +03:00
} ,
2003-04-14 07:59:04 +04:00
POPT_COMMON_SAMBA
2008-07-08 02:51:08 +04:00
POPT_COMMON_CONNECTION
2003-04-14 07:59:04 +04:00
POPT_COMMON_CREDENTIALS
2021-01-13 16:04:04 +03:00
POPT_LEGACY_S3
POPT_COMMON_VERSION
2008-07-08 02:51:08 +04:00
POPT_TABLEEND
2003-04-14 07:59:04 +04:00
} ;
2000-12-03 05:19:27 +03:00
2002-07-15 14:35:28 +04:00
struct cli_state * cli ;
2007-11-16 01:19:52 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2007-12-04 05:48:41 +03:00
const char * owner_username = " " ;
char * server ;
2002-07-15 14:35:28 +04:00
2015-03-21 22:00:06 +03:00
smb_init_locale ( ) ;
2005-12-29 01:48:54 +03:00
2021-01-13 16:04:04 +03:00
ok = samba_cmdline_init ( frame ,
SAMBA_CMDLINE_CONFIG_CLIENT ,
false /* require_smbconf */ ) ;
if ( ! ok ) {
DBG_ERR ( " Failed to init cmdline parser! \n " ) ;
TALLOC_FREE ( frame ) ;
exit ( 1 ) ;
}
2023-08-07 07:25:28 +03:00
lp_ctx = samba_cmdline_get_lp_ctx ( ) ;
2004-11-18 16:29:10 +03:00
/* set default debug level to 1 regardless of what smb.conf sets */
2023-08-07 07:25:28 +03:00
lpcfg_set_cmdline ( lp_ctx , " log level " , " 1 " ) ;
2000-12-03 05:19:27 +03:00
2004-09-15 17:57:33 +04:00
setlinebuf ( stdout ) ;
2000-12-03 05:19:27 +03:00
2021-01-13 16:04:04 +03:00
pc = samba_popt_get_context ( getprogname ( ) ,
argc ,
argv_const ,
long_options ,
0 ) ;
if ( pc = = NULL ) {
DBG_ERR ( " Failed to setup popt context! \n " ) ;
TALLOC_FREE ( frame ) ;
exit ( 1 ) ;
}
2007-12-04 05:48:41 +03:00
2005-11-04 20:40:35 +03:00
poptSetOtherOptionHelp ( pc , " //server1/share1 filename \n ACLs look like: "
" 'ACL:user:[ALLOWED|DENIED]/flags/permissions' " ) ;
2000-12-03 05:19:27 +03:00
2003-04-14 07:59:04 +04:00
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
2000-12-03 05:19:27 +03:00
switch ( opt ) {
2000-12-03 11:35:11 +03:00
case ' S ' :
2003-04-14 07:59:04 +04:00
the_acl = smb_xstrdup ( poptGetOptArg ( pc ) ) ;
2001-04-11 05:34:37 +04:00
mode = SMB_ACL_SET ;
2000-12-03 15:41:28 +03:00
break ;
case ' D ' :
2003-04-14 07:59:04 +04:00
the_acl = smb_xstrdup ( poptGetOptArg ( pc ) ) ;
2001-04-11 05:34:37 +04:00
mode = SMB_ACL_DELETE ;
2000-12-03 15:41:28 +03:00
break ;
case ' M ' :
2003-04-14 07:59:04 +04:00
the_acl = smb_xstrdup ( poptGetOptArg ( pc ) ) ;
2001-04-11 05:34:37 +04:00
mode = SMB_ACL_MODIFY ;
2000-12-03 15:41:28 +03:00
break ;
2003-09-01 14:43:21 +04:00
case ' a ' :
2003-04-14 07:59:04 +04:00
the_acl = smb_xstrdup ( poptGetOptArg ( pc ) ) ;
2001-04-11 05:34:37 +04:00
mode = SMB_ACL_ADD ;
2000-12-03 10:36:15 +03:00
break ;
2000-12-03 11:35:11 +03:00
2000-12-16 03:08:05 +03:00
case ' C ' :
2007-12-04 05:48:41 +03:00
owner_username = poptGetOptArg ( pc ) ;
2000-12-16 03:08:05 +03:00
change_mode = REQUEST_CHOWN ;
break ;
case ' G ' :
2007-12-04 05:48:41 +03:00
owner_username = poptGetOptArg ( pc ) ;
2000-12-16 03:08:05 +03:00
change_mode = REQUEST_CHGRP ;
break ;
2010-05-06 09:35:02 +04:00
case ' I ' :
owner_username = poptGetOptArg ( pc ) ;
change_mode = REQUEST_INHERIT ;
break ;
2013-08-08 22:43:16 +04:00
case ' m ' :
2023-08-07 07:25:28 +03:00
lpcfg_set_cmdline ( lp_ctx , " client max protocol " , poptGetOptArg ( pc ) ) ;
2013-08-08 22:43:16 +04:00
break ;
2019-02-27 18:45:07 +03:00
case ' x ' :
want_mxac = true ;
break ;
2021-09-10 08:11:43 +03:00
case POPT_ERROR_BADOPT :
fprintf ( stderr , " \n Invalid option %s: %s \n \n " ,
poptBadOption ( pc , 0 ) , poptStrerror ( opt ) ) ;
poptPrintUsage ( pc , stderr , 0 ) ;
exit ( 1 ) ;
2000-12-03 05:19:27 +03:00
}
}
2013-11-14 21:45:07 +04:00
if ( inheritance & & ! the_acl ) {
poptPrintUsage ( pc , stderr , 0 ) ;
return - 1 ;
}
2000-12-03 05:19:27 +03:00
2007-12-04 05:48:41 +03:00
if ( ! poptPeekArg ( pc ) ) {
2003-04-14 07:59:04 +04:00
poptPrintUsage ( pc , stderr , 0 ) ;
return - 1 ;
2000-12-07 09:05:57 +03:00
}
2007-12-04 05:48:41 +03:00
path = talloc_strdup ( frame , poptGetArg ( pc ) ) ;
if ( ! path ) {
2003-04-14 07:59:04 +04:00
return - 1 ;
}
2000-12-03 05:19:27 +03:00
2023-01-10 14:25:35 +03:00
if ( strncmp ( path , " \\ \\ " , 2 ) & & strncmp ( path , " // " , 2 ) ) {
printf ( " Invalid argument: %s \n " , path ) ;
return - 1 ;
}
2007-12-04 05:48:41 +03:00
if ( ! poptPeekArg ( pc ) ) {
poptPrintUsage ( pc , stderr , 0 ) ;
return - 1 ;
}
filename = talloc_strdup ( frame , poptGetArg ( pc ) ) ;
if ( ! filename ) {
return - 1 ;
}
2000-12-21 03:12:59 +03:00
2012-10-30 00:12:14 +04:00
poptFreeContext ( pc ) ;
2021-01-13 16:04:04 +03:00
samba_cmdline_burn ( argc , argv ) ;
2012-10-30 00:12:14 +04:00
2007-12-04 05:48:41 +03:00
string_replace ( path , ' / ' , ' \\ ' ) ;
server = talloc_strdup ( frame , path + 2 ) ;
if ( ! server ) {
return - 1 ;
}
2002-07-15 14:35:28 +04:00
share = strchr_m ( server , ' \\ ' ) ;
2019-05-08 18:12:12 +03:00
if ( share = = NULL ) {
printf ( " Invalid argument \n " ) ;
2007-05-19 08:23:04 +04:00
return - 1 ;
2002-07-15 14:35:28 +04:00
}
* share = 0 ;
share + + ;
2021-01-13 16:04:04 +03:00
creds = samba_cmdline_get_creds ( ) ;
2021-01-13 16:00:56 +03:00
2013-11-14 21:45:07 +04:00
/* Make connection to server */
2000-12-07 09:05:57 +03:00
if ( ! test_args ) {
2021-01-13 16:00:56 +03:00
cli = connect_one ( creds , server , share ) ;
2001-02-28 04:38:12 +03:00
if ( ! cli ) {
exit ( EXIT_FAILED ) ;
}
2002-07-15 14:35:28 +04:00
} else {
exit ( 0 ) ;
2000-12-07 09:05:57 +03:00
}
2000-12-03 05:19:27 +03:00
2007-12-04 05:48:41 +03:00
string_replace ( filename , ' / ' , ' \\ ' ) ;
2001-02-22 09:22:20 +03:00
if ( filename [ 0 ] ! = ' \\ ' ) {
2007-12-04 05:48:41 +03:00
filename = talloc_asprintf ( frame ,
" \\ %s " ,
filename ) ;
if ( ! filename ) {
return - 1 ;
}
2000-12-21 08:28:39 +03:00
}
2022-09-02 21:46:08 +03:00
status = cli_resolve_path ( frame ,
2020-06-07 22:09:59 +03:00
" " ,
2020-08-18 18:42:25 +03:00
creds ,
2020-06-07 22:09:59 +03:00
cli ,
filename ,
& targetcli ,
& targetfile ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " cli_resolve_path failed for %s! (%s) \n " , filename , nt_errstr ( status ) ) ) ;
return - 1 ;
}
2000-12-21 03:12:59 +03:00
/* Perform requested action */
2010-05-06 09:35:02 +04:00
if ( change_mode = = REQUEST_INHERIT ) {
2020-06-07 22:09:59 +03:00
result = inherit ( targetcli , targetfile , owner_username ) ;
2010-05-06 09:35:02 +04:00
} else if ( change_mode ! = REQUEST_NONE ) {
2020-06-07 22:09:59 +03:00
result = owner_set ( targetcli , change_mode , targetfile , owner_username ) ;
2000-12-16 03:08:05 +03:00
} else if ( the_acl ) {
2013-11-14 21:45:07 +04:00
if ( inheritance ) {
2020-10-20 10:24:06 +03:00
struct cacl_callback_state cbstate = {
2021-01-13 16:07:02 +03:00
. creds = creds ,
2020-10-20 10:24:06 +03:00
. cli = targetcli ,
. mode = mode ,
. the_acl = the_acl ,
. numeric = numeric ,
} ;
2013-11-14 21:45:07 +04:00
result = inheritance_cacl_set ( targetfile , & cbstate ) ;
} else {
result = cacl_set ( targetcli ,
targetfile ,
the_acl ,
mode ,
numeric ) ;
}
2000-12-03 10:36:15 +03:00
} else {
2023-11-14 12:12:01 +03:00
if ( save_file | | restore_file ) {
2022-08-12 13:27:58 +03:00
sddl = 1 ;
2023-11-14 12:12:01 +03:00
if ( save_file ) {
result = cacl_dump_dacl ( cli , creds , filename ) ;
} else {
result = cacl_restore ( targetcli ,
creds ,
numeric , restore_file ) ;
}
2022-08-12 13:27:58 +03:00
} else {
result = cacl_dump ( targetcli , targetfile , numeric ) ;
}
2000-12-03 10:36:15 +03:00
}
2000-12-03 05:19:27 +03:00
2023-10-24 13:00:46 +03:00
gfree_all ( ) ;
2007-10-10 18:57:34 +04:00
TALLOC_FREE ( frame ) ;
2001-02-28 04:38:12 +03:00
2000-12-22 02:36:25 +03:00
return result ;
2000-12-03 05:19:27 +03:00
}