2000-12-03 05:19:27 +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
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
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 .
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 .
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"
2010-08-05 12:49:53 +04:00
# include "popt_common.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-08-26 17:48:50 +04:00
# include "../libcli/security/dom_sid.h"
2000-12-03 05:19:27 +03:00
2009-08-12 01:35:48 +04:00
extern bool AllowDebugChange ;
2008-10-15 03:09:17 +04:00
static int test_args ;
2000-12-03 05:19:27 +03:00
2001-02-22 06:40:01 +03:00
# define CREATE_ACCESS_READ READ_CONTROL_ACCESS
2000-12-03 11:35:11 +03:00
/* numeric is set when the user wants numeric SIDs and ACEs rather
than going via LSA calls to resolve them */
2008-10-15 03:09:17 +04:00
static int numeric ;
2000-12-03 05:19:27 +03:00
2010-03-01 00:20:03 +03:00
static int sddl ;
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
2000-12-04 09:14:28 +03:00
struct perm_value {
2003-01-03 11:28:12 +03:00
const char * perm ;
2000-12-04 09:14:28 +03:00
uint32 mask ;
} ;
/* These values discovered by inspection */
2003-01-03 11:28:12 +03:00
static const struct perm_value special_values [ ] = {
2000-12-04 09:14:28 +03:00
{ " R " , 0x00120089 } ,
{ " W " , 0x00120116 } ,
{ " X " , 0x001200a0 } ,
{ " D " , 0x00010000 } ,
{ " P " , 0x00040000 } ,
{ " O " , 0x00080000 } ,
{ NULL , 0 } ,
} ;
2003-01-03 11:28:12 +03:00
static const struct perm_value standard_values [ ] = {
2000-12-04 09:14:28 +03:00
{ " READ " , 0x001200a9 } ,
{ " CHANGE " , 0x001301bf } ,
{ " FULL " , 0x001f01ff } ,
{ NULL , 0 } ,
} ;
2000-12-03 15:41:28 +03:00
2007-10-10 18:57:34 +04:00
/* Open cli connection and policy handle */
2002-07-15 14:35:28 +04:00
2007-10-10 18:57:34 +04:00
static NTSTATUS cli_lsa_lookup_sid ( struct cli_state * cli ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * sid ,
2007-10-10 18:57:34 +04:00
TALLOC_CTX * mem_ctx ,
enum lsa_SidType * type ,
char * * domain , char * * name )
{
uint16 orig_cnum = cli - > cnum ;
2009-11-13 00:56:33 +03:00
struct rpc_pipe_client * p = NULL ;
2007-10-10 18:57:34 +04:00
struct policy_handle handle ;
NTSTATUS status ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
enum lsa_SidType * types ;
char * * domains ;
char * * names ;
2000-12-14 06:27:53 +03:00
2009-01-26 10:37:13 +03:00
status = cli_tcon_andx ( cli , " IPC$ " , " ????? " , " " , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2007-10-10 18:57:34 +04:00
}
2008-07-20 13:04:31 +04:00
status = cli_rpc_pipe_open_noauth ( cli , & ndr_table_lsarpc . syntax_id ,
& p ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-10-10 18:57:34 +04:00
goto fail ;
}
status = rpccli_lsa_open_policy ( p , talloc_tos ( ) , True ,
GENERIC_EXECUTE_ACCESS , & handle ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
status = rpccli_lsa_lookup_sids ( p , talloc_tos ( ) , & handle , 1 , sid ,
& domains , & names , & types ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2000-12-14 06:27:53 +03:00
2007-10-10 18:57:34 +04:00
* type = types [ 0 ] ;
* domain = talloc_move ( mem_ctx , & domains [ 0 ] ) ;
* name = talloc_move ( mem_ctx , & names [ 0 ] ) ;
status = NT_STATUS_OK ;
fail :
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( p ) ;
2007-10-10 18:57:34 +04:00
cli_tdis ( cli ) ;
cli - > cnum = orig_cnum ;
TALLOC_FREE ( frame ) ;
return status ;
}
static NTSTATUS cli_lsa_lookup_name ( struct cli_state * cli ,
const char * name ,
enum lsa_SidType * type ,
2010-05-21 05:25:01 +04:00
struct dom_sid * sid )
2000-12-14 06:27:53 +03:00
{
2007-10-10 18:57:34 +04:00
uint16 orig_cnum = cli - > cnum ;
struct rpc_pipe_client * p ;
struct policy_handle handle ;
NTSTATUS status ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2010-05-21 05:25:01 +04:00
struct dom_sid * sids ;
2007-10-10 18:57:34 +04:00
enum lsa_SidType * types ;
2009-01-26 10:37:13 +03:00
status = cli_tcon_andx ( cli , " IPC$ " , " ????? " , " " , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2000-12-14 06:27:53 +03:00
}
2008-07-20 13:04:31 +04:00
status = cli_rpc_pipe_open_noauth ( cli , & ndr_table_lsarpc . syntax_id ,
& p ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-10-10 18:57:34 +04:00
goto fail ;
}
2001-01-23 20:33:35 +03:00
2007-10-10 18:57:34 +04:00
status = rpccli_lsa_open_policy ( p , talloc_tos ( ) , True ,
GENERIC_EXECUTE_ACCESS , & handle ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2001-01-23 20:33:35 +03:00
2007-10-10 18:57:34 +04:00
status = rpccli_lsa_lookup_names ( p , talloc_tos ( ) , & handle , 1 , & name ,
NULL , 1 , & sids , & types ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2000-12-14 06:27:53 +03:00
2007-10-10 18:57:34 +04:00
* type = types [ 0 ] ;
* sid = sids [ 0 ] ;
status = NT_STATUS_OK ;
fail :
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( p ) ;
2007-10-10 18:57:34 +04:00
cli_tdis ( cli ) ;
cli - > cnum = orig_cnum ;
TALLOC_FREE ( frame ) ;
return status ;
2000-12-14 06:27:53 +03:00
}
2000-12-03 11:35:11 +03:00
/* convert a SID to a string, either numeric or username/group */
2010-05-21 05:25:01 +04:00
static void SidToString ( struct cli_state * cli , fstring str , const struct dom_sid * sid )
2000-12-03 08:24:16 +03:00
{
2007-10-10 18:57:34 +04:00
char * domain = NULL ;
char * name = NULL ;
enum lsa_SidType type ;
NTSTATUS status ;
2000-12-13 15:53:42 +03:00
2007-12-16 00:47:30 +03:00
sid_to_fstring ( str , sid ) ;
2000-12-13 15:53:42 +03:00
2007-10-10 18:57:34 +04:00
if ( numeric ) {
return ;
}
2000-12-13 15:53:42 +03:00
2007-10-10 18:57:34 +04:00
status = cli_lsa_lookup_sid ( cli , sid , talloc_tos ( ) , & type ,
& domain , & name ) ;
2000-12-04 09:43:36 +03:00
2007-10-10 18:57:34 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2000-12-21 03:12:59 +03:00
return ;
2000-12-03 08:24:16 +03:00
}
2000-12-21 03:12:59 +03:00
2008-10-15 03:09:17 +04:00
if ( * domain ) {
slprintf ( str , sizeof ( fstring ) - 1 , " %s%s%s " ,
domain , lp_winbind_separator ( ) , name ) ;
} else {
fstrcpy ( str , name ) ;
}
2000-12-03 11:35:11 +03:00
}
2000-12-03 08:24:16 +03:00
2000-12-03 11:35:11 +03:00
/* convert a string to a SID, either numeric or username/group */
2010-05-21 05:25:01 +04:00
static bool StringToSid ( struct cli_state * cli , struct dom_sid * sid , const char * str )
2000-12-03 11:35:11 +03:00
{
2007-10-10 18:57:34 +04:00
enum lsa_SidType type ;
2002-01-26 14:48:42 +03:00
2000-12-13 15:53:42 +03:00
if ( strncmp ( str , " S- " , 2 ) = = 0 ) {
2000-12-21 03:12:59 +03:00
return string_to_sid ( sid , str ) ;
2000-12-13 15:53:42 +03:00
}
2000-12-04 09:43:36 +03:00
2007-10-10 18:57:34 +04:00
return NT_STATUS_IS_OK ( cli_lsa_lookup_name ( cli , str , & type , sid ) ) ;
2000-12-03 11:35:11 +03:00
}
2000-12-03 08:24:16 +03:00
2008-10-15 03:09:17 +04:00
static void print_ace_flags ( FILE * f , uint8_t flags )
{
char * str = talloc_strdup ( NULL , " " ) ;
if ( ! str ) {
goto out ;
}
if ( flags & SEC_ACE_FLAG_OBJECT_INHERIT ) {
str = talloc_asprintf ( str , " %s%s " ,
str , " OI| " ) ;
if ( ! str ) {
goto out ;
}
}
if ( flags & SEC_ACE_FLAG_CONTAINER_INHERIT ) {
str = talloc_asprintf ( str , " %s%s " ,
str , " CI| " ) ;
if ( ! str ) {
goto out ;
}
}
if ( flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) {
str = talloc_asprintf ( str , " %s%s " ,
str , " NP| " ) ;
if ( ! str ) {
goto out ;
}
}
if ( flags & SEC_ACE_FLAG_INHERIT_ONLY ) {
str = talloc_asprintf ( str , " %s%s " ,
str , " IO| " ) ;
if ( ! str ) {
goto out ;
}
}
if ( flags & SEC_ACE_FLAG_INHERITED_ACE ) {
str = talloc_asprintf ( str , " %s%s " ,
str , " I| " ) ;
if ( ! str ) {
goto out ;
}
}
/* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 )
and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they ' re
audit ace flags . */
if ( str [ strlen ( str ) - 1 ] = = ' | ' ) {
str [ strlen ( str ) - 1 ] = ' \0 ' ;
fprintf ( f , " /%s/ " , str ) ;
} else {
fprintf ( f , " /0x%x/ " , flags ) ;
}
TALLOC_FREE ( str ) ;
return ;
out :
fprintf ( f , " /0x%x/ " , flags ) ;
}
2000-12-03 08:24:16 +03:00
2000-12-03 11:35:11 +03:00
/* print an ACE on a FILE, using either numeric or ascii representation */
2010-05-18 05:25:38 +04:00
static void print_ace ( struct cli_state * cli , FILE * f , struct security_ace * ace )
2000-12-03 11:35:11 +03:00
{
2003-01-03 11:28:12 +03:00
const struct perm_value * v ;
2000-12-03 11:35:11 +03:00
fstring sidstr ;
2000-12-07 09:05:57 +03:00
int do_print = 0 ;
uint32 got_mask ;
2000-12-03 08:24:16 +03:00
2007-10-10 18:57:34 +04:00
SidToString ( cli , sidstr , & ace - > trustee ) ;
2000-12-03 10:36:15 +03:00
2000-12-03 11:35:11 +03:00
fprintf ( f , " %s: " , sidstr ) ;
if ( numeric ) {
2008-10-15 03:09:17 +04:00
fprintf ( f , " %d/0x%x/0x%08x " ,
2006-09-21 02:23:12 +04:00
ace - > type , ace - > flags , ace - > access_mask ) ;
2000-12-03 11:35:11 +03:00
return ;
2000-12-03 08:24:16 +03:00
}
2000-12-04 09:14:28 +03:00
/* Ace type */
if ( ace - > type = = SEC_ACE_TYPE_ACCESS_ALLOWED ) {
fprintf ( f , " ALLOWED " ) ;
} else if ( ace - > type = = SEC_ACE_TYPE_ACCESS_DENIED ) {
fprintf ( f , " DENIED " ) ;
2000-12-03 11:35:11 +03:00
} else {
2000-12-04 09:14:28 +03:00
fprintf ( f , " %d " , ace - > type ) ;
2000-12-03 11:35:11 +03:00
}
2000-12-03 08:24:16 +03:00
2008-10-15 03:09:17 +04:00
print_ace_flags ( f , ace - > flags ) ;
2000-12-04 09:14:28 +03:00
/* Standard permissions */
for ( v = standard_values ; v - > perm ; v + + ) {
2006-09-21 02:23:12 +04:00
if ( ace - > access_mask = = v - > mask ) {
2001-02-23 10:20:11 +03:00
fprintf ( f , " %s " , v - > perm ) ;
2000-12-04 09:14:28 +03:00
return ;
}
}
2000-12-07 09:05:57 +03:00
/* Special permissions. Print out a hex value if we have
leftover bits in the mask . */
2000-12-04 09:14:28 +03:00
2006-09-21 02:23:12 +04:00
got_mask = ace - > access_mask ;
2000-12-07 09:05:57 +03:00
again :
2000-12-04 09:14:28 +03:00
for ( v = special_values ; v - > perm ; v + + ) {
2006-09-21 02:23:12 +04:00
if ( ( ace - > access_mask & v - > mask ) = = v - > mask ) {
2000-12-07 09:05:57 +03:00
if ( do_print ) {
fprintf ( f , " %s " , v - > perm ) ;
}
got_mask & = ~ v - > mask ;
}
}
if ( ! do_print ) {
if ( got_mask ! = 0 ) {
2006-09-21 02:23:12 +04:00
fprintf ( f , " 0x%08x " , ace - > access_mask ) ;
2000-12-07 09:05:57 +03:00
} else {
do_print = 1 ;
goto again ;
2000-12-04 09:14:28 +03:00
}
}
2000-12-03 11:35:11 +03:00
}
2000-12-03 08:24:16 +03:00
2008-10-15 03:09:17 +04:00
static bool parse_ace_flags ( const char * str , unsigned int * pflags )
{
const char * p = str ;
* pflags = 0 ;
while ( * p ) {
if ( strnequal ( p , " OI " , 2 ) ) {
* pflags | = SEC_ACE_FLAG_OBJECT_INHERIT ;
p + = 2 ;
} else if ( strnequal ( p , " CI " , 2 ) ) {
* pflags | = SEC_ACE_FLAG_CONTAINER_INHERIT ;
p + = 2 ;
} else if ( strnequal ( p , " NP " , 2 ) ) {
* pflags | = SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ;
p + = 2 ;
} else if ( strnequal ( p , " IO " , 2 ) ) {
* pflags | = SEC_ACE_FLAG_INHERIT_ONLY ;
p + = 2 ;
} else if ( * p = = ' I ' ) {
* pflags | = SEC_ACE_FLAG_INHERITED_ACE ;
p + = 1 ;
} else if ( * p ) {
return false ;
}
if ( * p ! = ' | ' & & * p ! = ' \0 ' ) {
return false ;
}
}
return true ;
}
2000-12-03 11:35:11 +03:00
/* parse an ACE in the same format as print_ace() */
2010-05-18 05:25:38 +04:00
static bool parse_ace ( struct cli_state * cli , struct security_ace * ace ,
2007-10-10 18:57:34 +04:00
const char * orig_str )
2000-12-03 11:35:11 +03:00
{
char * p ;
2002-11-13 02:20:50 +03:00
const char * cp ;
2007-12-08 04:32:32 +03:00
char * tok ;
2005-11-02 23:32:11 +03:00
unsigned int atype = 0 ;
unsigned int aflags = 0 ;
unsigned int amask = 0 ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2008-10-09 20:49:03 +04:00
uint32_t mask ;
2003-01-03 11:28:12 +03:00
const struct perm_value * v ;
2005-11-02 05:13:08 +03:00
char * str = SMB_STRDUP ( orig_str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2005-11-02 05:13:08 +03:00
if ( ! str ) {
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2005-11-02 05:13:08 +03:00
return False ;
}
2000-12-07 09:05:57 +03:00
2000-12-03 11:35:11 +03:00
ZERO_STRUCTP ( ace ) ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( str , ' : ' ) ;
2005-11-02 05:13:08 +03:00
if ( ! p ) {
printf ( " ACE '%s': missing ':'. \n " , orig_str ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2005-11-02 05:13:08 +03:00
return False ;
}
2000-12-07 09:05:57 +03:00
* p = ' \0 ' ;
p + + ;
/* Try to parse numeric form */
if ( sscanf ( p , " %i/%i/%i " , & atype , & aflags , & amask ) = = 3 & &
2007-10-10 18:57:34 +04:00
StringToSid ( cli , & sid , str ) ) {
2000-12-07 09:05:57 +03:00
goto done ;
}
/* Try to parse text form */
2007-10-10 18:57:34 +04:00
if ( ! StringToSid ( cli , & sid , str ) ) {
2005-11-02 05:13:08 +03:00
printf ( " ACE '%s': failed to convert '%s' to SID \n " ,
orig_str , str ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2000-12-07 09:05:57 +03:00
return False ;
}
2002-11-13 02:20:50 +03:00
cp = p ;
2007-12-08 04:32:32 +03:00
if ( ! next_token_talloc ( frame , & cp , & tok , " / " ) ) {
2005-11-02 05:13:08 +03:00
printf ( " ACE '%s': failed to find '/' character. \n " ,
orig_str ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2000-12-07 09:05:57 +03:00
return False ;
}
if ( strncmp ( tok , " ALLOWED " , strlen ( " ALLOWED " ) ) = = 0 ) {
atype = SEC_ACE_TYPE_ACCESS_ALLOWED ;
} else if ( strncmp ( tok , " DENIED " , strlen ( " DENIED " ) ) = = 0 ) {
atype = SEC_ACE_TYPE_ACCESS_DENIED ;
} else {
2005-11-02 05:13:08 +03:00
printf ( " ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s' \n " ,
orig_str , tok ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2000-12-07 09:05:57 +03:00
return False ;
}
/* Only numeric form accepted for flags at present */
2008-10-15 03:09:17 +04:00
if ( ! next_token_talloc ( frame , & cp , & tok , " / " ) ) {
printf ( " ACE '%s': bad flags entry at '%s' \n " ,
2005-11-02 05:13:08 +03:00
orig_str , tok ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2000-12-07 09:05:57 +03:00
return False ;
}
2008-10-15 03:09:17 +04:00
if ( tok [ 0 ] < ' 0 ' | | tok [ 0 ] > ' 9 ' ) {
if ( ! parse_ace_flags ( tok , & aflags ) ) {
printf ( " ACE '%s': bad named flags entry at '%s' \n " ,
orig_str , tok ) ;
SAFE_FREE ( str ) ;
TALLOC_FREE ( frame ) ;
return False ;
}
} else if ( strnequal ( tok , " 0x " , 2 ) ) {
if ( ! sscanf ( tok , " %x " , & aflags ) ) {
printf ( " ACE '%s': bad hex flags entry at '%s' \n " ,
orig_str , tok ) ;
SAFE_FREE ( str ) ;
TALLOC_FREE ( frame ) ;
return False ;
}
} else {
if ( ! sscanf ( tok , " %i " , & aflags ) ) {
printf ( " ACE '%s': bad integer flags entry at '%s' \n " ,
orig_str , tok ) ;
SAFE_FREE ( str ) ;
TALLOC_FREE ( frame ) ;
return False ;
}
}
2007-12-08 04:32:32 +03:00
if ( ! next_token_talloc ( frame , & cp , & tok , " / " ) ) {
2005-11-02 05:13:08 +03:00
printf ( " ACE '%s': missing / at '%s' \n " ,
orig_str , tok ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2000-12-03 11:35:11 +03:00
return False ;
2000-12-03 08:24:16 +03:00
}
2000-12-07 09:05:57 +03:00
if ( strncmp ( tok , " 0x " , 2 ) = = 0 ) {
if ( sscanf ( tok , " %i " , & amask ) ! = 1 ) {
2005-11-02 05:13:08 +03:00
printf ( " ACE '%s': bad hex number at '%s' \n " ,
orig_str , tok ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2000-12-07 09:05:57 +03:00
return False ;
}
goto done ;
}
for ( v = standard_values ; v - > perm ; v + + ) {
if ( strcmp ( tok , v - > perm ) = = 0 ) {
amask = v - > mask ;
goto done ;
}
}
p = tok ;
while ( * p ) {
2007-10-19 04:40:25 +04:00
bool found = False ;
2000-12-07 09:05:57 +03:00
for ( v = special_values ; v - > perm ; v + + ) {
if ( v - > perm [ 0 ] = = * p ) {
amask | = v - > mask ;
found = True ;
}
}
2005-11-02 05:13:08 +03:00
if ( ! found ) {
printf ( " ACE '%s': bad permission value at '%s' \n " ,
orig_str , p ) ;
SAFE_FREE ( str ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2005-11-02 05:13:08 +03:00
return False ;
}
2000-12-07 09:05:57 +03:00
p + + ;
}
if ( * p ) {
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2005-11-02 05:13:08 +03:00
SAFE_FREE ( str ) ;
2000-12-07 09:05:57 +03:00
return False ;
}
done :
2006-09-21 02:23:12 +04:00
mask = amask ;
2000-12-04 05:01:57 +03:00
init_sec_ace ( ace , & sid , atype , mask , aflags ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2005-11-02 05:13:08 +03:00
SAFE_FREE ( str ) ;
2000-12-03 11:35:11 +03:00
return True ;
2000-12-03 08:24:16 +03:00
}
2010-05-18 05:30:40 +04:00
/* add an ACE to a list of ACEs in a struct security_acl */
static bool add_ace ( struct security_acl * * the_acl , struct security_ace * ace )
2000-12-03 10:36:15 +03:00
{
2010-05-18 05:30:40 +04:00
struct security_acl * new_ace ;
2010-05-18 05:25:38 +04:00
struct security_ace * aces ;
2000-12-14 08:38:05 +03:00
if ( ! * the_acl ) {
2007-10-10 18:57:34 +04:00
return ( ( ( * the_acl ) = make_sec_acl ( talloc_tos ( ) , 3 , 1 , ace ) )
! = NULL ) ;
2000-12-03 10:36:15 +03:00
}
2010-05-18 05:25:38 +04:00
if ( ! ( aces = SMB_CALLOC_ARRAY ( struct security_ace , 1 + ( * the_acl ) - > num_aces ) ) ) {
2006-06-20 13:16:53 +04:00
return False ;
}
2010-05-18 05:25:38 +04:00
memcpy ( aces , ( * the_acl ) - > aces , ( * the_acl ) - > num_aces * sizeof ( struct
security_ace ) ) ;
memcpy ( aces + ( * the_acl ) - > num_aces , ace , sizeof ( struct security_ace ) ) ;
2007-10-10 18:57:34 +04:00
new_ace = make_sec_acl ( talloc_tos ( ) , ( * the_acl ) - > revision , 1 + ( * the_acl ) - > num_aces , aces ) ;
2001-09-17 15:48:29 +04:00
SAFE_FREE ( aces ) ;
2005-06-25 00:25:18 +04:00
( * the_acl ) = new_ace ;
2000-12-03 10:36:15 +03:00
return True ;
}
/* 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 ;
2010-05-21 05:25:01 +04:00
struct dom_sid * grp_sid = NULL , * owner_sid = NULL ;
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 ) {
2006-03-13 04:32:30 +03:00
if ( owner_sid ) {
printf ( " Only specify owner once \n " ) ;
goto done ;
}
2010-05-21 05:25:01 +04:00
owner_sid = SMB_CALLOC_ARRAY ( struct dom_sid , 1 ) ;
2000-12-03 14:05:11 +03:00
if ( ! owner_sid | |
2007-10-10 18:57:34 +04:00
! 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
}
2000-12-12 09:06:10 +03:00
continue ;
2000-12-03 10:36:15 +03:00
}
if ( strncmp ( tok , " GROUP: " , 6 ) = = 0 ) {
2006-03-13 04:32:30 +03:00
if ( grp_sid ) {
printf ( " Only specify group once \n " ) ;
goto done ;
}
2010-05-21 05:25:01 +04:00
grp_sid = SMB_CALLOC_ARRAY ( struct dom_sid , 1 ) ;
2000-12-03 14:05:11 +03:00
if ( ! grp_sid | |
2007-10-10 18:57:34 +04:00
! StringToSid ( cli , grp_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
}
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
}
2007-12-08 04:32:32 +03:00
ret = make_sec_desc ( ctx , revision , SEC_DESC_SELF_RELATIVE , owner_sid , grp_sid ,
2000-12-04 07:58:40 +03:00
NULL , dacl , & sd_size ) ;
2000-12-03 10:36:15 +03:00
2006-03-13 03:35:33 +03:00
done :
2001-09-17 15:48:29 +04:00
SAFE_FREE ( grp_sid ) ;
SAFE_FREE ( owner_sid ) ;
2000-12-03 10:36:15 +03:00
return ret ;
}
2000-12-03 11:35:11 +03:00
/* print a ascii version of a security descriptor on a FILE handle */
2010-05-18 12:29:34 +04:00
static void sec_desc_print ( struct cli_state * cli , FILE * f , struct security_descriptor * sd )
2000-12-03 11:35:11 +03:00
{
fstring sidstr ;
2002-02-16 22:46:42 +03:00
uint32 i ;
2000-12-03 11:35:11 +03:00
2003-04-09 18:34:53 +04:00
fprintf ( f , " REVISION:%d \n " , sd - > revision ) ;
2008-10-15 03:09:17 +04:00
fprintf ( f , " CONTROL:0x%x \n " , sd - > type ) ;
2000-12-03 11:35:11 +03:00
/* Print owner and group sid */
if ( sd - > owner_sid ) {
2007-10-10 18:57:34 +04:00
SidToString ( cli , sidstr , sd - > owner_sid ) ;
2000-12-03 11:35:11 +03:00
} else {
fstrcpy ( sidstr , " " ) ;
}
2003-04-09 18:34:53 +04:00
fprintf ( f , " OWNER:%s \n " , sidstr ) ;
2000-12-03 11:35:11 +03:00
2006-09-21 02:23:12 +04:00
if ( sd - > group_sid ) {
2007-10-10 18:57:34 +04:00
SidToString ( cli , sidstr , sd - > group_sid ) ;
2000-12-03 11:35:11 +03:00
} else {
fstrcpy ( sidstr , " " ) ;
}
fprintf ( f , " GROUP:%s \n " , sidstr ) ;
/* Print aces */
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
2010-05-18 05:25:38 +04:00
struct security_ace * ace = & sd - > dacl - > aces [ i ] ;
2000-12-04 07:58:40 +03:00
fprintf ( f , " ACL: " ) ;
2007-10-10 18:57:34 +04:00
print_ace ( cli , f , ace ) ;
2001-02-23 10:20:11 +03:00
fprintf ( f , " \n " ) ;
2000-12-03 11:35:11 +03:00
}
2000-12-04 03:35:31 +03:00
2000-12-03 11:35:11 +03:00
}
2000-12-03 05:19:27 +03:00
2010-05-06 09:35:02 +04:00
/*****************************************************
get fileinfo for filename
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static uint16 get_fileinfo ( struct cli_state * cli , const char * filename )
{
uint16_t fnum = ( uint16_t ) - 1 ;
uint16 mode ;
/* The desired access below is the only one I could find that works
with NT4 , W2KP and Samba */
if ( ! NT_STATUS_IS_OK ( cli_ntcreate ( cli , filename , 0 , CREATE_ACCESS_READ ,
0 , FILE_SHARE_READ | FILE_SHARE_WRITE ,
FILE_OPEN , 0x0 , 0x0 , & fnum ) ) ) {
printf ( " Failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
}
if ( ! cli_qfileinfo ( cli , fnum , & mode , NULL , NULL , NULL ,
NULL , NULL , NULL ) ) {
printf ( " Failed to file info %s: %s \n " , filename ,
cli_errstr ( cli ) ) ;
}
cli_close ( cli , fnum ) ;
return mode ;
}
2010-05-03 05:08:29 +04:00
/*****************************************************
get sec desc for filename
2000-12-03 05:19:27 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-18 12:29:34 +04:00
static struct security_descriptor * get_secdesc ( 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 ;
2000-12-03 05:19:27 +03:00
2010-05-03 05:08:29 +04:00
/* The desired access below is the only one I could find that works
with NT4 , W2KP and Samba */
2000-12-07 09:05:57 +03:00
2010-05-03 05:08:29 +04:00
if ( ! NT_STATUS_IS_OK ( cli_ntcreate ( cli , filename , 0 , CREATE_ACCESS_READ ,
0 , FILE_SHARE_READ | FILE_SHARE_WRITE ,
FILE_OPEN , 0x0 , 0x0 , & fnum ) ) ) {
2000-12-04 09:46:52 +03:00
printf ( " Failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
2010-05-03 05:08:29 +04:00
return NULL ;
2000-12-03 05:19:27 +03:00
}
2007-10-10 18:57:34 +04:00
sd = cli_query_secdesc ( cli , fnum , talloc_tos ( ) ) ;
2000-12-03 08:24:16 +03:00
2010-05-03 05:08:29 +04:00
cli_close ( cli , fnum ) ;
2000-12-03 08:24:16 +03:00
if ( ! sd ) {
2010-05-03 05:08:29 +04:00
printf ( " Failed to get security descriptor \n " ) ;
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
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 ;
/* The desired access below is the only one I could find that works
with NT4 , W2KP and Samba */
if ( ! NT_STATUS_IS_OK ( cli_ntcreate ( cli , filename , 0 ,
WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS ,
0 , FILE_SHARE_READ | FILE_SHARE_WRITE ,
FILE_OPEN , 0x0 , 0x0 , & fnum ) ) ) {
printf ( " Failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
return false ;
}
if ( ! cli_set_secdesc ( cli , fnum , sd ) ) {
printf ( " ERROR: security description set failed: %s \n " ,
cli_errstr ( cli ) ) ;
result = false ;
}
cli_close ( cli , fnum ) ;
return result ;
}
2010-05-03 05:08:29 +04:00
/*****************************************************
dump the acls for a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int cacl_dump ( struct cli_state * cli , const char * filename )
{
int result = EXIT_FAILED ;
2010-05-18 12:29:34 +04:00
struct security_descriptor * sd ;
2000-12-03 05:19:27 +03:00
2010-05-03 05:08:29 +04:00
if ( test_args )
return EXIT_OK ;
2000-12-22 02:36:25 +03:00
2010-05-03 05:08:29 +04:00
sd = get_secdesc ( cli , filename ) ;
if ( sd ) {
if ( sddl ) {
printf ( " %s \n " , sddl_encode ( talloc_tos ( ) , sd ,
get_global_sam_sid ( ) ) ) ;
} else {
sec_desc_print ( cli , stdout , sd ) ;
}
result = EXIT_OK ;
}
2002-12-20 04:35:21 +03:00
return result ;
2000-12-03 05:19:27 +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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-12-22 02:36:25 +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 ;
2010-05-18 12:29:34 +04:00
struct security_descriptor * sd , * old ;
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
2010-05-03 05:08:29 +04:00
old = get_secdesc ( cli , filename ) ;
2001-02-22 06:40:01 +03:00
if ( ! old ) {
return EXIT_FAILED ;
}
2007-10-10 18:57:34 +04:00
sd = make_sec_desc ( talloc_tos ( ) , old - > revision , old - > type ,
2003-06-24 05:09:36 +04:00
( change_mode = = REQUEST_CHOWN ) ? & sid : NULL ,
( change_mode = = REQUEST_CHGRP ) ? & sid : NULL ,
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
{
2008-10-15 03:09:17 +04:00
if ( sec_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
{
2002-02-16 22:46:42 +03:00
uint32 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 ; ) {
2006-09-21 02:23:12 +04:00
if ( sec_ace_equal ( & the_acl - > aces [ i - 1 ] , & the_acl - > aces [ i ] ) ) {
2001-02-23 10:20:11 +03:00
int j ;
for ( j = i ; j < the_acl - > num_aces - 1 ; j + + ) {
2006-09-21 02:23:12 +04:00
the_acl - > aces [ j ] = the_acl - > aces [ j + 1 ] ;
2001-02-23 10:20:11 +03:00
}
the_acl - > num_aces - - ;
} else {
i + + ;
2000-12-21 09:21:26 +03:00
}
}
}
2000-12-03 10:36:15 +03:00
/*****************************************************
set the ACLs on a file given an ascii description
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-10-15 03:09:17 +04:00
2010-05-03 05:08:02 +04:00
static int cacl_set ( struct cli_state * cli , const char * filename ,
2000-12-22 02:36:25 +03:00
char * the_acl , enum acl_mode mode )
2000-12-03 10:36:15 +03:00
{
2010-05-18 12:29:34 +04:00
struct security_descriptor * sd , * old ;
2002-02-16 22:46:42 +03:00
uint32 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
2010-03-15 14:16:52 +03:00
if ( sddl ) {
sd = sddl_decode ( talloc_tos ( ) , the_acl , get_global_sam_sid ( ) ) ;
} else {
sd = sec_desc_parse ( talloc_tos ( ) , cli , the_acl ) ;
}
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
2010-05-03 05:08:29 +04:00
old = get_secdesc ( cli , filename ) ;
2000-12-03 15:41:28 +03:00
2001-02-22 06:40:01 +03:00
if ( ! old ) {
return EXIT_FAILED ;
}
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 + + ) {
2006-09-21 02:23:12 +04:00
if ( sec_ace_equal ( & sd - > dacl - > aces [ i ] ,
& old - > dacl - > aces [ j ] ) ) {
2002-02-16 22:46:42 +03:00
uint32 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: " ) ;
2007-10-10 18:57:34 +04:00
print_ace ( cli , stdout , & sd - > dacl - > aces [ i ] ) ;
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 ,
& sd - > dacl - > aces [ i ] . trustee ) ;
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
}
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 ;
2010-05-06 09:35:02 +04:00
uint32 oldattr ;
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 ) {
int i ;
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 ) ;
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 ;
2010-05-06 09:35:02 +04:00
if ( ( oldattr & aDIR ) = = aDIR ) {
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 ;
/* convert all inherited ACL's to non inherated ACL's. */
if ( old - > dacl ) {
int i ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-14 15:06:19 +03:00
static struct cli_state * connect_one ( struct user_auth_info * auth_info ,
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 ;
2007-10-25 01:16:54 +04:00
struct sockaddr_storage ss ;
2002-07-15 14:35:28 +04:00
NTSTATUS nt_status ;
2008-05-05 18:58:24 +04:00
uint32_t flags = 0 ;
2008-12-03 10:29:57 +03:00
zero_sockaddr ( & ss ) ;
2007-10-25 01:16:54 +04:00
2008-12-14 15:06:19 +03:00
if ( get_cmdline_auth_info_use_kerberos ( auth_info ) ) {
2008-05-05 18:58:24 +04:00
flags | = CLI_FULL_CONNECTION_USE_KERBEROS |
CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS ;
}
2008-12-14 15:06:19 +03:00
if ( get_cmdline_auth_info_use_machine_account ( auth_info ) & &
! set_cmdline_auth_info_machine_account_creds ( auth_info ) ) {
2008-05-05 18:58:24 +04:00
return NULL ;
}
2009-03-18 00:53:06 +03:00
set_cmdline_auth_info_getpass ( auth_info ) ;
2000-12-03 05:19:27 +03:00
2008-01-05 11:23:35 +03:00
nt_status = cli_full_connection ( & c , global_myname ( ) , server ,
& ss , 0 ,
share , " ????? " ,
2008-12-14 15:06:19 +03:00
get_cmdline_auth_info_username ( auth_info ) ,
2008-01-05 11:23:35 +03:00
lp_workgroup ( ) ,
2008-12-14 15:06:19 +03:00
get_cmdline_auth_info_password ( auth_info ) ,
2008-05-05 18:58:24 +04:00
flags ,
2008-12-14 15:06:19 +03:00
get_cmdline_auth_info_signing_state ( auth_info ) ,
2008-01-05 11:23:35 +03:00
NULL ) ;
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
2008-12-14 15:06:19 +03:00
if ( get_cmdline_auth_info_smb_encrypt ( auth_info ) ) {
2008-01-05 11:23:35 +03:00
nt_status = cli_cm_force_encryption ( c ,
2008-12-14 15:06:19 +03:00
get_cmdline_auth_info_username ( auth_info ) ,
get_cmdline_auth_info_password ( auth_info ) ,
2008-01-05 11:23:35 +03:00
lp_workgroup ( ) ,
share ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
cli_shutdown ( c ) ;
c = NULL ;
}
}
return c ;
2000-12-03 05:19:27 +03:00
}
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-04-14 07:59:04 +04:00
int main ( int argc , 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 ;
struct poptOption long_options [ ] = {
POPT_AUTOHELP
{ " delete " , ' D ' , POPT_ARG_STRING , NULL , ' D ' , " Delete an acl " , " ACL " } ,
{ " modify " , ' M ' , POPT_ARG_STRING , NULL , ' M ' , " Modify an acl " , " ACL " } ,
2003-09-01 14:43:21 +04:00
{ " add " , ' a ' , POPT_ARG_STRING , NULL , ' a ' , " Add an acl " , " ACL " } ,
2003-04-14 07:59:04 +04:00
{ " set " , ' S ' , POPT_ARG_STRING , NULL , ' S ' , " Set acls " , " ACLS " } ,
{ " chown " , ' C ' , POPT_ARG_STRING , NULL , ' C ' , " Change ownership of a file " , " USERNAME " } ,
{ " chgrp " , ' G ' , POPT_ARG_STRING , NULL , ' G ' , " Change group ownership of a file " , " GROUPNAME " } ,
2010-05-06 09:35:02 +04:00
{ " inherit " , ' I ' , POPT_ARG_STRING , NULL , ' I ' , " Inherit allow|remove|copy " } ,
2008-10-15 03:09:17 +04:00
{ " numeric " , 0 , POPT_ARG_NONE , & numeric , 1 , " Don't resolve sids or masks to names " } ,
2010-03-15 14:16:52 +03:00
{ " sddl " , 0 , POPT_ARG_NONE , & sddl , 1 , " Output and input acls in sddl format " } ,
2008-10-15 03:09:17 +04:00
{ " test-args " , ' t ' , POPT_ARG_NONE , & test_args , 1 , " Test arguments " } ,
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
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 ;
2008-12-14 15:06:19 +03:00
struct user_auth_info * auth_info ;
2002-07-15 14:35:28 +04:00
2005-12-29 01:48:54 +03:00
load_case_tables ( ) ;
2001-02-28 04:38:12 +03:00
2004-11-18 16:29:10 +03:00
/* set default debug level to 1 regardless of what smb.conf sets */
2004-09-15 17:57:33 +04:00
setup_logging ( " smbcacls " , True ) ;
DEBUGLEVEL_CLASS [ DBGC_ALL ] = 1 ;
2001-09-10 15:08:57 +04:00
dbf = x_stderr ;
2004-09-15 17:57:33 +04:00
x_setbuf ( x_stderr , NULL ) ;
2009-08-12 01:35:48 +04:00
AllowDebugChange = false ;
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
2007-12-10 22:30:37 +03:00
lp_load ( get_dyn_CONFIGFILE ( ) , True , False , False , True ) ;
2000-12-03 05:19:27 +03:00
load_interfaces ( ) ;
2008-12-14 15:06:19 +03:00
auth_info = user_auth_info_init ( frame ) ;
if ( auth_info = = NULL ) {
exit ( 1 ) ;
}
popt_common_set_auth_info ( auth_info ) ;
2003-04-14 07:59:04 +04:00
pc = poptGetContext ( " smbcacls " , argc , argv , long_options , 0 ) ;
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 ;
2000-12-03 05:19:27 +03:00
}
}
2003-04-14 07:59:04 +04:00
/* Make connection to server */
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
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
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 , ' \\ ' ) ;
if ( ! share ) {
2007-05-19 08:23:04 +04:00
printf ( " Invalid argument: %s \n " , share ) ;
return - 1 ;
2002-07-15 14:35:28 +04:00
}
* share = 0 ;
share + + ;
2000-12-07 09:05:57 +03:00
if ( ! test_args ) {
2008-12-14 15:06:19 +03:00
cli = connect_one ( auth_info , 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
}
2000-12-21 03:12:59 +03:00
/* Perform requested action */
2010-05-06 09:35:02 +04:00
if ( change_mode = = REQUEST_INHERIT ) {
result = inherit ( cli , filename , owner_username ) ;
} else if ( change_mode ! = REQUEST_NONE ) {
2000-12-22 02:36:25 +03:00
result = owner_set ( cli , change_mode , filename , owner_username ) ;
2000-12-16 03:08:05 +03:00
} else if ( the_acl ) {
2000-12-22 02:36:25 +03:00
result = cacl_set ( cli , filename , the_acl , mode ) ;
2000-12-03 10:36:15 +03:00
} else {
2000-12-22 02:36:25 +03:00
result = cacl_dump ( cli , filename ) ;
2000-12-03 10:36:15 +03:00
}
2000-12-03 05:19:27 +03:00
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
}