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 #if 0 /* usrmgr will display these twice if you include them. We don't
60 use them but we'll keep the bitmasks reserved in privileges.h anyways */
62 {0x0, SE_NETWORK_LOGON, "SeNetworkLogonRight", "Access this computer from network"},
63 {0x0, SE_INTERACTIVE_LOGON, "SeInteractiveLogonRight", "Log on locally"},
64 {0x0, SE_BATCH_LOGON, "SeBatchLogonRight", "Log on as a batch job"},
65 {0x0, SE_SERVICE_LOGON, "SeServiceLogonRight", "Log on as a service"},
67 {SEC_PRIV_MACHINE_ACCOUNT, SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Add machines to domain"},
68 {SEC_PRIV_TAKE_OWNERSHIP, SE_TAKE_OWNERSHIP, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects"},
69 {SEC_PRIV_BACKUP, SE_BACKUP, "SeBackupPrivilege", "Back up files and directories"},
70 {SEC_PRIV_RESTORE, SE_RESTORE, "SeRestorePrivilege", "Restore files and directories"},
71 {SEC_PRIV_REMOTE_SHUTDOWN, SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system"},
73 {SEC_PRIV_PRINT_OPERATOR, SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Manage printers"},
74 {SEC_PRIV_ADD_USERS, SE_ADD_USERS, "SeAddUsersPrivilege", "Add users and groups to the domain"},
75 {SEC_PRIV_DISK_OPERATOR, SE_DISK_OPERATOR, "SeDiskOperatorPrivilege", "Manage disk shares"},
79 /***************************************************************************
80 copy an uint64_t privilege bitmap
81 ****************************************************************************/
83 bool se_priv_copy( uint64_t *dst, const uint64_t *src )
93 /***************************************************************************
94 put all valid privileges into a mask
95 ****************************************************************************/
97 bool se_priv_put_all_privileges(uint64_t *privilege_mask)
100 uint32_t num_privs = ARRAY_SIZE(privs);
102 if (!se_priv_copy(privilege_mask, &se_priv_none)) {
105 for ( i=0; i<num_privs; i++ ) {
106 se_priv_add(privilege_mask, &privs[i].privilege_mask);
111 /***************************************************************************
112 combine 2 uint64_t privilege bitmaps and store the resulting set in new_mask
113 ****************************************************************************/
115 void se_priv_add( uint64_t *privilege_mask, const uint64_t *addpriv )
117 *privilege_mask |= *addpriv;
120 /***************************************************************************
121 remove one uint64_t privileges bitmap from another and store the resulting set
123 ****************************************************************************/
125 void se_priv_remove( uint64_t *privilege_mask, const uint64_t *removepriv )
127 *privilege_mask &= ~*removepriv;
130 /***************************************************************************
131 invert a given uint64_t and store the set in new_mask
132 ****************************************************************************/
134 static void se_priv_invert( uint64_t *new_mask, const uint64_t *privilege_mask )
138 se_priv_copy( &allprivs, &se_priv_all );
139 se_priv_remove( &allprivs, privilege_mask );
140 se_priv_copy( new_mask, &allprivs );
143 /***************************************************************************
144 check if 2 privilege bitmaps (as uint64_t) are equal
145 ****************************************************************************/
147 bool se_priv_equal( const uint64_t *privilege_mask1, const uint64_t *privilege_mask2 )
149 return *privilege_mask1 == *privilege_mask2;
152 /***************************************************************************
153 check if a uint64_t has any assigned privileges
154 ****************************************************************************/
156 static bool se_priv_empty( const uint64_t *privilege_mask )
160 se_priv_copy( &p1, privilege_mask );
164 return se_priv_equal( &p1, &se_priv_none );
167 /*********************************************************************
168 Lookup the uint64_t bitmask value for a privilege name
169 *********************************************************************/
171 bool se_priv_from_name( const char *name, uint64_t *privilege_mask )
175 uint32_t num_privs = ARRAY_SIZE(privs);
177 for ( i=0; i<num_privs; i++ ) {
178 if ( strequal( privs[i].name, name ) ) {
179 se_priv_copy( privilege_mask, &privs[i].privilege_mask );
187 /****************************************************************************
188 check if the privilege (by bitmask) is in the privilege list
189 ****************************************************************************/
191 bool is_privilege_assigned(const uint64_t *privileges,
192 const uint64_t *check)
196 if ( !privileges || !check )
199 /* everyone has privileges if you aren't checking for any */
201 if ( se_priv_empty( check ) ) {
202 DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
206 se_priv_copy( &p1, check );
208 /* invert the uint64_t we want to check for and remove that from the
209 original set. If we are left with the uint64_t we are checking
210 for then return true */
212 se_priv_invert( &p1, check );
213 se_priv_copy( &p2, privileges );
214 se_priv_remove( &p2, &p1 );
216 return se_priv_equal( &p2, check );
219 /****************************************************************************
220 check if the any of the privileges (by bitmask) is in the privilege list
221 ****************************************************************************/
223 static bool is_any_privilege_assigned( uint64_t *privileges, const uint64_t *check )
227 if ( !privileges || !check )
230 /* everyone has privileges if you aren't checking for any */
232 if ( se_priv_empty( check ) ) {
233 DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
237 se_priv_copy( &p1, check );
239 /* invert the uint64_t we want to check for and remove that from the
240 original set. If we are left with the uint64_t we are checking
241 for then return true */
243 se_priv_invert( &p1, check );
244 se_priv_copy( &p2, privileges );
245 se_priv_remove( &p2, &p1 );
247 /* see if we have any bits left */
249 return !se_priv_empty( &p2 );
252 /*********************************************************************
253 Generate the struct lsa_LUIDAttribute structure based on a bitmask
254 *********************************************************************/
256 const char* get_privilege_dispname( const char *name )
260 uint32_t num_privs = ARRAY_SIZE(privs);
266 for ( i=0; i<num_privs; i++ ) {
267 if ( strequal( privs[i].name, name ) ) {
268 return privs[i].description;
275 /****************************************************************************
276 initialise a privilege list and set the talloc context
277 ****************************************************************************/
279 /****************************************************************************
280 Does the user have the specified privilege ? We only deal with one privilege
282 *****************************************************************************/
284 bool user_has_privileges(const struct security_token *token, const uint64_t *privilege_bit)
289 return is_privilege_assigned( &token->privilege_mask, privilege_bit );
292 /****************************************************************************
293 Does the user have any of the specified privileges ? We only deal with one privilege
295 *****************************************************************************/
297 bool user_has_any_privilege(struct security_token *token, const uint64_t *privilege_mask)
302 return is_any_privilege_assigned( &token->privilege_mask, privilege_mask );
305 /*******************************************************************
306 return the number of elements in the privlege array
307 *******************************************************************/
309 int num_privileges_in_short_list( void )
311 return NUM_SHORT_LIST_PRIVS;
314 /*********************************************************************
315 Generate the struct lsa_LUIDAttribute structure based on a bitmask
316 The assumption here is that the privilege has already been validated
317 so we are guaranteed to find it in the list.
318 *********************************************************************/
320 enum sec_privilege get_privilege_luid( uint64_t *privilege_mask )
324 uint32_t num_privs = ARRAY_SIZE(privs);
326 for ( i=0; i<num_privs; i++ ) {
327 if ( se_priv_equal( &privs[i].privilege_mask, privilege_mask ) ) {
328 return privs[i].luid;
335 /****************************************************************************
336 Convert a LUID to a named string
337 ****************************************************************************/
339 const char *luid_to_privilege_name(const struct lsa_LUID *set)
343 uint32_t num_privs = ARRAY_SIZE(privs);
348 for ( i=0; i<num_privs; i++ ) {
349 if ( set->low == privs[i].luid ) {
350 return privs[i].name;
358 /****************************************************************************
359 add a privilege to a privilege array
360 ****************************************************************************/
362 static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set)
364 struct lsa_LUIDAttribute *new_set;
366 /* we can allocate memory to add the new privilege */
368 new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1);
370 DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
374 new_set[priv_set->count].luid.high = set.luid.high;
375 new_set[priv_set->count].luid.low = set.luid.low;
376 new_set[priv_set->count].attribute = set.attribute;
379 priv_set->set = new_set;
384 /*******************************************************************
385 *******************************************************************/
387 bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t *privilege_mask )
390 uint32_t num_privs = ARRAY_SIZE(privs);
391 struct lsa_LUIDAttribute luid;
396 for ( i=0; i<num_privs; i++ ) {
397 if ( !is_privilege_assigned(privilege_mask, &privs[i].privilege_mask) )
401 luid.luid.low = privs[i].luid;
403 if ( !privilege_set_add( set, luid ) )
410 /*******************************************************************
411 *******************************************************************/
413 static bool luid_to_se_priv( struct lsa_LUID *luid, uint64_t *privilege_mask )
416 uint32_t num_privs = ARRAY_SIZE(privs);
418 for ( i=0; i<num_privs; i++ ) {
419 if ( luid->low == privs[i].luid ) {
420 se_priv_copy( privilege_mask, &privs[i].privilege_mask );
428 /*******************************************************************
429 *******************************************************************/
431 bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset )
435 ZERO_STRUCTP( privilege_mask );
437 for ( i=0; i<privset->count; i++ ) {
440 /* sanity check for invalid privilege. we really
441 only care about the low 32 bits */
443 if ( privset->set[i].luid.high != 0 )
446 if ( luid_to_se_priv( &privset->set[i].luid, &r ) )
447 se_priv_add( privilege_mask, &r );
453 static const PRIVS privilege_names[] = {
456 "SeSecurityPrivilege",
462 "Backup files and directories"},
466 "SeRestorePrivilege",
467 "Restore files and directories"},
469 {SEC_PRIV_SYSTEMTIME,
471 "SeSystemtimePrivilege",
472 "Set the system clock"},
476 "SeShutdownPrivilege",
477 "Shutdown the system"},
479 {SEC_PRIV_REMOTE_SHUTDOWN,
481 "SeRemoteShutdownPrivilege",
482 "Shutdown the system remotely"},
484 {SEC_PRIV_TAKE_OWNERSHIP,
486 "SeTakeOwnershipPrivilege",
487 "Take ownership of files and directories"},
494 {SEC_PRIV_SYSTEM_ENVIRONMENT,
495 SE_SYSTEM_ENVIRONMENT,
496 "SeSystemEnvironmentPrivilege",
497 "Modify system environment"},
499 {SEC_PRIV_SYSTEM_PROFILE,
501 "SeSystemProfilePrivilege",
502 "Profile the system"},
504 {SEC_PRIV_PROFILE_SINGLE_PROCESS,
505 SE_PROFILE_SINGLE_PROCESS,
506 "SeProfileSingleProcessPrivilege",
507 "Profile one process"},
509 {SEC_PRIV_INCREASE_BASE_PRIORITY,
510 SE_INCREASE_BASE_PRIORITY,
511 "SeIncreaseBasePriorityPrivilege",
512 "Increase base priority"},
514 {SEC_PRIV_LOAD_DRIVER,
516 "SeLoadDriverPrivilege",
519 {SEC_PRIV_CREATE_PAGEFILE,
521 "SeCreatePagefilePrivilege",
522 "Create page files"},
524 {SEC_PRIV_INCREASE_QUOTA,
526 "SeIncreaseQuotaPrivilege",
529 {SEC_PRIV_CHANGE_NOTIFY,
531 "SeChangeNotifyPrivilege",
532 "Register for change notify"},
539 {SEC_PRIV_MANAGE_VOLUME,
541 "SeManageVolumePrivilege",
542 "Manage system volumes"},
544 {SEC_PRIV_IMPERSONATE,
546 "SeImpersonatePrivilege",
547 "Impersonate users"},
549 {SEC_PRIV_CREATE_GLOBAL,
551 "SeCreateGlobalPrivilege",
554 {SEC_PRIV_ENABLE_DELEGATION,
555 SE_ENABLE_DELEGATION,
556 "SeEnableDelegationPrivilege",
557 "Enable Delegation"},
559 {SEC_PRIV_INTERACTIVE_LOGON,
560 SE_INTERACTIVE_LOGON,
561 "SeInteractiveLogonRight",
562 "Interactive logon"},
564 {SEC_PRIV_NETWORK_LOGON,
566 "SeNetworkLogonRight",
569 {SEC_PRIV_REMOTE_INTERACTIVE_LOGON,
570 SE_REMOTE_INTERACTIVE_LOGON,
571 "SeRemoteInteractiveLogonRight",
572 "Remote Interactive logon"},
574 {SEC_PRIV_MACHINE_ACCOUNT,
576 "SeMachineAccountPrivilege",
577 "Add workstations to domain"},
579 /* These last 3 are Samba only */
580 {SEC_PRIV_PRINT_OPERATOR,
582 "SePrintOperatorPrivilege",
587 "SeAddUsersPrivilege",
588 "Add users and groups to the domain"},
590 {SEC_PRIV_DISK_OPERATOR,
592 "SeDiskOperatorPrivilege",
593 "Manage disk shares"},
598 map a privilege id to the wire string constant
600 const char *sec_privilege_name(enum sec_privilege privilege)
603 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
604 if (privilege_names[i].luid == privilege) {
605 return privilege_names[i].name;
612 map a privilege id to a privilege display name. Return NULL if not found
614 TODO: this should use language mappings
616 const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language)
619 if (privilege < 1 || privilege > 64) {
622 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
623 if (privilege_names[i].luid == privilege) {
624 return privilege_names[i].description;
631 map a privilege name to a privilege id. Return -1 if not found
633 enum sec_privilege sec_privilege_id(const char *name)
636 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
637 if (strcasecmp(privilege_names[i].name, name) == 0) {
638 return privilege_names[i].luid;
645 map a privilege name to a privilege id. Return -1 if not found
647 enum sec_privilege sec_privilege_from_mask(uint64_t mask)
650 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
651 if (privilege_names[i].privilege_mask == mask) {
652 return privilege_names[i].luid;
659 map a privilege name to a privilege id. Return -1 if not found
661 enum sec_privilege sec_privilege_from_index(int idx)
663 if (idx >= 0 && idx<ARRAY_SIZE(privilege_names)) {
664 return privilege_names[idx].luid;
671 return a privilege mask given a privilege id
673 static uint64_t sec_privilege_mask(enum sec_privilege privilege)
676 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
677 if (privilege_names[i].luid == privilege) {
678 return privilege_names[i].privilege_mask;
687 return true if a security_token has a particular privilege bit set
689 bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege)
693 mask = sec_privilege_mask(privilege);
698 if (token->privilege_mask & mask) {
705 set a bit in the privilege mask
707 void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege)
709 /* Relies on the fact that an invalid privilage will return 0, so won't change this */
710 token->privilege_mask |= sec_privilege_mask(privilege);
713 void security_token_debug_privileges(int dbg_lev, const struct security_token *token)
715 DEBUGADD(dbg_lev, (" Privileges (0x%16llX):\n",
716 (unsigned long long) token->privilege_mask));
718 if (token->privilege_mask) {
721 for (mask = 1; mask != 0; mask = mask << 1) {
722 if (token->privilege_mask & mask) {
723 enum sec_privilege privilege = sec_privilege_from_mask(mask);
724 DEBUGADD(dbg_lev, (" Privilege[%3lu]: %s\n", (unsigned long)i++,
725 sec_privilege_name(privilege)));