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
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #define PRIVPREFIX "PRIV_"
28 #define GENERATE_LUID_LOW(x) (x)+1;
30 static const SE_PRIV se_priv_all = SE_ALL_PRIVS;
31 static const SE_PRIV se_priv_end = SE_END;
33 /* Define variables for all privileges so we can use the
34 SE_PRIV* in the various se_priv_XXX() functions */
36 const SE_PRIV se_priv_none = SE_NONE;
37 const SE_PRIV se_machine_account = SE_MACHINE_ACCOUNT;
38 const SE_PRIV se_print_operator = SE_PRINT_OPERATOR;
39 const SE_PRIV se_add_users = SE_ADD_USERS;
40 const SE_PRIV se_disk_operators = SE_DISK_OPERATOR;
41 const SE_PRIV se_remote_shutdown = SE_REMOTE_SHUTDOWN;
43 /********************************************************************
44 This is a list of privileges reported by a WIndows 2000 SP4 AD DC
45 just for reference purposes:
47 SeCreateTokenPrivilege Create a token object
48 SeAssignPrimaryTokenPrivilege Replace a process level token
49 SeLockMemoryPrivilege Lock pages in memory
50 SeIncreaseQuotaPrivilege Increase quotas
51 SeMachineAccountPrivilege Add workstations to domain
52 SeTcbPrivilege Act as part of the operating system
53 SeSecurityPrivilege Manage auditing and security log
54 SeTakeOwnershipPrivilege Take ownership of files or other objects
55 SeLoadDriverPrivilege Load and unload device drivers
56 SeSystemProfilePrivilege Profile system performance
57 SeSystemtimePrivilege Change the system time
58 SeProfileSingleProcessPrivilege Profile single process
59 SeIncreaseBasePriorityPrivilege Increase scheduling priority
60 SeCreatePagefilePrivilege Create a pagefile
61 SeCreatePermanentPrivilege Create permanent shared objects
62 SeBackupPrivilege Back up files and directories
63 SeRestorePrivilege Restore files and directories
64 SeShutdownPrivilege Shut down the system
65 SeDebugPrivilege Debug programs
66 SeAuditPrivilege Generate security audits
67 SeSystemEnvironmentPrivilege Modify firmware environment values
68 SeChangeNotifyPrivilege Bypass traverse checking
69 SeRemoteShutdownPrivilege Force shutdown from a remote system
70 SeUndockPrivilege Remove computer from docking station
71 SeSyncAgentPrivilege Synchronize directory service data
72 SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation
73 SeManageVolumePrivilege Perform volume maintenance tasks
74 SeImpersonatePrivilege Impersonate a client after authentication
75 SeCreateGlobalPrivilege Create global objects
77 ********************************************************************/
81 #if 0 /* usrmgr will display these twice if you include them. We don't
82 use them but we'll keep the bitmasks reserved in privileges.h anyways */
84 {SE_NETWORK_LOGON, "SeNetworkLogonRight", "Access this computer from network"},
85 {SE_INTERACTIVE_LOGON, "SeInteractiveLogonRight", "Log on locally"},
86 {SE_BATCH_LOGON, "SeBatchLogonRight", "Log on as a batch job"},
87 {SE_SERVICE_LOGON, "SeServiceLogonRight", "Log on as a service"},
89 {SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Add machines to domain"},
90 {SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Manage printers"},
91 {SE_ADD_USERS, "SeAddUsersPrivilege", "Add users and groups to the domain"},
92 {SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system"},
93 {SE_DISK_OPERATOR, "SeDiskOperatorPrivilege", "Manage disk shares"},
98 typedef struct priv_sid_list {
104 /***************************************************************************
105 copy an SE_PRIV structure
106 ****************************************************************************/
108 BOOL se_priv_copy( SE_PRIV *dst, const SE_PRIV *src )
113 memcpy( dst, src, sizeof(SE_PRIV) );
118 /***************************************************************************
119 combine 2 SE_PRIV structures and store the resulting set in mew_mask
120 ****************************************************************************/
122 void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv )
126 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
127 mask->mask[i] |= addpriv->mask[i];
131 /***************************************************************************
132 remove one SE_PRIV sytucture from another and store the resulting set
134 ****************************************************************************/
136 void se_priv_remove( SE_PRIV *mask, const SE_PRIV *removepriv )
140 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
141 mask->mask[i] &= ~removepriv->mask[i];
145 /***************************************************************************
146 invert a given SE_PRIV and store the set in new_mask
147 ****************************************************************************/
149 static void se_priv_invert( SE_PRIV *new_mask, const SE_PRIV *mask )
153 se_priv_copy( &allprivs, &se_priv_all );
154 se_priv_remove( &allprivs, mask );
155 se_priv_copy( new_mask, &allprivs );
158 /***************************************************************************
159 check if 2 SE_PRIV structure are equal
160 ****************************************************************************/
162 static BOOL se_priv_equal( const SE_PRIV *mask1, const SE_PRIV *mask2 )
164 return ( memcmp(mask1, mask2, sizeof(SE_PRIV)) == 0 );
167 /***************************************************************************
168 check if a SE_PRIV has any assigned privileges
169 ****************************************************************************/
171 static BOOL se_priv_empty( const SE_PRIV *mask )
176 se_priv_copy( &p1, mask );
178 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
179 p1.mask[i] &= se_priv_all.mask[i];
182 return se_priv_equal( &p1, &se_priv_none );
185 /*********************************************************************
186 Lookup the SE_PRIV value for a privilege name
187 *********************************************************************/
189 BOOL se_priv_from_name( const char *name, SE_PRIV *mask )
193 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
194 if ( strequal( privs[i].name, name ) ) {
195 se_priv_copy( mask, &privs[i].se_priv );
203 /***************************************************************************
204 dump an SE_PRIV structure to the log files
205 ****************************************************************************/
207 void dump_se_priv( int dbg_cl, int dbg_lvl, const SE_PRIV *mask )
211 DEBUGADDC( dbg_cl, dbg_lvl,("SE_PRIV "));
213 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
214 DEBUGADDC( dbg_cl, dbg_lvl,(" 0x%x", mask->mask[i] ));
217 DEBUGADDC( dbg_cl, dbg_lvl, ("\n"));
220 /***************************************************************************
221 Retrieve the privilege mask (set) for a given SID
222 ****************************************************************************/
224 static BOOL get_privileges( const DOM_SID *sid, SE_PRIV *mask )
226 TDB_CONTEXT *tdb = get_account_pol_tdb();
230 /* Fail if the admin has not enable privileges */
232 if ( !lp_enable_privileges() ) {
239 /* PRIV_<SID> (NULL terminated) as the key */
241 fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
243 key.dsize = strlen(keystr) + 1;
245 data = tdb_fetch( tdb, key );
248 DEBUG(3,("get_privileges: No privileges assigned to SID [%s]\n",
249 sid_string_static(sid)));
253 SMB_ASSERT( data.dsize == sizeof( SE_PRIV ) );
255 se_priv_copy( mask, (SE_PRIV*)data.dptr );
256 SAFE_FREE(data.dptr);
261 /***************************************************************************
262 Store the privilege mask (set) for a given SID
263 ****************************************************************************/
265 static BOOL set_privileges( const DOM_SID *sid, SE_PRIV *mask )
267 TDB_CONTEXT *tdb = get_account_pol_tdb();
271 if ( !lp_enable_privileges() )
277 /* PRIV_<SID> (NULL terminated) as the key */
279 fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
281 key.dsize = strlen(keystr) + 1;
283 /* no packing. static size structure, just write it out */
285 data.dptr = (char*)mask;
286 data.dsize = sizeof(SE_PRIV);
288 return ( tdb_store(tdb, key, data, TDB_REPLACE) != -1 );
291 /****************************************************************************
292 check if the privilege is in the privilege list
293 ****************************************************************************/
295 static BOOL is_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
299 if ( !privileges || !check )
302 /* everyone has privileges if you aren't checking for any */
304 if ( se_priv_empty( check ) ) {
305 DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
309 se_priv_copy( &p1, check );
311 /* invert the SE_PRIV we want to check for and remove that from the
312 original set. If we are left with the SE_PRIV we are checking
313 for then return True */
315 se_priv_invert( &p1, check );
316 se_priv_copy( &p2, privileges );
317 se_priv_remove( &p2, &p1 );
319 return se_priv_equal( &p2, check );
322 /****************************************************************************
323 check if the privilege is in the privilege list
324 ****************************************************************************/
326 static BOOL is_any_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
330 if ( !privileges || !check )
333 /* everyone has privileges if you aren't checking for any */
335 if ( se_priv_empty( check ) ) {
336 DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
340 se_priv_copy( &p1, check );
342 /* invert the SE_PRIV we want to check for and remove that from the
343 original set. If we are left with the SE_PRIV we are checking
344 for then return True */
346 se_priv_invert( &p1, check );
347 se_priv_copy( &p2, privileges );
348 se_priv_remove( &p2, &p1 );
350 /* see if we have any bits left */
352 return !se_priv_empty( &p2 );
355 /****************************************************************************
356 add a privilege to a privilege array
357 ****************************************************************************/
359 static BOOL privilege_set_add(PRIVILEGE_SET *priv_set, LUID_ATTR set)
363 /* we can allocate memory to add the new privilege */
365 new_set = TALLOC_REALLOC_ARRAY(priv_set->mem_ctx, priv_set->set, LUID_ATTR, priv_set->count + 1);
367 DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
371 new_set[priv_set->count].luid.high = set.luid.high;
372 new_set[priv_set->count].luid.low = set.luid.low;
373 new_set[priv_set->count].attr = set.attr;
376 priv_set->set = new_set;
381 /*********************************************************************
382 Generate the LUID_ATTR structure based on a bitmask
383 *********************************************************************/
385 LUID_ATTR get_privilege_luid( SE_PRIV *mask )
391 priv_luid.luid.high = 0;
393 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
395 if ( se_priv_equal( &privs[i].se_priv, mask ) ) {
396 priv_luid.luid.low = GENERATE_LUID_LOW(i);
404 /*********************************************************************
405 Generate the LUID_ATTR structure based on a bitmask
406 *********************************************************************/
408 const char* get_privilege_dispname( const char *name )
412 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
414 if ( strequal( privs[i].name, name ) ) {
415 return privs[i].description;
422 /*********************************************************************
423 get a list of all privleges for all sids the in list
424 *********************************************************************/
426 BOOL get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount)
432 se_priv_copy( privileges, &se_priv_none );
434 for ( i=0; i<scount; i++ ) {
435 /* don't add unless we actually have a privilege assigned */
437 if ( !get_privileges( &slist[i], &mask ) )
440 DEBUG(5,("get_privileges_for_sids: sid = %s\nPrivilege set:\n",
441 sid_string_static(&slist[i])));
442 dump_se_priv( DBGC_ALL, 5, &mask );
444 se_priv_add( privileges, &mask );
452 /*********************************************************************
453 travseral functions for privilege_enumerate_accounts
454 *********************************************************************/
456 static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
458 PRIV_SID_LIST *priv = state;
459 int prefixlen = strlen(PRIVPREFIX);
463 /* easy check first */
465 if ( data.dsize != sizeof(SE_PRIV) )
468 /* check we have a PRIV_+SID entry */
470 if ( strncmp(key.dptr, PRIVPREFIX, prefixlen) != 0)
473 /* check to see if we are looking for a particular privilege */
475 if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
478 se_priv_copy( &mask, (SE_PRIV*)data.dptr );
480 /* if the SID does not have the specified privilege
483 if ( !is_privilege_assigned( &mask, &priv->privilege) )
487 fstrcpy( sid_string, &key.dptr[strlen(PRIVPREFIX)] );
489 if ( !string_to_sid(&sid, sid_string) ) {
490 DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
495 add_sid_to_array( &sid, &priv->sids.list, &priv->sids.count );
500 /*********************************************************************
501 Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
502 *********************************************************************/
504 NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
506 TDB_CONTEXT *tdb = get_account_pol_tdb();
511 se_priv_copy( &priv.privilege, &se_priv_none );
513 tdb_traverse( tdb, priv_traverse_fn, &priv);
515 /* give the memory away; caller will free */
517 *sids = priv.sids.list;
518 *num_sids = priv.sids.count;
523 /***************************************************************************
525 ****************************************************************************/
527 BOOL grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
529 SE_PRIV old_mask, new_mask;
531 if ( get_privileges( sid, &old_mask ) )
532 se_priv_copy( &new_mask, &old_mask );
534 se_priv_copy( &new_mask, &se_priv_none );
536 se_priv_add( &new_mask, priv_mask );
538 DEBUG(10,("grant_privilege: %s\n", sid_string_static(sid)));
540 DEBUGADD( 10, ("original privilege mask:\n"));
541 dump_se_priv( DBGC_ALL, 10, &old_mask );
543 DEBUGADD( 10, ("new privilege mask:\n"));
544 dump_se_priv( DBGC_ALL, 10, &new_mask );
546 return set_privileges( sid, &new_mask );
549 /*********************************************************************
550 Add a privilege based on its name
551 *********************************************************************/
553 BOOL grant_privilege_by_name(DOM_SID *sid, const char *name)
557 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
558 if ( strequal(privs[i].name, name) ) {
559 return grant_privilege( sid, &privs[i].se_priv );
563 DEBUG(3, ("grant_privilege_by_name: No Such Privilege Found (%s)\n", name));
568 /***************************************************************************
569 Remove privilege from sid
570 ****************************************************************************/
572 BOOL revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
576 /* if the user has no privileges, then we can't revoke any */
578 if ( !get_privileges( sid, &mask ) )
581 DEBUG(10,("revoke_privilege: %s\n", sid_string_static(sid)));
583 DEBUGADD( 10, ("original privilege mask:\n"));
584 dump_se_priv( DBGC_ALL, 10, &mask );
586 se_priv_remove( &mask, priv_mask );
588 DEBUGADD( 10, ("new privilege mask:\n"));
589 dump_se_priv( DBGC_ALL, 10, &mask );
591 return set_privileges( sid, &mask );
594 /*********************************************************************
595 Revoke all privileges
596 *********************************************************************/
598 BOOL revoke_all_privileges( DOM_SID *sid )
600 return revoke_privilege( sid, &se_priv_all );
603 /*********************************************************************
604 Add a privilege based on its name
605 *********************************************************************/
607 BOOL revoke_privilege_by_name(DOM_SID *sid, const char *name)
611 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
612 if ( strequal(privs[i].name, name) ) {
613 return revoke_privilege( sid, &privs[i].se_priv );
617 DEBUG(3, ("revoke_privilege_by_name: No Such Privilege Found (%s)\n", name));
622 /***************************************************************************
623 Retrieve the SIDs assigned to a given privilege
624 ****************************************************************************/
626 NTSTATUS privilege_create_account(const DOM_SID *sid )
628 return ( grant_privilege(sid, &se_priv_none) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
631 /****************************************************************************
632 initialise a privilege list and set the talloc context
633 ****************************************************************************/
634 NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
638 ZERO_STRUCTP( priv_set );
640 mem_ctx = talloc_init("privilege set");
642 DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n"));
643 return NT_STATUS_NO_MEMORY;
646 priv_set->mem_ctx = mem_ctx;
651 /****************************************************************************
652 initialise a privilege list and with someone else's talloc context
653 ****************************************************************************/
655 NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
657 ZERO_STRUCTP( priv_set );
659 priv_set->mem_ctx = mem_ctx;
660 priv_set->ext_ctx = True;
665 /****************************************************************************
666 Free all memory used by a PRIVILEGE_SET
667 ****************************************************************************/
669 void privilege_set_free(PRIVILEGE_SET *priv_set)
674 if ( !( priv_set->ext_ctx ) )
675 talloc_destroy( priv_set->mem_ctx );
677 ZERO_STRUCTP( priv_set );
680 /****************************************************************************
681 duplicate alloc luid_attr
682 ****************************************************************************/
684 NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
691 *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
693 DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count));
694 return NT_STATUS_NO_MEMORY;
697 for (i=0; i<count; i++) {
698 (*new_la)[i].luid.high = old_la[i].luid.high;
699 (*new_la)[i].luid.low = old_la[i].luid.low;
700 (*new_la)[i].attr = old_la[i].attr;
706 /****************************************************************************
707 Does the user have the specified privilege ? We only deal with one privilege
709 *****************************************************************************/
711 BOOL user_has_privileges(NT_USER_TOKEN *token, const SE_PRIV *privilege)
716 return is_privilege_assigned( &token->privileges, privilege );
719 /****************************************************************************
720 Does the user have any of the specified privileges ? We only deal with one privilege
722 *****************************************************************************/
724 BOOL user_has_any_privilege(NT_USER_TOKEN *token, const SE_PRIV *privilege)
729 return is_any_privilege_assigned( &token->privileges, privilege );
732 /****************************************************************************
733 Convert a LUID to a named string
734 ****************************************************************************/
736 char* luid_to_privilege_name(const LUID *set)
739 int max = count_all_privileges();
744 if ( set->low > max )
747 fstrcpy( name, privs[set->low - 1].name );
752 /*******************************************************************
753 return the number of elements in the privlege array
754 *******************************************************************/
756 int count_all_privileges( void )
763 /* loop over the array and count it */
764 for ( count=0; !se_priv_equal(&privs[count].se_priv, &se_priv_end); count++ ) ;
769 /*******************************************************************
770 *******************************************************************/
772 BOOL se_priv_to_privilege_set( PRIVILEGE_SET *set, SE_PRIV *mask )
775 uint32 num_privs = count_all_privileges();
781 for ( i=0; i<num_privs; i++ ) {
782 if ( !is_privilege_assigned(mask, &privs[i].se_priv) )
785 luid.luid.low = GENERATE_LUID_LOW(i);
787 if ( !privilege_set_add( set, luid ) )
794 /*******************************************************************
795 *******************************************************************/
797 BOOL privilege_set_to_se_priv( SE_PRIV *mask, PRIVILEGE_SET *privset )
800 uint32 num_privs = count_all_privileges();
802 ZERO_STRUCTP( mask );
804 for ( i=0; i<privset->count; i++ ) {
807 /* sanity check for invalid privilege. we really
808 only care about the low 32 bits */
810 if ( privset->set[i].luid.high != 0 )
813 /* make sure :LUID.low is in range */
814 if ( privset->set[i].luid.low == 0 || privset->set[i].luid.low > num_privs )
817 r = privs[privset->set[i].luid.low - 1].se_priv;
818 se_priv_add( mask, &r );
824 /*******************************************************************
825 *******************************************************************/
827 BOOL is_privileged_sid( DOM_SID *sid )
831 return get_privileges( sid, &mask );