2 Unix SMB/CIFS implementation.
3 Privileges handling functions
4 Copyright (C) Jean François Micouleau 1998-2001
5 Copyright (C) Simo Sorce 2002-2003
6 Copyright (C) Gerald (Jerry) Carter 2005
7 Copyright (C) Michael Adam 2007
8 Copyright (C) Andrew Bartlett 2010
9 Copyright (C) Andrew Tridgell 2004
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Basic privileges functions (mask-operations and conversion
27 * functions between the different formats (se_priv, privset, luid)
28 * moved here * from lib/privileges.c to minimize linker deps.
30 * generally SID- and LUID-related code is left in lib/privileges.c
32 * some extra functions to hide privs array from lib/privileges.c
36 #include "libcli/security/privileges.h"
37 #include "librpc/gen_ndr/security.h"
39 /* The use of strcasecmp here is safe, all the comparison strings are ASCII */
42 const uint64_t se_priv_all = SE_ALL_PRIVS;
44 /* Define variables for all privileges so we can use the
45 uint64_t* in the various se_priv_XXX() functions */
47 const uint64_t se_priv_none = SE_NONE;
48 const uint64_t se_machine_account = SE_MACHINE_ACCOUNT;
49 const uint64_t se_print_operator = SE_PRINT_OPERATOR;
50 const uint64_t se_add_users = SE_ADD_USERS;
51 const uint64_t se_disk_operators = SE_DISK_OPERATOR;
52 const uint64_t se_remote_shutdown = SE_REMOTE_SHUTDOWN;
53 const uint64_t se_restore = SE_RESTORE;
54 const uint64_t se_take_ownership = SE_TAKE_OWNERSHIP;
56 #define NUM_SHORT_LIST_PRIVS 8
59 enum sec_privilege luid;
60 uint64_t privilege_mask;
62 const char *description;
65 {SEC_PRIV_MACHINE_ACCOUNT, SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Add machines to domain"},
66 {SEC_PRIV_TAKE_OWNERSHIP, SE_TAKE_OWNERSHIP, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects"},
67 {SEC_PRIV_BACKUP, SE_BACKUP, "SeBackupPrivilege", "Back up files and directories"},
68 {SEC_PRIV_RESTORE, SE_RESTORE, "SeRestorePrivilege", "Restore files and directories"},
69 {SEC_PRIV_REMOTE_SHUTDOWN, SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system"},
71 {SEC_PRIV_PRINT_OPERATOR, SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Manage printers"},
72 {SEC_PRIV_ADD_USERS, SE_ADD_USERS, "SeAddUsersPrivilege", "Add users and groups to the domain"},
73 {SEC_PRIV_DISK_OPERATOR, SE_DISK_OPERATOR, "SeDiskOperatorPrivilege", "Manage disk shares"},
75 /* The list from here on was not displayed in the code from
76 * source3/ with the comment that usrmgr will display these
77 * next 2 twice if you include them. The source4/ code has
78 * always included them, but they do not appear in Windows
81 Finally, the parameter 'short_list' determines if the short
82 or full list (including many other privileges) is used */
86 "SeSecurityPrivilege",
91 "SeSystemtimePrivilege",
92 "Set the system clock"},
96 "SeShutdownPrivilege",
97 "Shutdown the system"},
104 {SEC_PRIV_SYSTEM_ENVIRONMENT,
105 SE_SYSTEM_ENVIRONMENT,
106 "SeSystemEnvironmentPrivilege",
107 "Modify system environment"},
109 {SEC_PRIV_SYSTEM_PROFILE,
111 "SeSystemProfilePrivilege",
112 "Profile the system"},
114 {SEC_PRIV_PROFILE_SINGLE_PROCESS,
115 SE_PROFILE_SINGLE_PROCESS,
116 "SeProfileSingleProcessPrivilege",
117 "Profile one process"},
119 {SEC_PRIV_INCREASE_BASE_PRIORITY,
120 SE_INCREASE_BASE_PRIORITY,
121 "SeIncreaseBasePriorityPrivilege",
122 "Increase base priority"},
124 {SEC_PRIV_LOAD_DRIVER,
126 "SeLoadDriverPrivilege",
129 {SEC_PRIV_CREATE_PAGEFILE,
131 "SeCreatePagefilePrivilege",
132 "Create page files"},
134 {SEC_PRIV_INCREASE_QUOTA,
136 "SeIncreaseQuotaPrivilege",
139 {SEC_PRIV_CHANGE_NOTIFY,
141 "SeChangeNotifyPrivilege",
142 "Register for change notify"},
149 {SEC_PRIV_MANAGE_VOLUME,
151 "SeManageVolumePrivilege",
152 "Manage system volumes"},
154 {SEC_PRIV_IMPERSONATE,
156 "SeImpersonatePrivilege",
157 "Impersonate users"},
159 {SEC_PRIV_CREATE_GLOBAL,
161 "SeCreateGlobalPrivilege",
164 {SEC_PRIV_ENABLE_DELEGATION,
165 SE_ENABLE_DELEGATION,
166 "SeEnableDelegationPrivilege",
167 "Enable Delegation"},
169 {SEC_PRIV_INTERACTIVE_LOGON,
170 SE_INTERACTIVE_LOGON,
171 "SeInteractiveLogonRight",
172 "Interactive logon"},
174 {SEC_PRIV_NETWORK_LOGON,
176 "SeNetworkLogonRight",
179 {SEC_PRIV_REMOTE_INTERACTIVE_LOGON,
180 SE_REMOTE_INTERACTIVE_LOGON,
181 "SeRemoteInteractiveLogonRight",
182 "Remote Interactive logon"}
185 /***************************************************************************
186 copy an uint64_t privilege bitmap
187 ****************************************************************************/
189 bool se_priv_copy( uint64_t *dst, const uint64_t *src )
199 /***************************************************************************
200 put all valid privileges into a mask
201 ****************************************************************************/
203 bool se_priv_put_all_privileges(uint64_t *privilege_mask)
206 uint32_t num_privs = ARRAY_SIZE(privs);
208 if (!se_priv_copy(privilege_mask, &se_priv_none)) {
211 for ( i=0; i<num_privs; i++ ) {
212 se_priv_add(privilege_mask, &privs[i].privilege_mask);
217 /***************************************************************************
218 combine 2 uint64_t privilege bitmaps and store the resulting set in new_mask
219 ****************************************************************************/
221 void se_priv_add( uint64_t *privilege_mask, const uint64_t *addpriv )
223 *privilege_mask |= *addpriv;
226 /***************************************************************************
227 remove one uint64_t privileges bitmap from another and store the resulting set
229 ****************************************************************************/
231 void se_priv_remove( uint64_t *privilege_mask, const uint64_t *removepriv )
233 *privilege_mask &= ~*removepriv;
236 /***************************************************************************
237 invert a given uint64_t and store the set in new_mask
238 ****************************************************************************/
240 static void se_priv_invert( uint64_t *new_mask, const uint64_t *privilege_mask )
244 se_priv_copy( &allprivs, &se_priv_all );
245 se_priv_remove( &allprivs, privilege_mask );
246 se_priv_copy( new_mask, &allprivs );
249 /***************************************************************************
250 check if 2 privilege bitmaps (as uint64_t) are equal
251 ****************************************************************************/
253 bool se_priv_equal( const uint64_t *privilege_mask1, const uint64_t *privilege_mask2 )
255 return *privilege_mask1 == *privilege_mask2;
258 /***************************************************************************
259 check if a uint64_t has any assigned privileges
260 ****************************************************************************/
262 static bool se_priv_empty( const uint64_t *privilege_mask )
266 se_priv_copy( &p1, privilege_mask );
270 return se_priv_equal( &p1, &se_priv_none );
273 /*********************************************************************
274 Lookup the uint64_t bitmask value for a privilege name
275 *********************************************************************/
277 bool se_priv_from_name( const char *name, uint64_t *privilege_mask )
281 uint32_t num_privs = ARRAY_SIZE(privs);
283 for ( i=0; i<num_privs; i++ ) {
284 if ( strequal( privs[i].name, name ) ) {
285 se_priv_copy( privilege_mask, &privs[i].privilege_mask );
293 /****************************************************************************
294 check if the privilege (by bitmask) is in the privilege list
295 ****************************************************************************/
297 bool is_privilege_assigned(const uint64_t *privileges,
298 const uint64_t *check)
302 if ( !privileges || !check )
305 /* everyone has privileges if you aren't checking for any */
307 if ( se_priv_empty( check ) ) {
308 DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
312 se_priv_copy( &p1, check );
314 /* invert the uint64_t we want to check for and remove that from the
315 original set. If we are left with the uint64_t we are checking
316 for then return true */
318 se_priv_invert( &p1, check );
319 se_priv_copy( &p2, privileges );
320 se_priv_remove( &p2, &p1 );
322 return se_priv_equal( &p2, check );
325 /****************************************************************************
326 check if the any of the privileges (by bitmask) is in the privilege list
327 ****************************************************************************/
329 static bool is_any_privilege_assigned( uint64_t *privileges, const uint64_t *check )
333 if ( !privileges || !check )
336 /* everyone has privileges if you aren't checking for any */
338 if ( se_priv_empty( check ) ) {
339 DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
343 se_priv_copy( &p1, check );
345 /* invert the uint64_t we want to check for and remove that from the
346 original set. If we are left with the uint64_t we are checking
347 for then return true */
349 se_priv_invert( &p1, check );
350 se_priv_copy( &p2, privileges );
351 se_priv_remove( &p2, &p1 );
353 /* see if we have any bits left */
355 return !se_priv_empty( &p2 );
358 /*********************************************************************
359 Generate the struct lsa_LUIDAttribute structure based on a bitmask
360 *********************************************************************/
362 const char* get_privilege_dispname( const char *name )
366 uint32_t num_privs = ARRAY_SIZE(privs);
372 for ( i=0; i<num_privs; i++ ) {
373 if ( strequal( privs[i].name, name ) ) {
374 return privs[i].description;
381 /****************************************************************************
382 initialise a privilege list and set the talloc context
383 ****************************************************************************/
385 /****************************************************************************
386 Does the user have the specified privilege ? We only deal with one privilege
388 *****************************************************************************/
390 bool user_has_privileges(const struct security_token *token, const uint64_t *privilege_bit)
395 return is_privilege_assigned( &token->privilege_mask, privilege_bit );
398 /****************************************************************************
399 Does the user have any of the specified privileges ? We only deal with one privilege
401 *****************************************************************************/
403 bool user_has_any_privilege(struct security_token *token, const uint64_t *privilege_mask)
408 return is_any_privilege_assigned( &token->privilege_mask, privilege_mask );
411 /*******************************************************************
412 return the number of elements in the 'short' privlege array (traditional source3 behaviour)
413 *******************************************************************/
415 int num_privileges_in_short_list( void )
417 return NUM_SHORT_LIST_PRIVS;
420 /****************************************************************************
421 add a privilege to a privilege array
422 ****************************************************************************/
424 static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set)
426 struct lsa_LUIDAttribute *new_set;
428 /* we can allocate memory to add the new privilege */
430 new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1);
432 DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
436 new_set[priv_set->count].luid.high = set.luid.high;
437 new_set[priv_set->count].luid.low = set.luid.low;
438 new_set[priv_set->count].attribute = set.attribute;
441 priv_set->set = new_set;
446 /*******************************************************************
447 *******************************************************************/
449 bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t privilege_mask )
452 uint32_t num_privs = ARRAY_SIZE(privs);
453 struct lsa_LUIDAttribute luid;
458 for ( i=0; i<num_privs; i++ ) {
459 if ((privilege_mask & privs[i].privilege_mask) == 0)
463 luid.luid.low = privs[i].luid;
465 if ( !privilege_set_add( set, luid ) )
472 /*******************************************************************
473 *******************************************************************/
475 bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset )
479 ZERO_STRUCTP( privilege_mask );
481 for ( i=0; i<privset->count; i++ ) {
484 /* sanity check for invalid privilege. we really
485 only care about the low 32 bits */
487 if ( privset->set[i].luid.high != 0 )
490 r = sec_privilege_mask(privset->set[i].luid.low);
492 *privilege_mask |= r;
500 map a privilege id to the wire string constant
502 const char *sec_privilege_name(enum sec_privilege privilege)
505 for (i=0;i<ARRAY_SIZE(privs);i++) {
506 if (privs[i].luid == privilege) {
507 return privs[i].name;
514 map a privilege id to a privilege display name. Return NULL if not found
516 TODO: this should use language mappings
518 const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language)
521 if (privilege < 1 || privilege > 64) {
524 for (i=0;i<ARRAY_SIZE(privs);i++) {
525 if (privs[i].luid == privilege) {
526 return privs[i].description;
533 map a privilege name to a privilege id. Return -1 if not found
535 enum sec_privilege sec_privilege_id(const char *name)
538 for (i=0;i<ARRAY_SIZE(privs);i++) {
539 if (strcasecmp(privs[i].name, name) == 0) {
540 return privs[i].luid;
547 map a privilege name to a privilege id. Return -1 if not found
549 enum sec_privilege sec_privilege_from_mask(uint64_t mask)
552 for (i=0;i<ARRAY_SIZE(privs);i++) {
553 if (privs[i].privilege_mask == mask) {
554 return privs[i].luid;
561 assist in walking the table of privileges - return the LUID (low 32 bits) by index
563 enum sec_privilege sec_privilege_from_index(int idx)
565 if (idx >= 0 && idx<ARRAY_SIZE(privs)) {
566 return privs[idx].luid;
572 assist in walking the table of privileges - return the string constant by index
574 const char *sec_privilege_name_from_index(int idx)
576 if (idx >= 0 && idx<ARRAY_SIZE(privs)) {
577 return privs[idx].name;
584 return a privilege mask given a privilege id
586 static uint64_t sec_privilege_mask(enum sec_privilege privilege)
589 for (i=0;i<ARRAY_SIZE(privs);i++) {
590 if (privs[i].luid == privilege) {
591 return privs[i].privilege_mask;
600 return true if a security_token has a particular privilege bit set
602 bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege)
606 mask = sec_privilege_mask(privilege);
611 if (token->privilege_mask & mask) {
618 set a bit in the privilege mask
620 void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege)
622 /* Relies on the fact that an invalid privilage will return 0, so won't change this */
623 token->privilege_mask |= sec_privilege_mask(privilege);
626 void security_token_debug_privileges(int dbg_lev, const struct security_token *token)
628 DEBUGADD(dbg_lev, (" Privileges (0x%16llX):\n",
629 (unsigned long long) token->privilege_mask));
631 if (token->privilege_mask) {
634 for (idx = 0; idx<ARRAY_SIZE(privs); idx++) {
635 if (token->privilege_mask & privs[idx].privilege_mask) {
636 DEBUGADD(dbg_lev, (" Privilege[%3lu]: %s\n", (unsigned long)i++,