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 struct lsa_LUIDAttribute get_privilege_luid( uint64_t *privilege_mask )
321 struct lsa_LUIDAttribute priv_luid;
324 uint32_t num_privs = ARRAY_SIZE(privs);
326 ZERO_STRUCT( priv_luid );
328 for ( i=0; i<num_privs; i++ ) {
329 if ( se_priv_equal( &privs[i].privilege_mask, privilege_mask ) ) {
330 priv_luid.luid.low = privs[i].luid;
331 priv_luid.luid.high = 0;
339 /****************************************************************************
340 Convert a LUID to a named string
341 ****************************************************************************/
343 const char *luid_to_privilege_name(const struct lsa_LUID *set)
347 uint32_t num_privs = ARRAY_SIZE(privs);
352 for ( i=0; i<num_privs; i++ ) {
353 if ( set->low == privs[i].luid ) {
354 return privs[i].name;
362 /****************************************************************************
363 add a privilege to a privilege array
364 ****************************************************************************/
366 static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set)
368 struct lsa_LUIDAttribute *new_set;
370 /* we can allocate memory to add the new privilege */
372 new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1);
374 DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
378 new_set[priv_set->count].luid.high = set.luid.high;
379 new_set[priv_set->count].luid.low = set.luid.low;
380 new_set[priv_set->count].attribute = set.attribute;
383 priv_set->set = new_set;
388 /*******************************************************************
389 *******************************************************************/
391 bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t *privilege_mask )
394 uint32_t num_privs = ARRAY_SIZE(privs);
395 struct lsa_LUIDAttribute luid;
400 for ( i=0; i<num_privs; i++ ) {
401 if ( !is_privilege_assigned(privilege_mask, &privs[i].privilege_mask) )
405 luid.luid.low = privs[i].luid;
407 if ( !privilege_set_add( set, luid ) )
414 /*******************************************************************
415 *******************************************************************/
417 static bool luid_to_se_priv( struct lsa_LUID *luid, uint64_t *privilege_mask )
420 uint32_t num_privs = ARRAY_SIZE(privs);
422 for ( i=0; i<num_privs; i++ ) {
423 if ( luid->low == privs[i].luid ) {
424 se_priv_copy( privilege_mask, &privs[i].privilege_mask );
432 /*******************************************************************
433 *******************************************************************/
435 bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset )
439 ZERO_STRUCTP( privilege_mask );
441 for ( i=0; i<privset->count; i++ ) {
444 /* sanity check for invalid privilege. we really
445 only care about the low 32 bits */
447 if ( privset->set[i].luid.high != 0 )
450 if ( luid_to_se_priv( &privset->set[i].luid, &r ) )
451 se_priv_add( privilege_mask, &r );
457 static const PRIVS privilege_names[] = {
460 "SeSecurityPrivilege",
466 "Backup files and directories"},
470 "SeRestorePrivilege",
471 "Restore files and directories"},
473 {SEC_PRIV_SYSTEMTIME,
475 "SeSystemtimePrivilege",
476 "Set the system clock"},
480 "SeShutdownPrivilege",
481 "Shutdown the system"},
483 {SEC_PRIV_REMOTE_SHUTDOWN,
485 "SeRemoteShutdownPrivilege",
486 "Shutdown the system remotely"},
488 {SEC_PRIV_TAKE_OWNERSHIP,
490 "SeTakeOwnershipPrivilege",
491 "Take ownership of files and directories"},
498 {SEC_PRIV_SYSTEM_ENVIRONMENT,
499 SE_SYSTEM_ENVIRONMENT,
500 "SeSystemEnvironmentPrivilege",
501 "Modify system environment"},
503 {SEC_PRIV_SYSTEM_PROFILE,
505 "SeSystemProfilePrivilege",
506 "Profile the system"},
508 {SEC_PRIV_PROFILE_SINGLE_PROCESS,
509 SE_PROFILE_SINGLE_PROCESS,
510 "SeProfileSingleProcessPrivilege",
511 "Profile one process"},
513 {SEC_PRIV_INCREASE_BASE_PRIORITY,
514 SE_INCREASE_BASE_PRIORITY,
515 "SeIncreaseBasePriorityPrivilege",
516 "Increase base priority"},
518 {SEC_PRIV_LOAD_DRIVER,
520 "SeLoadDriverPrivilege",
523 {SEC_PRIV_CREATE_PAGEFILE,
525 "SeCreatePagefilePrivilege",
526 "Create page files"},
528 {SEC_PRIV_INCREASE_QUOTA,
530 "SeIncreaseQuotaPrivilege",
533 {SEC_PRIV_CHANGE_NOTIFY,
535 "SeChangeNotifyPrivilege",
536 "Register for change notify"},
543 {SEC_PRIV_MANAGE_VOLUME,
545 "SeManageVolumePrivilege",
546 "Manage system volumes"},
548 {SEC_PRIV_IMPERSONATE,
550 "SeImpersonatePrivilege",
551 "Impersonate users"},
553 {SEC_PRIV_CREATE_GLOBAL,
555 "SeCreateGlobalPrivilege",
558 {SEC_PRIV_ENABLE_DELEGATION,
559 SE_ENABLE_DELEGATION,
560 "SeEnableDelegationPrivilege",
561 "Enable Delegation"},
563 {SEC_PRIV_INTERACTIVE_LOGON,
564 SE_INTERACTIVE_LOGON,
565 "SeInteractiveLogonRight",
566 "Interactive logon"},
568 {SEC_PRIV_NETWORK_LOGON,
570 "SeNetworkLogonRight",
573 {SEC_PRIV_REMOTE_INTERACTIVE_LOGON,
574 SE_REMOTE_INTERACTIVE_LOGON,
575 "SeRemoteInteractiveLogonRight",
576 "Remote Interactive logon"},
578 {SEC_PRIV_MACHINE_ACCOUNT,
580 "SeMachineAccountPrivilege",
581 "Add workstations to domain"},
583 /* These last 3 are Samba only */
584 {SEC_PRIV_PRINT_OPERATOR,
586 "SePrintOperatorPrivilege",
591 "SeAddUsersPrivilege",
592 "Add users and groups to the domain"},
594 {SEC_PRIV_DISK_OPERATOR,
596 "SeDiskOperatorPrivilege",
597 "Manage disk shares"},
602 map a privilege id to the wire string constant
604 const char *sec_privilege_name(enum sec_privilege privilege)
607 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
608 if (privilege_names[i].luid == privilege) {
609 return privilege_names[i].name;
616 map a privilege id to a privilege display name. Return NULL if not found
618 TODO: this should use language mappings
620 const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language)
623 if (privilege < 1 || privilege > 64) {
626 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
627 if (privilege_names[i].luid == privilege) {
628 return privilege_names[i].description;
635 map a privilege name to a privilege id. Return -1 if not found
637 enum sec_privilege sec_privilege_id(const char *name)
640 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
641 if (strcasecmp(privilege_names[i].name, name) == 0) {
642 return privilege_names[i].luid;
649 map a privilege name to a privilege id. Return -1 if not found
651 enum sec_privilege sec_privilege_from_mask(uint64_t mask)
654 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
655 if (privilege_names[i].privilege_mask == mask) {
656 return privilege_names[i].luid;
663 map a privilege name to a privilege id. Return -1 if not found
665 enum sec_privilege sec_privilege_from_index(int idx)
667 if (idx >= 0 && idx<ARRAY_SIZE(privilege_names)) {
668 return privilege_names[idx].luid;
675 return a privilege mask given a privilege id
677 static uint64_t sec_privilege_mask(enum sec_privilege privilege)
680 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
681 if (privilege_names[i].luid == privilege) {
682 return privilege_names[i].privilege_mask;
691 return true if a security_token has a particular privilege bit set
693 bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege)
697 mask = sec_privilege_mask(privilege);
702 if (token->privilege_mask & mask) {
709 set a bit in the privilege mask
711 void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege)
713 /* Relies on the fact that an invalid privilage will return 0, so won't change this */
714 token->privilege_mask |= sec_privilege_mask(privilege);
717 void security_token_debug_privileges(int dbg_lev, const struct security_token *token)
719 DEBUGADD(dbg_lev, (" Privileges (0x%16llX):\n",
720 (unsigned long long) token->privilege_mask));
722 if (token->privilege_mask) {
725 for (mask = 1; mask != 0; mask = mask << 1) {
726 if (token->privilege_mask & mask) {
727 enum sec_privilege privilege = sec_privilege_from_mask(mask);
728 DEBUGADD(dbg_lev, (" Privilege[%3lu]: %s\n", (unsigned long)i++,
729 sec_privilege_name(privilege)));