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;
57 #if 0 /* usrmgr will display these twice if you include them. We don't
58 use them but we'll keep the bitmasks reserved in privileges.h anyways */
60 {0x0, SE_NETWORK_LOGON, "SeNetworkLogonRight", "Access this computer from network"},
61 {0x0, SE_INTERACTIVE_LOGON, "SeInteractiveLogonRight", "Log on locally"},
62 {0x0, SE_BATCH_LOGON, "SeBatchLogonRight", "Log on as a batch job"},
63 {0x0, SE_SERVICE_LOGON, "SeServiceLogonRight", "Log on as a service"},
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"},
77 /***************************************************************************
78 copy an uint64_t privilege bitmap
79 ****************************************************************************/
81 bool se_priv_copy( uint64_t *dst, const uint64_t *src )
91 /***************************************************************************
92 put all valid privileges into a mask
93 ****************************************************************************/
95 bool se_priv_put_all_privileges(uint64_t *privilege_mask)
98 uint32_t num_privs = ARRAY_SIZE(privs);
100 if (!se_priv_copy(privilege_mask, &se_priv_none)) {
103 for ( i=0; i<num_privs; i++ ) {
104 se_priv_add(privilege_mask, &privs[i].privilege_mask);
109 /***************************************************************************
110 combine 2 uint64_t privilege bitmaps and store the resulting set in new_mask
111 ****************************************************************************/
113 void se_priv_add( uint64_t *privilege_mask, const uint64_t *addpriv )
115 *privilege_mask |= *addpriv;
118 /***************************************************************************
119 remove one uint64_t privileges bitmap from another and store the resulting set
121 ****************************************************************************/
123 void se_priv_remove( uint64_t *privilege_mask, const uint64_t *removepriv )
125 *privilege_mask &= ~*removepriv;
128 /***************************************************************************
129 invert a given uint64_t and store the set in new_mask
130 ****************************************************************************/
132 static void se_priv_invert( uint64_t *new_mask, const uint64_t *privilege_mask )
136 se_priv_copy( &allprivs, &se_priv_all );
137 se_priv_remove( &allprivs, privilege_mask );
138 se_priv_copy( new_mask, &allprivs );
141 /***************************************************************************
142 check if 2 privilege bitmaps (as uint64_t) are equal
143 ****************************************************************************/
145 bool se_priv_equal( const uint64_t *privilege_mask1, const uint64_t *privilege_mask2 )
147 return *privilege_mask1 == *privilege_mask2;
150 /***************************************************************************
151 check if a uint64_t has any assigned privileges
152 ****************************************************************************/
154 static bool se_priv_empty( const uint64_t *privilege_mask )
158 se_priv_copy( &p1, privilege_mask );
162 return se_priv_equal( &p1, &se_priv_none );
165 /*********************************************************************
166 Lookup the uint64_t bitmask value for a privilege name
167 *********************************************************************/
169 bool se_priv_from_name( const char *name, uint64_t *privilege_mask )
173 uint32_t num_privs = ARRAY_SIZE(privs);
175 for ( i=0; i<num_privs; i++ ) {
176 if ( strequal( privs[i].name, name ) ) {
177 se_priv_copy( privilege_mask, &privs[i].privilege_mask );
185 /****************************************************************************
186 check if the privilege (by bitmask) is in the privilege list
187 ****************************************************************************/
189 bool is_privilege_assigned(const uint64_t *privileges,
190 const uint64_t *check)
194 if ( !privileges || !check )
197 /* everyone has privileges if you aren't checking for any */
199 if ( se_priv_empty( check ) ) {
200 DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
204 se_priv_copy( &p1, check );
206 /* invert the uint64_t we want to check for and remove that from the
207 original set. If we are left with the uint64_t we are checking
208 for then return true */
210 se_priv_invert( &p1, check );
211 se_priv_copy( &p2, privileges );
212 se_priv_remove( &p2, &p1 );
214 return se_priv_equal( &p2, check );
217 /****************************************************************************
218 check if the any of the privileges (by bitmask) is in the privilege list
219 ****************************************************************************/
221 static bool is_any_privilege_assigned( uint64_t *privileges, const uint64_t *check )
225 if ( !privileges || !check )
228 /* everyone has privileges if you aren't checking for any */
230 if ( se_priv_empty( check ) ) {
231 DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
235 se_priv_copy( &p1, check );
237 /* invert the uint64_t we want to check for and remove that from the
238 original set. If we are left with the uint64_t we are checking
239 for then return true */
241 se_priv_invert( &p1, check );
242 se_priv_copy( &p2, privileges );
243 se_priv_remove( &p2, &p1 );
245 /* see if we have any bits left */
247 return !se_priv_empty( &p2 );
250 /*********************************************************************
251 Generate the struct lsa_LUIDAttribute structure based on a bitmask
252 *********************************************************************/
254 const char* get_privilege_dispname( const char *name )
258 uint32_t num_privs = ARRAY_SIZE(privs);
264 for ( i=0; i<num_privs; i++ ) {
265 if ( strequal( privs[i].name, name ) ) {
266 return privs[i].description;
273 /****************************************************************************
274 initialise a privilege list and set the talloc context
275 ****************************************************************************/
277 /****************************************************************************
278 Does the user have the specified privilege ? We only deal with one privilege
280 *****************************************************************************/
282 bool user_has_privileges(const struct security_token *token, const uint64_t *privilege_bit)
287 return is_privilege_assigned( &token->privilege_mask, privilege_bit );
290 /****************************************************************************
291 Does the user have any of the specified privileges ? We only deal with one privilege
293 *****************************************************************************/
295 bool user_has_any_privilege(struct security_token *token, const uint64_t *privilege_mask)
300 return is_any_privilege_assigned( &token->privilege_mask, privilege_mask );
303 /*******************************************************************
304 return the number of elements in the privlege array
305 *******************************************************************/
307 int count_all_privileges( void )
309 return ARRAY_SIZE(privs);
313 /*********************************************************************
314 Generate the struct lsa_LUIDAttribute structure based on a bitmask
315 The assumption here is that the privilege has already been validated
316 so we are guaranteed to find it in the list.
317 *********************************************************************/
319 enum sec_privilege get_privilege_luid( uint64_t *privilege_mask )
323 uint32_t num_privs = ARRAY_SIZE(privs);
325 for ( i=0; i<num_privs; i++ ) {
326 if ( se_priv_equal( &privs[i].privilege_mask, privilege_mask ) ) {
327 return privs[i].luid;
334 /****************************************************************************
335 Convert a LUID to a named string
336 ****************************************************************************/
338 const char *luid_to_privilege_name(const struct lsa_LUID *set)
342 uint32_t num_privs = ARRAY_SIZE(privs);
347 for ( i=0; i<num_privs; i++ ) {
348 if ( set->low == privs[i].luid ) {
349 return privs[i].name;
357 /****************************************************************************
358 add a privilege to a privilege array
359 ****************************************************************************/
361 static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set)
363 struct lsa_LUIDAttribute *new_set;
365 /* we can allocate memory to add the new privilege */
367 new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1);
369 DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
373 new_set[priv_set->count].luid.high = set.luid.high;
374 new_set[priv_set->count].luid.low = set.luid.low;
375 new_set[priv_set->count].attribute = set.attribute;
378 priv_set->set = new_set;
383 /*******************************************************************
384 *******************************************************************/
386 bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t *privilege_mask )
389 uint32_t num_privs = ARRAY_SIZE(privs);
390 struct lsa_LUIDAttribute luid;
395 for ( i=0; i<num_privs; i++ ) {
396 if ( !is_privilege_assigned(privilege_mask, &privs[i].privilege_mask) )
400 luid.luid.low = privs[i].luid;
402 if ( !privilege_set_add( set, luid ) )
409 /*******************************************************************
410 *******************************************************************/
412 static bool luid_to_se_priv( struct lsa_LUID *luid, uint64_t *privilege_mask )
415 uint32_t num_privs = ARRAY_SIZE(privs);
417 for ( i=0; i<num_privs; i++ ) {
418 if ( luid->low == privs[i].luid ) {
419 se_priv_copy( privilege_mask, &privs[i].privilege_mask );
427 /*******************************************************************
428 *******************************************************************/
430 bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset )
434 ZERO_STRUCTP( privilege_mask );
436 for ( i=0; i<privset->count; i++ ) {
439 /* sanity check for invalid privilege. we really
440 only care about the low 32 bits */
442 if ( privset->set[i].luid.high != 0 )
445 if ( luid_to_se_priv( &privset->set[i].luid, &r ) )
446 se_priv_add( privilege_mask, &r );
452 static const PRIVS privilege_names[] = {
455 "SeSecurityPrivilege",
461 "Backup files and directories"},
465 "SeRestorePrivilege",
466 "Restore files and directories"},
468 {SEC_PRIV_SYSTEMTIME,
470 "SeSystemtimePrivilege",
471 "Set the system clock"},
475 "SeShutdownPrivilege",
476 "Shutdown the system"},
478 {SEC_PRIV_REMOTE_SHUTDOWN,
480 "SeRemoteShutdownPrivilege",
481 "Shutdown the system remotely"},
483 {SEC_PRIV_TAKE_OWNERSHIP,
485 "SeTakeOwnershipPrivilege",
486 "Take ownership of files and directories"},
493 {SEC_PRIV_SYSTEM_ENVIRONMENT,
494 SE_SYSTEM_ENVIRONMENT,
495 "SeSystemEnvironmentPrivilege",
496 "Modify system environment"},
498 {SEC_PRIV_SYSTEM_PROFILE,
500 "SeSystemProfilePrivilege",
501 "Profile the system"},
503 {SEC_PRIV_PROFILE_SINGLE_PROCESS,
504 SE_PROFILE_SINGLE_PROCESS,
505 "SeProfileSingleProcessPrivilege",
506 "Profile one process"},
508 {SEC_PRIV_INCREASE_BASE_PRIORITY,
509 SE_INCREASE_BASE_PRIORITY,
510 "SeIncreaseBasePriorityPrivilege",
511 "Increase base priority"},
513 {SEC_PRIV_LOAD_DRIVER,
515 "SeLoadDriverPrivilege",
518 {SEC_PRIV_CREATE_PAGEFILE,
520 "SeCreatePagefilePrivilege",
521 "Create page files"},
523 {SEC_PRIV_INCREASE_QUOTA,
525 "SeIncreaseQuotaPrivilege",
528 {SEC_PRIV_CHANGE_NOTIFY,
530 "SeChangeNotifyPrivilege",
531 "Register for change notify"},
538 {SEC_PRIV_MANAGE_VOLUME,
540 "SeManageVolumePrivilege",
541 "Manage system volumes"},
543 {SEC_PRIV_IMPERSONATE,
545 "SeImpersonatePrivilege",
546 "Impersonate users"},
548 {SEC_PRIV_CREATE_GLOBAL,
550 "SeCreateGlobalPrivilege",
553 {SEC_PRIV_ENABLE_DELEGATION,
554 SE_ENABLE_DELEGATION,
555 "SeEnableDelegationPrivilege",
556 "Enable Delegation"},
558 {SEC_PRIV_INTERACTIVE_LOGON,
559 SE_INTERACTIVE_LOGON,
560 "SeInteractiveLogonRight",
561 "Interactive logon"},
563 {SEC_PRIV_NETWORK_LOGON,
565 "SeNetworkLogonRight",
568 {SEC_PRIV_REMOTE_INTERACTIVE_LOGON,
569 SE_REMOTE_INTERACTIVE_LOGON,
570 "SeRemoteInteractiveLogonRight",
571 "Remote Interactive logon"},
573 {SEC_PRIV_MACHINE_ACCOUNT,
575 "SeMachineAccountPrivilege",
576 "Add workstations to domain"},
578 /* These last 3 are Samba only */
579 {SEC_PRIV_PRINT_OPERATOR,
581 "SePrintOperatorPrivilege",
586 "SeAddUsersPrivilege",
587 "Add users and groups to the domain"},
589 {SEC_PRIV_DISK_OPERATOR,
591 "SeDiskOperatorPrivilege",
592 "Manage disk shares"},
597 map a privilege id to the wire string constant
599 const char *sec_privilege_name(enum sec_privilege privilege)
602 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
603 if (privilege_names[i].luid == privilege) {
604 return privilege_names[i].name;
611 map a privilege id to a privilege display name. Return NULL if not found
613 TODO: this should use language mappings
615 const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language)
618 if (privilege < 1 || privilege > 64) {
621 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
622 if (privilege_names[i].luid == privilege) {
623 return privilege_names[i].description;
630 map a privilege name to a privilege id. Return -1 if not found
632 enum sec_privilege sec_privilege_id(const char *name)
635 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
636 if (strcasecmp(privilege_names[i].name, name) == 0) {
637 return privilege_names[i].luid;
644 map a privilege name to a privilege id. Return -1 if not found
646 enum sec_privilege sec_privilege_from_mask(uint64_t mask)
649 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
650 if (privilege_names[i].privilege_mask == mask) {
651 return privilege_names[i].luid;
658 map a privilege name to a privilege id. Return -1 if not found
660 enum sec_privilege sec_privilege_from_index(int idx)
662 if (idx >= 0 && idx<ARRAY_SIZE(privilege_names)) {
663 return privilege_names[idx].luid;
670 return a privilege mask given a privilege id
672 static uint64_t sec_privilege_mask(enum sec_privilege privilege)
675 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
676 if (privilege_names[i].luid == privilege) {
677 return privilege_names[i].privilege_mask;
686 return true if a security_token has a particular privilege bit set
688 bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege)
692 mask = sec_privilege_mask(privilege);
697 if (token->privilege_mask & mask) {
704 set a bit in the privilege mask
706 void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege)
708 /* Relies on the fact that an invalid privilage will return 0, so won't change this */
709 token->privilege_mask |= sec_privilege_mask(privilege);
712 void security_token_debug_privileges(int dbg_lev, const struct security_token *token)
714 DEBUGADD(dbg_lev, (" Privileges (0x%16llX):\n",
715 (unsigned long long) token->privilege_mask));
717 if (token->privilege_mask) {
720 for (mask = 1; mask != 0; mask = mask << 1) {
721 if (token->privilege_mask & mask) {
722 enum sec_privilege privilege = sec_privilege_from_mask(mask);
723 DEBUGADD(dbg_lev, (" Privilege[%3lu]: %s\n", (unsigned long)i++,
724 sec_privilege_name(privilege)));