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;
43 static const uint64_t se_priv_end = SE_END;
45 /* Define variables for all privileges so we can use the
46 uint64_t* in the various se_priv_XXX() functions */
48 const uint64_t se_priv_none = SE_NONE;
49 const uint64_t se_machine_account = SE_MACHINE_ACCOUNT;
50 const uint64_t se_print_operator = SE_PRINT_OPERATOR;
51 const uint64_t se_add_users = SE_ADD_USERS;
52 const uint64_t se_disk_operators = SE_DISK_OPERATOR;
53 const uint64_t se_remote_shutdown = SE_REMOTE_SHUTDOWN;
54 const uint64_t se_restore = SE_RESTORE;
55 const uint64_t se_take_ownership = SE_TAKE_OWNERSHIP;
58 #if 0 /* usrmgr will display these twice if you include them. We don't
59 use them but we'll keep the bitmasks reserved in privileges.h anyways */
61 {0x0, SE_NETWORK_LOGON, "SeNetworkLogonRight", "Access this computer from network"},
62 {0x0, SE_INTERACTIVE_LOGON, "SeInteractiveLogonRight", "Log on locally"},
63 {0x0, SE_BATCH_LOGON, "SeBatchLogonRight", "Log on as a batch job"},
64 {0x0, SE_SERVICE_LOGON, "SeServiceLogonRight", "Log on as a service"},
66 {SEC_PRIV_MACHINE_ACCOUNT, SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Add machines to domain"},
67 {SEC_PRIV_TAKE_OWNERSHIP, SE_TAKE_OWNERSHIP, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects"},
68 {SEC_PRIV_BACKUP, SE_BACKUP, "SeBackupPrivilege", "Back up files and directories"},
69 {SEC_PRIV_RESTORE, SE_RESTORE, "SeRestorePrivilege", "Restore files and directories"},
70 {SEC_PRIV_REMOTE_SHUTDOWN, SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system"},
72 {SEC_PRIV_PRINT_OPERATOR, SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Manage printers"},
73 {SEC_PRIV_ADD_USERS, SE_ADD_USERS, "SeAddUsersPrivilege", "Add users and groups to the domain"},
74 {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 )
88 memcpy( dst, src, sizeof(uint64_t) );
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 = count_all_privileges();
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 for ( i=0; !se_priv_equal(&privs[i].privilege_mask, &se_priv_end); 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 )
262 for ( i=0; !se_priv_equal(&privs[i].privilege_mask, &se_priv_end); i++ ) {
264 if ( strequal( privs[i].name, name ) ) {
265 return privs[i].description;
272 /****************************************************************************
273 initialise a privilege list and set the talloc context
274 ****************************************************************************/
276 /****************************************************************************
277 Does the user have the specified privilege ? We only deal with one privilege
279 *****************************************************************************/
281 bool user_has_privileges(const struct security_token *token, const uint64_t *privilege_bit)
286 return is_privilege_assigned( &token->privilege_mask, privilege_bit );
289 /****************************************************************************
290 Does the user have any of the specified privileges ? We only deal with one privilege
292 *****************************************************************************/
294 bool user_has_any_privilege(struct security_token *token, const uint64_t *privilege_mask)
299 return is_any_privilege_assigned( &token->privilege_mask, privilege_mask );
302 /*******************************************************************
303 return the number of elements in the privlege array
304 *******************************************************************/
306 int count_all_privileges( void )
309 * The -1 is due to the weird SE_END record...
311 return (sizeof(privs) / sizeof(privs[0])) - 1;
315 /*********************************************************************
316 Generate the struct lsa_LUIDAttribute structure based on a bitmask
317 The assumption here is that the privilege has already been validated
318 so we are guaranteed to find it in the list.
319 *********************************************************************/
321 struct lsa_LUIDAttribute get_privilege_luid( uint64_t *privilege_mask )
323 struct lsa_LUIDAttribute priv_luid;
326 ZERO_STRUCT( priv_luid );
328 for ( i=0; !se_priv_equal(&privs[i].privilege_mask, &se_priv_end); i++ ) {
330 if ( se_priv_equal( &privs[i].privilege_mask, privilege_mask ) ) {
331 priv_luid.luid.low = privs[i].luid;
332 priv_luid.luid.high = 0;
340 /****************************************************************************
341 Convert a LUID to a named string
342 ****************************************************************************/
344 const char *luid_to_privilege_name(const struct lsa_LUID *set)
351 for ( i=0; !se_priv_equal(&privs[i].privilege_mask, &se_priv_end); i++ ) {
352 if ( set->low == privs[i].luid ) {
353 return privs[i].name;
361 /****************************************************************************
362 add a privilege to a privilege array
363 ****************************************************************************/
365 static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set)
367 struct lsa_LUIDAttribute *new_set;
369 /* we can allocate memory to add the new privilege */
371 new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1);
373 DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
377 new_set[priv_set->count].luid.high = set.luid.high;
378 new_set[priv_set->count].luid.low = set.luid.low;
379 new_set[priv_set->count].attribute = set.attribute;
382 priv_set->set = new_set;
387 /*******************************************************************
388 *******************************************************************/
390 bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t *privilege_mask )
393 uint32_t num_privs = count_all_privileges();
394 struct lsa_LUIDAttribute luid;
399 for ( i=0; i<num_privs; i++ ) {
400 if ( !is_privilege_assigned(privilege_mask, &privs[i].privilege_mask) )
404 luid.luid.low = privs[i].luid;
406 if ( !privilege_set_add( set, luid ) )
413 /*******************************************************************
414 *******************************************************************/
416 static bool luid_to_se_priv( struct lsa_LUID *luid, uint64_t *privilege_mask )
419 uint32_t num_privs = count_all_privileges();
421 for ( i=0; i<num_privs; i++ ) {
422 if ( luid->low == privs[i].luid ) {
423 se_priv_copy( privilege_mask, &privs[i].privilege_mask );
431 /*******************************************************************
432 *******************************************************************/
434 bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset )
438 ZERO_STRUCTP( privilege_mask );
440 for ( i=0; i<privset->count; i++ ) {
443 /* sanity check for invalid privilege. we really
444 only care about the low 32 bits */
446 if ( privset->set[i].luid.high != 0 )
449 if ( luid_to_se_priv( &privset->set[i].luid, &r ) )
450 se_priv_add( privilege_mask, &r );
456 static const PRIVS privilege_names[] = {
459 "SeSecurityPrivilege",
465 "Backup files and directories"},
469 "SeRestorePrivilege",
470 "Restore files and directories"},
472 {SEC_PRIV_SYSTEMTIME,
474 "SeSystemtimePrivilege",
475 "Set the system clock"},
479 "SeShutdownPrivilege",
480 "Shutdown the system"},
482 {SEC_PRIV_REMOTE_SHUTDOWN,
484 "SeRemoteShutdownPrivilege",
485 "Shutdown the system remotely"},
487 {SEC_PRIV_TAKE_OWNERSHIP,
489 "SeTakeOwnershipPrivilege",
490 "Take ownership of files and directories"},
497 {SEC_PRIV_SYSTEM_ENVIRONMENT,
498 SE_SYSTEM_ENVIRONMENT,
499 "SeSystemEnvironmentPrivilege",
500 "Modify system environment"},
502 {SEC_PRIV_SYSTEM_PROFILE,
504 "SeSystemProfilePrivilege",
505 "Profile the system"},
507 {SEC_PRIV_PROFILE_SINGLE_PROCESS,
508 SE_PROFILE_SINGLE_PROCESS,
509 "SeProfileSingleProcessPrivilege",
510 "Profile one process"},
512 {SEC_PRIV_INCREASE_BASE_PRIORITY,
513 SE_INCREASE_BASE_PRIORITY,
514 "SeIncreaseBasePriorityPrivilege",
515 "Increase base priority"},
517 {SEC_PRIV_LOAD_DRIVER,
519 "SeLoadDriverPrivilege",
522 {SEC_PRIV_CREATE_PAGEFILE,
524 "SeCreatePagefilePrivilege",
525 "Create page files"},
527 {SEC_PRIV_INCREASE_QUOTA,
529 "SeIncreaseQuotaPrivilege",
532 {SEC_PRIV_CHANGE_NOTIFY,
534 "SeChangeNotifyPrivilege",
535 "Register for change notify"},
542 {SEC_PRIV_MANAGE_VOLUME,
544 "SeManageVolumePrivilege",
545 "Manage system volumes"},
547 {SEC_PRIV_IMPERSONATE,
549 "SeImpersonatePrivilege",
550 "Impersonate users"},
552 {SEC_PRIV_CREATE_GLOBAL,
554 "SeCreateGlobalPrivilege",
557 {SEC_PRIV_ENABLE_DELEGATION,
558 SE_ENABLE_DELEGATION,
559 "SeEnableDelegationPrivilege",
560 "Enable Delegation"},
562 {SEC_PRIV_INTERACTIVE_LOGON,
563 SE_INTERACTIVE_LOGON,
564 "SeInteractiveLogonRight",
565 "Interactive logon"},
567 {SEC_PRIV_NETWORK_LOGON,
569 "SeNetworkLogonRight",
572 {SEC_PRIV_REMOTE_INTERACTIVE_LOGON,
573 SE_REMOTE_INTERACTIVE_LOGON,
574 "SeRemoteInteractiveLogonRight",
575 "Remote Interactive logon"},
577 {SEC_PRIV_MACHINE_ACCOUNT,
579 "SeMachineAccountPrivilege",
580 "Add workstations to domain"},
582 /* These last 3 are Samba only */
583 {SEC_PRIV_PRINT_OPERATOR,
585 "SePrintOperatorPrivilege",
590 "SeAddUsersPrivilege",
591 "Add users and groups to the domain"},
593 {SEC_PRIV_DISK_OPERATOR,
595 "SeDiskOperatorPrivilege",
596 "Manage disk shares"},
601 map a privilege id to the wire string constant
603 const char *sec_privilege_name(enum sec_privilege privilege)
606 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
607 if (privilege_names[i].luid == privilege) {
608 return privilege_names[i].name;
615 map a privilege id to a privilege display name. Return NULL if not found
617 TODO: this should use language mappings
619 const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language)
622 if (privilege < 1 || privilege > 64) {
625 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
626 if (privilege_names[i].luid == privilege) {
627 return privilege_names[i].description;
634 map a privilege name to a privilege id. Return -1 if not found
636 enum sec_privilege sec_privilege_id(const char *name)
639 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
640 if (strcasecmp(privilege_names[i].name, name) == 0) {
641 return privilege_names[i].luid;
648 map a privilege name to a privilege id. Return -1 if not found
650 enum sec_privilege sec_privilege_from_mask(uint64_t mask)
653 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
654 if (privilege_names[i].privilege_mask == mask) {
655 return privilege_names[i].luid;
662 map a privilege name to a privilege id. Return -1 if not found
664 enum sec_privilege sec_privilege_from_index(int idx)
666 if (idx >= 0 && idx<ARRAY_SIZE(privilege_names)) {
667 return privilege_names[idx].luid;
674 return a privilege mask given a privilege id
676 static uint64_t sec_privilege_mask(enum sec_privilege privilege)
679 for (i=0;i<ARRAY_SIZE(privilege_names);i++) {
680 if (privilege_names[i].luid == privilege) {
681 return privilege_names[i].privilege_mask;
690 return true if a security_token has a particular privilege bit set
692 bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege)
696 mask = sec_privilege_mask(privilege);
701 if (token->privilege_mask & mask) {
708 set a bit in the privilege mask
710 void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege)
712 /* Relies on the fact that an invalid privilage will return 0, so won't change this */
713 token->privilege_mask |= sec_privilege_mask(privilege);
716 void security_token_debug_privileges(int dbg_lev, const struct security_token *token)
718 DEBUGADD(dbg_lev, (" Privileges (0x%16llX):\n",
719 (unsigned long long) token->privilege_mask));
721 if (token->privilege_mask) {
724 for (mask = 1; mask != 0; mask = mask << 1) {
725 if (token->privilege_mask & mask) {
726 enum sec_privilege privilege = sec_privilege_from_mask(mask);
727 DEBUGADD(dbg_lev, (" Privilege[%3lu]: %s\n", (unsigned long)i++,
728 sec_privilege_name(privilege)));