2000-12-03 05:19:27 +03:00
/*
Unix SMB / Netbios implementation .
2000-12-03 14:05:11 +03:00
ACL get / set utility
2000-12-03 05:19:27 +03:00
Version 3.0
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
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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
static fstring password ;
2000-12-16 03:08:05 +03:00
static pstring username ;
static pstring owner_username ;
2000-12-13 15:53:42 +03:00
static fstring server ;
2000-12-03 05:19:27 +03:00
static int got_pass ;
2000-12-07 09:05:57 +03:00
static int test_args ;
2001-02-28 04:38:12 +03:00
TALLOC_CTX * ctx ;
2000-12-03 05:19:27 +03:00
2001-02-22 06:40:01 +03:00
# define CREATE_ACCESS_READ READ_CONTROL_ACCESS
# define CREATE_ACCESS_WRITE (WRITE_DAC_ACCESS | WRITE_OWNER_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 */
static int numeric ;
2000-12-03 05:19:27 +03:00
2001-04-11 05:34:37 +04:00
enum acl_mode { SMB_ACL_SET , SMB_ACL_DELETE , SMB_ACL_MODIFY , SMB_ACL_ADD } ;
2000-12-16 03:08:05 +03:00
enum chown_mode { REQUEST_NONE , REQUEST_CHOWN , REQUEST_CHGRP } ;
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 {
char * perm ;
uint32 mask ;
} ;
/* These values discovered by inspection */
static struct perm_value special_values [ ] = {
{ " R " , 0x00120089 } ,
{ " W " , 0x00120116 } ,
{ " X " , 0x001200a0 } ,
{ " D " , 0x00010000 } ,
{ " P " , 0x00040000 } ,
{ " O " , 0x00080000 } ,
{ NULL , 0 } ,
} ;
static struct perm_value standard_values [ ] = {
{ " READ " , 0x001200a9 } ,
{ " CHANGE " , 0x001301bf } ,
{ " FULL " , 0x001f01ff } ,
{ NULL , 0 } ,
} ;
2000-12-03 15:41:28 +03:00
2000-12-14 06:27:53 +03:00
struct cli_state lsa_cli ;
POLICY_HND pol ;
struct ntuser_creds creds ;
BOOL got_policy_hnd ;
/* Open cli connection and policy handle */
2001-04-13 23:12:06 +04:00
static BOOL cacls_open_policy_hnd ( void )
2000-12-14 06:27:53 +03:00
{
creds . pwd . null_pwd = 1 ;
/* Initialise cli LSA connection */
if ( ! lsa_cli . initialised & &
! cli_lsa_initialise ( & lsa_cli , server , & creds ) ) {
return False ;
}
/* Open policy handle */
if ( ! got_policy_hnd ) {
2001-01-23 20:33:35 +03:00
/* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
but NT sends 0x2000000 so we might as well do it too . */
2001-09-04 14:57:29 +04:00
if ( ! NT_STATUS_IS_OK ( cli_lsa_open_policy ( & lsa_cli , lsa_cli . mem_ctx , True ,
GENERIC_EXECUTE_ACCESS , & pol ) ) ) {
2000-12-14 06:27:53 +03:00
return False ;
}
got_policy_hnd = True ;
}
return True ;
}
2000-12-03 11:35:11 +03:00
/* convert a SID to a string, either numeric or username/group */
static void SidToString ( fstring str , DOM_SID * sid )
2000-12-03 08:24:16 +03:00
{
2000-12-14 06:27:53 +03:00
char * * names = NULL ;
uint32 * types = NULL ;
2000-12-13 15:53:42 +03:00
int num_names ;
2000-12-14 06:27:53 +03:00
sid_to_string ( str , sid ) ;
2000-12-13 15:53:42 +03:00
2000-12-14 06:27:53 +03:00
if ( numeric ) return ;
2000-12-13 15:53:42 +03:00
2000-12-14 06:27:53 +03:00
/* Ask LSA to convert the sid to a name */
2000-12-04 09:43:36 +03:00
2001-04-13 23:12:06 +04:00
if ( ! cacls_open_policy_hnd ( ) | |
2001-09-04 14:57:29 +04:00
! NT_STATUS_IS_OK ( cli_lsa_lookup_sids ( & lsa_cli , lsa_cli . mem_ctx , & pol , 1 , sid , & names ,
& types , & num_names ) ) | |
2001-02-22 09:22:20 +03:00
! names | | ! names [ 0 ] ) {
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
/* Converted OK */
fstrcpy ( str , names [ 0 ] ) ;
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 */
2000-12-15 04:02:11 +03:00
static BOOL StringToSid ( DOM_SID * sid , char * str )
2000-12-03 11:35:11 +03:00
{
2000-12-14 06:27:53 +03:00
uint32 * types = NULL ;
DOM_SID * sids = NULL ;
2000-12-13 15:53:42 +03:00
int num_sids ;
2000-12-15 04:02:11 +03:00
BOOL result = True ;
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
2001-04-13 23:12:06 +04:00
if ( ! cacls_open_policy_hnd ( ) | |
2001-09-04 14:57:29 +04:00
! NT_STATUS_IS_OK ( cli_lsa_lookup_names ( & lsa_cli , lsa_cli . mem_ctx , & pol , 1 , & str ,
& sids , & types , & num_sids ) ) ) {
2000-12-21 09:21:26 +03:00
result = False ;
2000-12-13 15:53:42 +03:00
goto done ;
}
sid_copy ( sid , & sids [ 0 ] ) ;
done :
2000-12-15 04:02:11 +03:00
2000-12-13 15:53:42 +03:00
return result ;
2000-12-03 11:35:11 +03:00
}
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 */
static void print_ace ( FILE * f , SEC_ACE * ace )
{
2000-12-04 09:14:28 +03:00
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
2001-11-30 04:04:15 +03:00
SidToString ( 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 ) {
2001-02-23 10:20:11 +03:00
fprintf ( f , " %d/%d/0x%08x " ,
2000-12-03 11:35:11 +03:00
ace - > type , ace - > flags , ace - > info . mask ) ;
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
2000-12-04 09:14:28 +03:00
/* Not sure what flags can be set in a file ACL */
fprintf ( f , " /%d/ " , ace - > flags ) ;
/* Standard permissions */
for ( v = standard_values ; v - > perm ; v + + ) {
if ( ace - > info . 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
2000-12-07 09:05:57 +03:00
got_mask = ace - > info . mask ;
again :
2000-12-04 09:14:28 +03:00
for ( v = special_values ; v - > perm ; v + + ) {
if ( ( ace - > info . 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 ) {
fprintf ( f , " 0x%08x " , ace - > info . mask ) ;
} 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
2000-12-03 11:35:11 +03:00
/* parse an ACE in the same format as print_ace() */
static BOOL parse_ace ( SEC_ACE * ace , char * str )
{
char * p ;
2000-12-07 09:05:57 +03:00
fstring tok ;
2000-12-03 11:35:11 +03:00
unsigned atype , aflags , amask ;
2000-12-04 05:01:57 +03:00
DOM_SID sid ;
SEC_ACCESS mask ;
2000-12-07 09:05:57 +03:00
struct perm_value * v ;
2000-12-03 11:35:11 +03:00
ZERO_STRUCTP ( ace ) ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( str , ' : ' ) ;
2000-12-03 11:35:11 +03:00
if ( ! p ) 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 & &
StringToSid ( & sid , str ) ) {
goto done ;
}
/* Try to parse text form */
2000-12-13 15:53:42 +03:00
if ( ! StringToSid ( & sid , str ) ) {
2000-12-07 09:05:57 +03:00
return False ;
}
if ( ! next_token ( & p , tok , " / " , sizeof ( fstring ) ) ) {
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 {
return False ;
}
/* Only numeric form accepted for flags at present */
2001-06-21 13:10:42 +04:00
if ( ! ( next_token ( & p , tok , " / " , sizeof ( fstring ) ) & &
2000-12-07 09:05:57 +03:00
sscanf ( tok , " %i " , & aflags ) ) ) {
return False ;
}
2001-06-21 13:10:42 +04:00
if ( ! next_token ( & p , tok , " / " , sizeof ( fstring ) ) ) {
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 ) {
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 ) {
BOOL found = False ;
for ( v = special_values ; v - > perm ; v + + ) {
if ( v - > perm [ 0 ] = = * p ) {
amask | = v - > mask ;
found = True ;
}
}
if ( ! found ) return False ;
p + + ;
}
if ( * p ) {
return False ;
}
done :
2000-12-04 05:01:57 +03:00
mask . mask = amask ;
init_sec_ace ( ace , & sid , atype , mask , aflags ) ;
2000-12-03 11:35:11 +03:00
return True ;
2000-12-03 08:24:16 +03:00
}
2000-12-03 10:36:15 +03:00
/* add an ACE to a list of ACEs in a SEC_ACL */
2000-12-14 08:38:05 +03:00
static BOOL add_ace ( SEC_ACL * * the_acl , SEC_ACE * ace )
2000-12-03 10:36:15 +03:00
{
2000-12-04 05:01:57 +03:00
SEC_ACL * new ;
SEC_ACE * aces ;
2000-12-14 08:38:05 +03:00
if ( ! * the_acl ) {
2001-02-28 04:38:12 +03:00
( * the_acl ) = make_sec_acl ( ctx , 3 , 1 , ace ) ;
2000-12-04 05:01:57 +03:00
return True ;
2000-12-03 10:36:15 +03:00
}
2000-12-14 08:38:05 +03:00
aces = calloc ( 1 + ( * the_acl ) - > num_aces , sizeof ( SEC_ACE ) ) ;
memcpy ( aces , ( * the_acl ) - > ace , ( * the_acl ) - > num_aces * sizeof ( SEC_ACE ) ) ;
memcpy ( aces + ( * the_acl ) - > num_aces , ace , sizeof ( SEC_ACE ) ) ;
2001-02-28 04:38:12 +03:00
new = make_sec_acl ( ctx , ( * the_acl ) - > revision , 1 + ( * the_acl ) - > num_aces , aces ) ;
2001-09-17 15:48:29 +04:00
SAFE_FREE ( aces ) ;
2000-12-14 08:38:05 +03:00
( * the_acl ) = new ;
2000-12-03 10:36:15 +03:00
return True ;
}
/* parse a ascii version of a security descriptor */
static SEC_DESC * sec_desc_parse ( char * str )
{
char * p = str ;
fstring tok ;
2000-12-03 14:05:11 +03:00
SEC_DESC * ret ;
2001-06-20 21:49:38 +04:00
size_t sd_size ;
2000-12-03 14:05:11 +03:00
DOM_SID * grp_sid = NULL , * owner_sid = NULL ;
2000-12-04 07:58:40 +03:00
SEC_ACL * dacl = NULL ;
2000-12-03 14:05:11 +03:00
int revision = 1 ;
2000-12-03 10:36:15 +03:00
2000-12-21 09:21:26 +03:00
while ( next_token ( & p , tok , " \t , \r \n " , sizeof ( tok ) ) ) {
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 ) {
2000-12-03 14:05:11 +03:00
owner_sid = ( DOM_SID * ) calloc ( 1 , sizeof ( DOM_SID ) ) ;
if ( ! owner_sid | |
! StringToSid ( owner_sid , tok + 6 ) ) {
2000-12-03 10:36:15 +03:00
printf ( " Failed to parse owner sid \n " ) ;
return NULL ;
}
2000-12-12 09:06:10 +03:00
continue ;
2000-12-03 10:36:15 +03:00
}
if ( strncmp ( tok , " GROUP: " , 6 ) = = 0 ) {
2000-12-03 14:05:11 +03:00
grp_sid = ( DOM_SID * ) calloc ( 1 , sizeof ( DOM_SID ) ) ;
if ( ! grp_sid | |
! StringToSid ( grp_sid , tok + 6 ) ) {
2000-12-03 10:36:15 +03:00
printf ( " Failed to parse group sid \n " ) ;
return NULL ;
}
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 ) {
2000-12-03 10:36:15 +03:00
SEC_ACE ace ;
2000-12-15 04:02:11 +03:00
if ( ! parse_ace ( & ace , tok + 4 ) ) {
printf ( " Failed to parse ACL %s \n " , tok ) ;
return NULL ;
}
if ( ! add_ace ( & dacl , & ace ) ) {
printf ( " Failed to add ACL %s \n " , tok ) ;
2000-12-03 10:36:15 +03:00
return NULL ;
}
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
printf ( " Failed to parse security descriptor \n " ) ;
return NULL ;
2000-12-03 10:36:15 +03:00
}
2001-02-28 04:38:12 +03:00
ret = make_sec_desc ( ctx , revision , owner_sid , grp_sid ,
2000-12-04 07:58:40 +03:00
NULL , dacl , & sd_size ) ;
2000-12-03 10:36:15 +03:00
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 */
static void sec_desc_print ( FILE * f , SEC_DESC * sd )
{
fstring sidstr ;
int i ;
2000-12-12 09:14:01 +03:00
printf ( " REVISION:%d \n " , sd - > revision ) ;
2000-12-03 11:35:11 +03:00
/* Print owner and group sid */
if ( sd - > owner_sid ) {
SidToString ( sidstr , sd - > owner_sid ) ;
} else {
fstrcpy ( sidstr , " " ) ;
}
printf ( " OWNER:%s \n " , sidstr ) ;
if ( sd - > grp_sid ) {
SidToString ( sidstr , sd - > grp_sid ) ;
} else {
fstrcpy ( sidstr , " " ) ;
}
fprintf ( f , " GROUP:%s \n " , sidstr ) ;
/* Print aces */
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
SEC_ACE * ace = & sd - > dacl - > ace [ i ] ;
2000-12-04 07:58:40 +03:00
fprintf ( f , " ACL: " ) ;
2000-12-04 03:35:31 +03:00
print_ace ( 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
/*****************************************************
dump the acls for a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-12-22 02:36:25 +03:00
static int cacl_dump ( struct cli_state * cli , char * filename )
2000-12-03 05:19:27 +03:00
{
int fnum ;
2000-12-03 08:24:16 +03:00
SEC_DESC * sd ;
2000-12-03 05:19:27 +03:00
2000-12-22 02:36:25 +03:00
if ( test_args ) return EXIT_OK ;
2000-12-07 09:05:57 +03:00
2001-02-22 06:40:01 +03:00
fnum = cli_nt_create ( cli , filename , CREATE_ACCESS_READ ) ;
2000-12-03 05:19:27 +03:00
if ( fnum = = - 1 ) {
2000-12-04 09:46:52 +03:00
printf ( " Failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
2000-12-22 02:36:25 +03:00
return EXIT_FAILED ;
2000-12-03 05:19:27 +03:00
}
2001-05-02 03:07:30 +04:00
sd = cli_query_secdesc ( cli , fnum , ctx ) ;
2000-12-03 08:24:16 +03:00
if ( ! sd ) {
2000-12-04 09:46:52 +03:00
printf ( " ERROR: secdesc query failed: %s \n " , cli_errstr ( cli ) ) ;
2000-12-22 02:36:25 +03:00
return EXIT_FAILED ;
2000-12-03 08:24:16 +03:00
}
sec_desc_print ( stdout , sd ) ;
2000-12-03 05:19:27 +03:00
cli_close ( cli , fnum ) ;
2000-12-22 02:36:25 +03:00
return EXIT_OK ;
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 ,
char * filename , char * new_username )
2000-12-16 03:08:05 +03:00
{
int fnum ;
DOM_SID sid ;
SEC_DESC * sd , * old ;
size_t sd_size ;
2001-02-22 06:40:01 +03:00
fnum = cli_nt_create ( cli , filename , CREATE_ACCESS_READ ) ;
2000-12-21 08:28:39 +03:00
2000-12-16 03:08:05 +03:00
if ( fnum = = - 1 ) {
printf ( " Failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
2000-12-22 02:36:25 +03:00
return EXIT_FAILED ;
2000-12-16 03:08:05 +03:00
}
if ( ! StringToSid ( & sid , new_username ) )
2000-12-22 02:36:25 +03:00
return EXIT_PARSE_ERROR ;
2000-12-16 03:08:05 +03:00
2001-05-02 03:07:30 +04:00
old = cli_query_secdesc ( cli , fnum , ctx ) ;
2000-12-16 03:08:05 +03:00
2001-02-22 06:40:01 +03:00
cli_close ( cli , fnum ) ;
if ( ! old ) {
printf ( " owner_set: Failed to query old descriptor \n " ) ;
return EXIT_FAILED ;
}
2001-02-28 04:38:12 +03:00
sd = make_sec_desc ( ctx , old - > revision ,
2000-12-16 03:08:05 +03:00
( change_mode = = REQUEST_CHOWN ) ? & sid : old - > owner_sid ,
( change_mode = = REQUEST_CHGRP ) ? & sid : old - > grp_sid ,
NULL , old - > dacl , & sd_size ) ;
2001-02-22 06:40:01 +03:00
fnum = cli_nt_create ( cli , filename , CREATE_ACCESS_WRITE ) ;
if ( fnum = = - 1 ) {
printf ( " Failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
return EXIT_FAILED ;
}
2000-12-16 03:08:05 +03:00
if ( ! cli_set_secdesc ( cli , fnum , sd ) ) {
printf ( " ERROR: secdesc set failed: %s \n " , cli_errstr ( cli ) ) ;
}
cli_close ( cli , fnum ) ;
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
2000-12-21 09:21:26 +03: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 . */
2001-02-23 10:20:11 +03:00
static int ace_compare ( SEC_ACE * ace1 , SEC_ACE * ace2 )
2000-12-21 09:21:26 +03:00
{
2001-11-30 04:04:15 +03:00
if ( sec_ace_equal ( ace1 , ace2 ) )
return 0 ;
if ( ace1 - > type ! = ace2 - > type )
return ace2 - > type - ace1 - > type ;
if ( sid_compare ( & ace1 - > trustee , & ace2 - > trustee ) )
return sid_compare ( & ace1 - > trustee , & ace2 - > trustee ) ;
if ( ace1 - > flags ! = ace2 - > flags )
return ace1 - > flags - ace2 - > flags ;
if ( ace1 - > info . mask ! = ace2 - > info . mask )
return ace1 - > info . mask - ace2 - > info . mask ;
if ( ace1 - > size ! = ace2 - > size )
return ace1 - > size - ace2 - > size ;
2001-02-23 10:20:11 +03:00
return memcmp ( ace1 , ace2 , sizeof ( SEC_ACE ) ) ;
}
2000-12-21 09:21:26 +03:00
2001-02-23 10:20:11 +03:00
static void sort_acl ( SEC_ACL * the_acl )
{
int i ;
2001-02-22 09:35:54 +03:00
if ( ! the_acl ) return ;
2001-02-23 10:21:50 +03:00
qsort ( the_acl - > ace , the_acl - > num_aces , sizeof ( the_acl - > ace [ 0 ] ) , QSORT_CAST 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 ; ) {
if ( sec_ace_equal ( & the_acl - > ace [ i - 1 ] , & the_acl - > ace [ i ] ) ) {
int j ;
for ( j = i ; j < the_acl - > num_aces - 1 ; j + + ) {
the_acl - > ace [ j ] = the_acl - > ace [ j + 1 ] ;
}
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-12-22 02:36:25 +03:00
static int cacl_set ( struct cli_state * cli , char * filename ,
char * the_acl , enum acl_mode mode )
2000-12-03 10:36:15 +03:00
{
int fnum ;
2000-12-03 15:41:28 +03:00
SEC_DESC * sd , * old ;
2000-12-04 06:27:02 +03:00
int 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-14 08:38:05 +03:00
sd = sec_desc_parse ( 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
2000-12-21 08:28:39 +03:00
/* The desired access below is the only one I could find that works
with NT4 , W2KP and Samba */
2001-02-22 06:40:01 +03:00
fnum = cli_nt_create ( cli , filename , CREATE_ACCESS_READ ) ;
2000-12-21 08:28:39 +03:00
2000-12-03 10:36:15 +03:00
if ( fnum = = - 1 ) {
2001-02-22 06:40:01 +03:00
printf ( " cacl_set failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
2000-12-22 02:36:25 +03:00
return EXIT_FAILED ;
2000-12-03 10:36:15 +03:00
}
2001-05-02 03:07:30 +04:00
old = cli_query_secdesc ( cli , fnum , ctx ) ;
2000-12-03 15:41:28 +03:00
2001-02-22 06:40:01 +03:00
if ( ! old ) {
printf ( " calc_set: Failed to query old descriptor \n " ) ;
return EXIT_FAILED ;
}
cli_close ( cli , fnum ) ;
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 + + ) {
2000-12-12 09:06:10 +03:00
BOOL found = False ;
2000-12-03 15:41:28 +03:00
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
if ( sec_ace_equal ( & sd - > dacl - > ace [ i ] ,
& old - > dacl - > ace [ j ] ) ) {
2001-02-23 10:20:11 +03:00
int k ;
for ( k = j ; k < old - > dacl - > num_aces - 1 ; k + + ) {
old - > dacl - > ace [ k ] = old - > dacl - > ace [ k + 1 ] ;
2000-12-04 03:33:08 +03:00
}
old - > dacl - > num_aces - - ;
if ( old - > dacl - > num_aces = = 0 ) {
2001-09-17 15:48:29 +04:00
SAFE_FREE ( old - > dacl - > ace ) ;
SAFE_FREE ( old - > dacl ) ;
2000-12-04 03:33:08 +03:00
old - > off_dacl = 0 ;
2000-12-03 15:41:28 +03:00
}
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 ) {
2001-02-23 10:20:11 +03:00
printf ( " ACL for ACE: " ) ;
print_ace ( stdout , & sd - > dacl - > ace [ i ] ) ;
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 + + ) {
2000-12-04 09:43:36 +03:00
BOOL found = False ;
2000-12-03 15:41:28 +03:00
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
2001-11-30 04:04:15 +03:00
if ( sid_equal ( & sd - > dacl - > ace [ i ] . trustee ,
& old - > dacl - > ace [ j ] . trustee ) ) {
2000-12-03 15:41:28 +03:00
old - > dacl - > ace [ j ] = sd - > dacl - > ace [ 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 ;
2001-11-30 04:04:15 +03:00
SidToString ( str , & sd - > dacl - > ace [ 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
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 + + ) {
add_ace ( & old - > dacl , & sd - > dacl - > ace [ i ] ) ;
}
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 */
2001-02-28 04:38:12 +03:00
sd = make_sec_desc ( ctx , old - > revision , old - > owner_sid , old - > grp_sid ,
2000-12-04 07:58:40 +03:00
NULL , old - > dacl , & sd_size ) ;
2000-12-04 03:33:08 +03:00
2001-02-22 06:40:01 +03:00
fnum = cli_nt_create ( cli , filename , CREATE_ACCESS_WRITE ) ;
if ( fnum = = - 1 ) {
printf ( " cacl_set failed to open %s: %s \n " , filename , cli_errstr ( cli ) ) ;
return EXIT_FAILED ;
}
2000-12-04 03:33:08 +03:00
if ( ! cli_set_secdesc ( cli , fnum , sd ) ) {
2000-12-04 09:46:52 +03:00
printf ( " ERROR: secdesc set failed: %s \n " , cli_errstr ( cli ) ) ;
2000-12-22 02:36:25 +03:00
result = EXIT_FAILED ;
2000-12-03 10:36:15 +03:00
}
2000-12-21 09:21:26 +03:00
/* Clean up */
2000-12-03 10:36:15 +03:00
cli_close ( cli , fnum ) ;
2000-12-22 02:36:25 +03:00
return result ;
2000-12-03 10:36:15 +03:00
}
2000-12-03 05:19:27 +03:00
/*****************************************************
return a connection to a server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct cli_state * connect_one ( char * share )
{
struct cli_state * c ;
struct nmb_name called , calling ;
struct in_addr ip ;
extern pstring global_myname ;
fstrcpy ( server , share + 2 ) ;
2001-07-04 11:36:09 +04:00
share = strchr_m ( server , ' \\ ' ) ;
2000-12-03 05:19:27 +03:00
if ( ! share ) return NULL ;
* share = 0 ;
share + + ;
2001-11-26 06:11:44 +03:00
zero_ip ( & ip ) ;
2000-12-03 05:19:27 +03:00
make_nmb_name ( & calling , global_myname , 0x0 ) ;
make_nmb_name ( & called , server , 0x20 ) ;
again :
2001-11-26 06:11:44 +03:00
zero_ip ( & ip ) ;
2000-12-03 05:19:27 +03:00
/* have to open a new connection */
2001-08-25 00:11:09 +04:00
if ( ! ( c = cli_initialise ( NULL ) ) | | ! cli_connect ( c , server , & ip ) ) {
2001-07-04 08:04:17 +04:00
DEBUG ( 0 , ( " Connection to %s failed \n " , server ) ) ;
2000-12-15 04:02:11 +03:00
cli_shutdown ( c ) ;
2000-12-03 05:19:27 +03:00
return NULL ;
}
if ( ! cli_session_request ( c , & calling , & called ) ) {
DEBUG ( 0 , ( " session request to %s failed \n " , called . name ) ) ;
cli_shutdown ( c ) ;
if ( strcmp ( called . name , " *SMBSERVER " ) ) {
make_nmb_name ( & called , " *SMBSERVER " , 0x20 ) ;
goto again ;
}
return NULL ;
}
DEBUG ( 4 , ( " session request ok \n " ) ) ;
if ( ! cli_negprot ( c ) ) {
DEBUG ( 0 , ( " protocol negotiation failed \n " ) ) ;
cli_shutdown ( c ) ;
return NULL ;
}
if ( ! got_pass ) {
char * pass = getpass ( " Password: " ) ;
if ( pass ) {
pstrcpy ( password , pass ) ;
}
}
if ( ! cli_session_setup ( c , username ,
password , strlen ( password ) ,
password , strlen ( password ) ,
lp_workgroup ( ) ) ) {
DEBUG ( 0 , ( " session setup failed: %s \n " , cli_errstr ( c ) ) ) ;
2000-12-15 04:02:11 +03:00
cli_shutdown ( c ) ;
2000-12-03 05:19:27 +03:00
return NULL ;
}
DEBUG ( 4 , ( " session setup ok \n " ) ) ;
if ( ! cli_send_tconX ( c , share , " ????? " ,
password , strlen ( password ) + 1 ) ) {
DEBUG ( 0 , ( " tree connect failed: %s \n " , cli_errstr ( c ) ) ) ;
cli_shutdown ( c ) ;
return NULL ;
}
DEBUG ( 4 , ( " tconx ok \n " ) ) ;
return c ;
}
static void usage ( void )
{
printf (
2000-12-21 03:12:59 +03:00
" Usage: smbcacls //server1/share1 filename [options] \n \
2000-12-03 15:41:28 +03:00
\ n \
2000-12-04 09:14:28 +03:00
\ t - D < acls > delete an acl \ n \
\ t - M < acls > modify an acl \ n \
\ t - A < acls > add an acl \ n \
\ t - S < acls > set acls \ n \
2000-12-16 03:08:05 +03:00
\ t - C username change ownership of a file \ n \
\ t - G username change group ownership of a file \ n \
2000-12-04 09:14:28 +03:00
\ t - n don ' t resolve sids or masks to names \ n \
\ t - h print help \ n \
2001-06-27 08:43:55 +04:00
\ t - d debuglevel set debug output level \ n \
\ t - U username user to autheticate as \ n \
2000-12-03 15:41:28 +03:00
\ n \
2000-12-07 09:05:57 +03:00
The username can be of the form username % % password or \ n \
workgroup \ \ username % % password . \ n \ n \
2000-12-04 09:43:36 +03:00
An acl is of the form ACL : < SID > : type / flags / mask \ n \
2000-12-04 09:14:28 +03:00
You can string acls together with spaces , commas or newlines \ n \
2000-12-03 15:41:28 +03:00
" );
2000-12-03 05:19:27 +03:00
}
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main ( int argc , char * argv [ ] )
{
char * share ;
2001-02-22 09:22:20 +03:00
pstring filename ;
2000-12-03 05:19:27 +03:00
extern char * optarg ;
extern int optind ;
int opt ;
char * p ;
2001-04-13 23:12:06 +04:00
struct cli_state * cli = NULL ;
2001-06-19 04:44:23 +04:00
enum acl_mode mode = SMB_ACL_SET ;
2000-12-14 08:38:05 +03:00
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 ;
2000-12-03 05:19:27 +03:00
2001-02-28 04:38:12 +03:00
ctx = talloc_init ( ) ;
2000-12-03 05:19:27 +03:00
setlinebuf ( stdout ) ;
2001-09-10 15:08:57 +04:00
dbf = x_stderr ;
2000-12-03 05:19:27 +03:00
2000-12-21 03:12:59 +03:00
if ( argc < 3 | | argv [ 1 ] [ 0 ] = = ' - ' ) {
2000-12-03 05:19:27 +03:00
usage ( ) ;
2001-02-28 04:38:12 +03:00
talloc_destroy ( ctx ) ;
2000-12-22 02:36:25 +03:00
exit ( EXIT_PARSE_ERROR ) ;
2000-12-03 05:19:27 +03:00
}
setup_logging ( argv [ 0 ] , True ) ;
share = argv [ 1 ] ;
2001-02-22 09:22:20 +03:00
pstrcpy ( filename , argv [ 2 ] ) ;
2000-12-03 05:19:27 +03:00
all_string_sub ( share , " / " , " \\ " , 0 ) ;
argc - = 2 ;
argv + = 2 ;
2001-11-19 05:49:53 +03:00
lp_load ( dyn_CONFIGFILE , True , False , False ) ;
2000-12-03 05:19:27 +03:00
load_interfaces ( ) ;
if ( getenv ( " USER " ) ) {
pstrcpy ( username , getenv ( " USER " ) ) ;
2000-12-21 03:12:59 +03:00
2001-07-04 11:36:09 +04:00
if ( ( p = strchr_m ( username , ' % ' ) ) ) {
2000-12-21 03:12:59 +03:00
* p = 0 ;
pstrcpy ( password , p + 1 ) ;
got_pass = True ;
2001-07-04 11:36:09 +04:00
memset ( strchr_m ( getenv ( " USER " ) , ' % ' ) + 1 , ' X ' ,
2000-12-21 03:12:59 +03:00
strlen ( password ) ) ;
}
2000-12-03 05:19:27 +03:00
}
2001-06-27 08:43:55 +04:00
while ( ( opt = getopt ( argc , argv , " U:nhS:D:A:M:C:G:td: " ) ) ! = EOF ) {
2000-12-03 05:19:27 +03:00
switch ( opt ) {
case ' U ' :
pstrcpy ( username , optarg ) ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( username , ' % ' ) ;
2000-12-03 05:19:27 +03:00
if ( p ) {
* p = 0 ;
pstrcpy ( password , p + 1 ) ;
got_pass = 1 ;
}
break ;
2000-12-03 11:35:11 +03:00
case ' S ' :
2000-12-14 08:38:05 +03:00
the_acl = optarg ;
2001-04-11 05:34:37 +04:00
mode = SMB_ACL_SET ;
2000-12-03 15:41:28 +03:00
break ;
case ' D ' :
2000-12-14 08:38:05 +03:00
the_acl = optarg ;
2001-04-11 05:34:37 +04:00
mode = SMB_ACL_DELETE ;
2000-12-03 15:41:28 +03:00
break ;
case ' M ' :
2000-12-14 08:38:05 +03:00
the_acl = optarg ;
2001-04-11 05:34:37 +04:00
mode = SMB_ACL_MODIFY ;
2000-12-03 15:41:28 +03:00
break ;
case ' A ' :
2000-12-14 08:38:05 +03:00
the_acl = optarg ;
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 ' :
pstrcpy ( owner_username , optarg ) ;
change_mode = REQUEST_CHOWN ;
break ;
case ' G ' :
pstrcpy ( owner_username , optarg ) ;
change_mode = REQUEST_CHGRP ;
break ;
2000-12-03 11:35:11 +03:00
case ' n ' :
numeric = 1 ;
break ;
2000-12-07 09:05:57 +03:00
case ' t ' :
test_args = 1 ;
break ;
2000-12-03 05:19:27 +03:00
case ' h ' :
usage ( ) ;
2001-02-28 04:38:12 +03:00
talloc_destroy ( ctx ) ;
2000-12-22 02:36:25 +03:00
exit ( EXIT_PARSE_ERROR ) ;
2000-12-04 09:14:28 +03:00
2001-06-27 08:43:55 +04:00
case ' d ' :
DEBUGLEVEL = atoi ( optarg ) ;
break ;
2000-12-03 05:19:27 +03:00
default :
printf ( " Unknown option %c (%d) \n " , ( char ) opt , opt ) ;
2001-02-28 04:38:12 +03:00
talloc_destroy ( ctx ) ;
2000-12-22 02:36:25 +03:00
exit ( EXIT_PARSE_ERROR ) ;
2000-12-03 05:19:27 +03:00
}
}
argc - = optind ;
argv + = optind ;
2000-12-07 09:05:57 +03:00
if ( argc > 0 ) {
usage ( ) ;
2001-02-28 04:38:12 +03:00
talloc_destroy ( ctx ) ;
2000-12-22 02:36:25 +03:00
exit ( EXIT_PARSE_ERROR ) ;
2000-12-07 09:05:57 +03:00
}
2000-12-03 05:19:27 +03:00
2000-12-21 03:12:59 +03:00
/* Make connection to server */
2000-12-07 09:05:57 +03:00
if ( ! test_args ) {
cli = connect_one ( share ) ;
2001-02-28 04:38:12 +03:00
if ( ! cli ) {
talloc_destroy ( ctx ) ;
exit ( EXIT_FAILED ) ;
}
2000-12-07 09:05:57 +03:00
}
2000-12-03 05:19:27 +03:00
2001-02-22 09:22:20 +03:00
all_string_sub ( filename , " / " , " \\ " , 0 ) ;
if ( filename [ 0 ] ! = ' \\ ' ) {
pstring s ;
s [ 0 ] = ' \\ ' ;
safe_strcpy ( & s [ 1 ] , filename , sizeof ( pstring ) - 1 ) ;
pstrcpy ( filename , s ) ;
2000-12-21 08:28:39 +03:00
}
2000-12-21 03:12:59 +03:00
/* Perform requested action */
2000-12-16 03:08:05 +03:00
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
2001-02-28 04:38:12 +03:00
talloc_destroy ( ctx ) ;
2000-12-22 02:36:25 +03:00
return result ;
2000-12-03 05:19:27 +03:00
}