2007-06-14 15:29:35 +04:00
/*
Unix SMB / CIFS implementation .
Privileges handling functions
Copyright ( C ) Jean François Micouleau 1998 - 2001
Copyright ( C ) Simo Sorce 2002 - 2003
Copyright ( C ) Gerald ( Jerry ) Carter 2005
Copyright ( C ) Michael Adam 2007
2010-08-26 12:38:16 +04:00
Copyright ( C ) Andrew Bartlett 2010
2010-08-27 03:35:55 +04:00
Copyright ( C ) Andrew Tridgell 2004
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04: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
2007-06-14 15:29:35 +04:00
( at your option ) any later version .
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04: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 .
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04: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/>.
2007-06-14 15:29:35 +04:00
*/
/*
2009-05-16 03:21:08 +04:00
* Basic privileges functions ( mask - operations and conversion
2007-06-14 15:29:35 +04:00
* functions between the different formats ( se_priv , privset , luid )
* moved here * from lib / privileges . c to minimize linker deps .
*
* generally SID - and LUID - related code is left in lib / privileges . c
*
* some extra functions to hide privs array from lib / privileges . c
*/
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04:00
# include "includes.h"
2010-08-27 03:35:55 +04:00
# include "libcli/security/privileges.h"
# include "librpc/gen_ndr/security.h"
/* The use of strcasecmp here is safe, all the comparison strings are ASCII */
# undef strcasecmp
2007-06-14 15:29:35 +04:00
2010-08-27 05:52:51 +04:00
# define NUM_SHORT_LIST_PRIVS 8
2010-08-27 06:19:09 +04:00
static const struct {
enum sec_privilege luid ;
uint64_t privilege_mask ;
const char * name ;
const char * description ;
} privs [ ] = {
2010-08-27 05:56:37 +04:00
2010-08-30 07:28:19 +04:00
{ SEC_PRIV_MACHINE_ACCOUNT , SEC_PRIV_MACHINE_ACCOUNT_BIT , " SeMachineAccountPrivilege " , " Add machines to domain " } ,
{ SEC_PRIV_TAKE_OWNERSHIP , SEC_PRIV_TAKE_OWNERSHIP_BIT , " SeTakeOwnershipPrivilege " , " Take ownership of files or other objects " } ,
{ SEC_PRIV_BACKUP , SEC_PRIV_BACKUP_BIT , " SeBackupPrivilege " , " Back up files and directories " } ,
{ SEC_PRIV_RESTORE , SEC_PRIV_RESTORE_BIT , " SeRestorePrivilege " , " Restore files and directories " } ,
{ SEC_PRIV_REMOTE_SHUTDOWN , SEC_PRIV_REMOTE_SHUTDOWN_BIT , " SeRemoteShutdownPrivilege " , " Force shutdown from a remote system " } ,
2010-08-26 10:02:12 +04:00
2010-08-30 07:28:19 +04:00
{ SEC_PRIV_PRINT_OPERATOR , SEC_PRIV_PRINT_OPERATOR_BIT , " SePrintOperatorPrivilege " , " Manage printers " } ,
{ SEC_PRIV_ADD_USERS , SEC_PRIV_ADD_USERS_BIT , " SeAddUsersPrivilege " , " Add users and groups to the domain " } ,
{ SEC_PRIV_DISK_OPERATOR , SEC_PRIV_DISK_OPERATOR_BIT , " SeDiskOperatorPrivilege " , " Manage disk shares " } ,
2007-06-14 15:29:35 +04:00
2010-08-27 05:56:37 +04:00
/* The list from here on was not displayed in the code from
* source3 / with the comment that usrmgr will display these
* next 2 twice if you include them . The source4 / code has
* always included them , but they do not appear in Windows
* 2008 R2 .
Finally , the parameter ' short_list ' determines if the short
or full list ( including many other privileges ) is used */
{ SEC_PRIV_SECURITY ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_SECURITY_BIT ,
2010-08-27 05:56:37 +04:00
" SeSecurityPrivilege " ,
" System security " } ,
{ SEC_PRIV_SYSTEMTIME ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_SYSTEMTIME_BIT ,
2010-08-27 05:56:37 +04:00
" SeSystemtimePrivilege " ,
" Set the system clock " } ,
{ SEC_PRIV_SHUTDOWN ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_SHUTDOWN_BIT ,
2010-08-27 05:56:37 +04:00
" SeShutdownPrivilege " ,
" Shutdown the system " } ,
{ SEC_PRIV_DEBUG ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_DEBUG_BIT ,
2010-08-27 05:56:37 +04:00
" SeDebugPrivilege " ,
" Debug processes " } ,
{ SEC_PRIV_SYSTEM_ENVIRONMENT ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_SYSTEM_ENVIRONMENT_BIT ,
2010-08-27 05:56:37 +04:00
" SeSystemEnvironmentPrivilege " ,
" Modify system environment " } ,
{ SEC_PRIV_SYSTEM_PROFILE ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_SYSTEM_PROFILE_BIT ,
2010-08-27 05:56:37 +04:00
" SeSystemProfilePrivilege " ,
" Profile the system " } ,
{ SEC_PRIV_PROFILE_SINGLE_PROCESS ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_PROFILE_SINGLE_PROCESS_BIT ,
2010-08-27 05:56:37 +04:00
" SeProfileSingleProcessPrivilege " ,
" Profile one process " } ,
{ SEC_PRIV_INCREASE_BASE_PRIORITY ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_INCREASE_BASE_PRIORITY_BIT ,
2010-08-27 05:56:37 +04:00
" SeIncreaseBasePriorityPrivilege " ,
" Increase base priority " } ,
{ SEC_PRIV_LOAD_DRIVER ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_LOAD_DRIVER_BIT ,
2010-08-27 05:56:37 +04:00
" SeLoadDriverPrivilege " ,
" Load drivers " } ,
{ SEC_PRIV_CREATE_PAGEFILE ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_CREATE_PAGEFILE_BIT ,
2010-08-27 05:56:37 +04:00
" SeCreatePagefilePrivilege " ,
" Create page files " } ,
{ SEC_PRIV_INCREASE_QUOTA ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_INCREASE_QUOTA_BIT ,
2010-08-27 05:56:37 +04:00
" SeIncreaseQuotaPrivilege " ,
" Increase quota " } ,
{ SEC_PRIV_CHANGE_NOTIFY ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_CHANGE_NOTIFY_BIT ,
2010-08-27 05:56:37 +04:00
" SeChangeNotifyPrivilege " ,
" Register for change notify " } ,
{ SEC_PRIV_UNDOCK ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_UNDOCK_BIT ,
2010-08-27 05:56:37 +04:00
" SeUndockPrivilege " ,
" Undock devices " } ,
{ SEC_PRIV_MANAGE_VOLUME ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_MANAGE_VOLUME_BIT ,
2010-08-27 05:56:37 +04:00
" SeManageVolumePrivilege " ,
" Manage system volumes " } ,
{ SEC_PRIV_IMPERSONATE ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_IMPERSONATE_BIT ,
2010-08-27 05:56:37 +04:00
" SeImpersonatePrivilege " ,
" Impersonate users " } ,
{ SEC_PRIV_CREATE_GLOBAL ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_CREATE_GLOBAL_BIT ,
2010-08-27 05:56:37 +04:00
" SeCreateGlobalPrivilege " ,
" Create global " } ,
{ SEC_PRIV_ENABLE_DELEGATION ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_ENABLE_DELEGATION_BIT ,
2010-08-27 05:56:37 +04:00
" SeEnableDelegationPrivilege " ,
" Enable Delegation " } ,
{ SEC_PRIV_INTERACTIVE_LOGON ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_INTERACTIVE_LOGON_BIT ,
2010-08-27 05:56:37 +04:00
" SeInteractiveLogonRight " ,
" Interactive logon " } ,
{ SEC_PRIV_NETWORK_LOGON ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_NETWORK_LOGON_BIT ,
2010-08-27 05:56:37 +04:00
" SeNetworkLogonRight " ,
" Network logon " } ,
{ SEC_PRIV_REMOTE_INTERACTIVE_LOGON ,
2010-08-30 07:28:19 +04:00
SEC_PRIV_REMOTE_INTERACTIVE_LOGON_BIT ,
2010-08-27 05:56:37 +04:00
" SeRemoteInteractiveLogonRight " ,
" Remote Interactive logon " }
2007-06-14 15:29:35 +04:00
} ;
2010-08-30 07:33:19 +04:00
/*
return a privilege mask given a privilege id
*/
static uint64_t sec_privilege_mask ( enum sec_privilege privilege )
2007-06-14 15:29:35 +04:00
{
2010-08-30 07:33:19 +04:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( privs ) ; i + + ) {
if ( privs [ i ] . luid = = privilege ) {
return privs [ i ] . privilege_mask ;
}
}
2009-05-16 03:21:08 +04:00
2010-08-30 07:33:19 +04:00
return 0 ;
2007-06-14 15:29:35 +04:00
}
/***************************************************************************
2010-08-27 04:30:18 +04:00
put all valid privileges into a mask
2007-06-14 15:29:35 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-26 16:30:26 +04:00
bool se_priv_put_all_privileges ( uint64_t * privilege_mask )
2007-06-14 15:29:35 +04:00
{
int i ;
2010-08-27 04:52:38 +04:00
uint32_t num_privs = ARRAY_SIZE ( privs ) ;
2007-06-14 15:29:35 +04:00
2010-08-30 07:33:19 +04:00
* privilege_mask = 0 ;
2007-06-14 15:29:35 +04:00
for ( i = 0 ; i < num_privs ; i + + ) {
2010-08-30 07:33:19 +04:00
* privilege_mask | = privs [ i ] . privilege_mask ;
2007-06-14 15:29:35 +04:00
}
2010-08-27 03:41:32 +04:00
return true ;
2007-06-14 15:29:35 +04:00
}
/*********************************************************************
2010-08-27 04:30:18 +04:00
Lookup the uint64_t bitmask value for a privilege name
2007-06-14 15:29:35 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-26 16:30:26 +04:00
bool se_priv_from_name ( const char * name , uint64_t * privilege_mask )
2007-06-14 15:29:35 +04:00
{
int i ;
2010-08-27 04:52:38 +04:00
uint32_t num_privs = ARRAY_SIZE ( privs ) ;
for ( i = 0 ; i < num_privs ; i + + ) {
2007-06-14 15:29:35 +04:00
if ( strequal ( privs [ i ] . name , name ) ) {
2010-08-30 07:33:19 +04:00
* privilege_mask = privs [ i ] . privilege_mask ;
2010-08-27 03:41:32 +04:00
return true ;
2007-06-14 15:29:35 +04:00
}
}
2010-08-27 03:41:32 +04:00
return false ;
2007-06-14 15:29:35 +04:00
}
const char * get_privilege_dispname ( const char * name )
{
int i ;
2010-08-27 04:52:38 +04:00
uint32_t num_privs = ARRAY_SIZE ( privs ) ;
2008-02-11 13:57:29 +03:00
if ( ! name ) {
return NULL ;
}
2010-08-27 04:52:38 +04:00
for ( i = 0 ; i < num_privs ; i + + ) {
2007-06-14 15:29:35 +04:00
if ( strequal ( privs [ i ] . name , name ) ) {
return privs [ i ] . description ;
}
}
return NULL ;
}
/*******************************************************************
2010-08-27 06:19:09 +04:00
return the number of elements in the ' short ' privlege array ( traditional source3 behaviour )
2007-06-14 15:29:35 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-27 05:52:51 +04:00
int num_privileges_in_short_list ( void )
2007-06-14 15:29:35 +04:00
{
2010-08-27 05:52:51 +04:00
return NUM_SHORT_LIST_PRIVS ;
2007-06-14 15:29:35 +04:00
}
/****************************************************************************
add a privilege to a privilege array
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-05 04:39:11 +04:00
static bool privilege_set_add ( PRIVILEGE_SET * priv_set , struct lsa_LUIDAttribute set )
2007-06-14 15:29:35 +04:00
{
2010-06-05 04:39:11 +04:00
struct lsa_LUIDAttribute * new_set ;
2007-06-14 15:29:35 +04:00
/* we can allocate memory to add the new privilege */
2010-08-27 03:50:31 +04:00
new_set = talloc_realloc ( priv_set - > mem_ctx , priv_set - > set , struct lsa_LUIDAttribute , priv_set - > count + 1 ) ;
2007-06-14 15:29:35 +04:00
if ( ! new_set ) {
DEBUG ( 0 , ( " privilege_set_add: failed to allocate memory! \n " ) ) ;
2010-08-27 03:41:32 +04:00
return false ;
2009-05-16 03:21:08 +04:00
}
2007-06-14 15:29:35 +04:00
new_set [ priv_set - > count ] . luid . high = set . luid . high ;
new_set [ priv_set - > count ] . luid . low = set . luid . low ;
2010-06-05 04:39:11 +04:00
new_set [ priv_set - > count ] . attribute = set . attribute ;
2007-06-14 15:29:35 +04:00
priv_set - > count + + ;
priv_set - > set = new_set ;
2010-08-27 03:41:32 +04:00
return true ;
2007-06-14 15:29:35 +04:00
}
/*******************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-30 06:50:49 +04:00
bool se_priv_to_privilege_set ( PRIVILEGE_SET * set , uint64_t privilege_mask )
2007-06-14 15:29:35 +04:00
{
int i ;
2010-08-27 04:52:38 +04:00
uint32_t num_privs = ARRAY_SIZE ( privs ) ;
2010-06-05 04:39:11 +04:00
struct lsa_LUIDAttribute luid ;
2009-05-16 03:21:08 +04:00
2010-06-05 04:39:11 +04:00
luid . attribute = 0 ;
2007-06-14 15:29:35 +04:00
luid . luid . high = 0 ;
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04:00
for ( i = 0 ; i < num_privs ; i + + ) {
2010-08-30 06:50:49 +04:00
if ( ( privilege_mask & privs [ i ] . privilege_mask ) = = 0 )
2007-06-14 15:29:35 +04:00
continue ;
2009-05-16 03:21:08 +04:00
2010-08-26 13:20:32 +04:00
luid . luid . high = 0 ;
luid . luid . low = privs [ i ] . luid ;
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04:00
if ( ! privilege_set_add ( set , luid ) )
2010-08-27 03:41:32 +04:00
return false ;
2007-06-14 15:29:35 +04:00
}
2010-08-27 03:41:32 +04:00
return true ;
2007-06-14 15:29:35 +04:00
}
/*******************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-26 16:30:26 +04:00
bool privilege_set_to_se_priv ( uint64_t * privilege_mask , struct lsa_PrivilegeSet * privset )
2007-06-14 15:29:35 +04:00
{
int i ;
2009-05-16 03:21:08 +04:00
2010-08-26 16:30:26 +04:00
ZERO_STRUCTP ( privilege_mask ) ;
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04:00
for ( i = 0 ; i < privset - > count ; i + + ) {
2010-08-26 08:37:00 +04:00
uint64_t r ;
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04:00
/* sanity check for invalid privilege. we really
only care about the low 32 bits */
2009-05-16 03:21:08 +04:00
2007-06-14 15:29:35 +04:00
if ( privset - > set [ i ] . luid . high ! = 0 )
2010-08-27 03:41:32 +04:00
return false ;
2009-05-16 03:21:08 +04:00
2010-08-30 07:17:48 +04:00
r = sec_privilege_mask ( privset - > set [ i ] . luid . low ) ;
if ( r ) {
* privilege_mask | = r ;
}
2007-06-14 15:29:35 +04:00
}
2010-08-27 03:41:32 +04:00
return true ;
2007-06-14 15:29:35 +04:00
}
2010-08-27 03:35:55 +04:00
/*
map a privilege id to the wire string constant
*/
const char * sec_privilege_name ( enum sec_privilege privilege )
{
int i ;
2010-08-27 05:56:37 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( privs ) ; i + + ) {
if ( privs [ i ] . luid = = privilege ) {
return privs [ i ] . name ;
2010-08-27 03:35:55 +04:00
}
}
return NULL ;
}
/*
map a privilege id to a privilege display name . Return NULL if not found
TODO : this should use language mappings
*/
const char * sec_privilege_display_name ( enum sec_privilege privilege , uint16_t * language )
{
int i ;
if ( privilege < 1 | | privilege > 64 ) {
return NULL ;
}
2010-08-27 05:56:37 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( privs ) ; i + + ) {
if ( privs [ i ] . luid = = privilege ) {
return privs [ i ] . description ;
2010-08-27 03:35:55 +04:00
}
}
return NULL ;
}
/*
map a privilege name to a privilege id . Return - 1 if not found
*/
enum sec_privilege sec_privilege_id ( const char * name )
{
int i ;
2010-08-27 05:56:37 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( privs ) ; i + + ) {
if ( strcasecmp ( privs [ i ] . name , name ) = = 0 ) {
return privs [ i ] . luid ;
2010-08-27 03:35:55 +04:00
}
}
return - 1 ;
}
/*
2010-08-27 06:19:09 +04:00
assist in walking the table of privileges - return the LUID ( low 32 bits ) by index
2010-08-27 03:35:55 +04:00
*/
enum sec_privilege sec_privilege_from_index ( int idx )
{
2010-08-27 05:56:37 +04:00
if ( idx > = 0 & & idx < ARRAY_SIZE ( privs ) ) {
return privs [ idx ] . luid ;
2010-08-27 03:35:55 +04:00
}
return - 1 ;
}
2010-08-27 06:19:09 +04:00
/*
assist in walking the table of privileges - return the string constant by index
*/
const char * sec_privilege_name_from_index ( int idx )
{
if ( idx > = 0 & & idx < ARRAY_SIZE ( privs ) ) {
return privs [ idx ] . name ;
}
return NULL ;
}
2010-08-27 03:35:55 +04:00
/*
return true if a security_token has a particular privilege bit set
*/
bool security_token_has_privilege ( const struct security_token * token , enum sec_privilege privilege )
{
uint64_t mask ;
mask = sec_privilege_mask ( privilege ) ;
if ( mask = = 0 ) {
return false ;
}
if ( token - > privilege_mask & mask ) {
return true ;
}
return false ;
}
/*
set a bit in the privilege mask
*/
void security_token_set_privilege ( struct security_token * token , enum sec_privilege privilege )
{
/* Relies on the fact that an invalid privilage will return 0, so won't change this */
token - > privilege_mask | = sec_privilege_mask ( privilege ) ;
}
void security_token_debug_privileges ( int dbg_lev , const struct security_token * token )
{
DEBUGADD ( dbg_lev , ( " Privileges (0x%16llX): \n " ,
( unsigned long long ) token - > privilege_mask ) ) ;
if ( token - > privilege_mask ) {
2010-08-30 07:06:18 +04:00
int idx = 0 ;
2010-08-27 03:35:55 +04:00
int i = 0 ;
2010-08-30 07:06:18 +04:00
for ( idx = 0 ; idx < ARRAY_SIZE ( privs ) ; idx + + ) {
if ( token - > privilege_mask & privs [ idx ] . privilege_mask ) {
2010-08-27 03:35:55 +04:00
DEBUGADD ( dbg_lev , ( " Privilege[%3lu]: %s \n " , ( unsigned long ) i + + ,
2010-08-30 07:06:18 +04:00
privs [ idx ] . name ) ) ;
2010-08-27 03:35:55 +04:00
}
}
}
}