1/*
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
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.
12
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.
17
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.
21*/
22
23
24#include "includes.h"
25
26#define PRIVPREFIX              "PRIV_"
27
28#define GENERATE_LUID_LOW(x)	(x)+1;
29
30static const SE_PRIV se_priv_all  = SE_ALL_PRIVS;
31static const SE_PRIV se_priv_end  = SE_END;
32
33/* Define variables for all privileges so we can use the
34   SE_PRIV* in the various se_priv_XXX() functions */
35
36const SE_PRIV se_priv_none       = SE_NONE;
37const SE_PRIV se_machine_account = SE_MACHINE_ACCOUNT;
38const SE_PRIV se_print_operator  = SE_PRINT_OPERATOR;
39const SE_PRIV se_add_users       = SE_ADD_USERS;
40const SE_PRIV se_disk_operators  = SE_DISK_OPERATOR;
41const SE_PRIV se_remote_shutdown = SE_REMOTE_SHUTDOWN;
42
43/********************************************************************
44 This is a list of privileges reported by a WIndows 2000 SP4 AD DC
45 just for reference purposes:
46
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
76
77********************************************************************/
78
79
80PRIVS privs[] = {
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 */
83
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"},
88#endif
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"},
94
95	{SE_END,			"",					""}
96};
97
98typedef struct priv_sid_list {
99	SE_PRIV privilege;
100	SID_LIST sids;
101} PRIV_SID_LIST;
102
103
104/***************************************************************************
105 copy an SE_PRIV structure
106****************************************************************************/
107
108BOOL se_priv_copy( SE_PRIV *dst, const SE_PRIV *src )
109{
110	if ( !dst || !src )
111		return False;
112
113	memcpy( dst, src, sizeof(SE_PRIV) );
114
115	return True;
116}
117
118/***************************************************************************
119 combine 2 SE_PRIV structures and store the resulting set in mew_mask
120****************************************************************************/
121
122void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv )
123{
124	int i;
125
126	for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
127		mask->mask[i] |= addpriv->mask[i];
128	}
129}
130
131/***************************************************************************
132 remove one SE_PRIV sytucture from another and store the resulting set
133 in mew_mask
134****************************************************************************/
135
136void se_priv_remove( SE_PRIV *mask, const SE_PRIV *removepriv )
137{
138	int i;
139
140	for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
141		mask->mask[i] &= ~removepriv->mask[i];
142	}
143}
144
145/***************************************************************************
146 invert a given SE_PRIV and store the set in new_mask
147****************************************************************************/
148
149static void se_priv_invert( SE_PRIV *new_mask, const SE_PRIV *mask )
150{
151	SE_PRIV allprivs;
152
153	se_priv_copy( &allprivs, &se_priv_all );
154	se_priv_remove( &allprivs, mask );
155	se_priv_copy( new_mask, &allprivs );
156}
157
158/***************************************************************************
159 check if 2 SE_PRIV structure are equal
160****************************************************************************/
161
162static BOOL se_priv_equal( const SE_PRIV *mask1, const SE_PRIV *mask2 )
163{
164	return ( memcmp(mask1, mask2, sizeof(SE_PRIV)) == 0 );
165}
166
167/***************************************************************************
168 check if a SE_PRIV has any assigned privileges
169****************************************************************************/
170
171static BOOL se_priv_empty( const SE_PRIV *mask )
172{
173	SE_PRIV p1;
174	int i;
175
176	se_priv_copy( &p1, mask );
177
178	for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
179		p1.mask[i] &= se_priv_all.mask[i];
180	}
181
182	return se_priv_equal( &p1, &se_priv_none );
183}
184
185/*********************************************************************
186 Lookup the SE_PRIV value for a privilege name
187*********************************************************************/
188
189BOOL se_priv_from_name( const char *name, SE_PRIV *mask )
190{
191	int i;
192
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 );
196			return True;
197		}
198	}
199
200	return False;
201}
202
203/***************************************************************************
204 dump an SE_PRIV structure to the log files
205****************************************************************************/
206
207void dump_se_priv( int dbg_cl, int dbg_lvl, const SE_PRIV *mask )
208{
209	int i;
210
211	DEBUGADDC( dbg_cl, dbg_lvl,("SE_PRIV "));
212
213	for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
214		DEBUGADDC( dbg_cl, dbg_lvl,(" 0x%x", mask->mask[i] ));
215	}
216
217	DEBUGADDC( dbg_cl, dbg_lvl, ("\n"));
218}
219
220/***************************************************************************
221 Retrieve the privilege mask (set) for a given SID
222****************************************************************************/
223
224static BOOL get_privileges( const DOM_SID *sid, SE_PRIV *mask )
225{
226	TDB_CONTEXT *tdb = get_account_pol_tdb();
227	fstring keystr;
228	TDB_DATA key, data;
229
230	/* Fail if the admin has not enable privileges */
231
232	if ( !lp_enable_privileges() ) {
233		return False;
234	}
235
236	if ( !tdb )
237		return False;
238
239	/* PRIV_<SID> (NULL terminated) as the key */
240
241	fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
242	key.dptr = keystr;
243	key.dsize = strlen(keystr) + 1;
244
245	data = tdb_fetch( tdb, key );
246
247	if ( !data.dptr ) {
248		DEBUG(3,("get_privileges: No privileges assigned to SID [%s]\n",
249			sid_string_static(sid)));
250		return False;
251	}
252
253	SMB_ASSERT( data.dsize == sizeof( SE_PRIV ) );
254
255	se_priv_copy( mask, (SE_PRIV*)data.dptr );
256	SAFE_FREE(data.dptr);
257
258	return True;
259}
260
261/***************************************************************************
262 Store the privilege mask (set) for a given SID
263****************************************************************************/
264
265static BOOL set_privileges( const DOM_SID *sid, SE_PRIV *mask )
266{
267	TDB_CONTEXT *tdb = get_account_pol_tdb();
268	fstring keystr;
269	TDB_DATA key, data;
270
271	if ( !lp_enable_privileges() )
272		return False;
273
274	if ( !tdb )
275		return False;
276
277	/* PRIV_<SID> (NULL terminated) as the key */
278
279	fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
280	key.dptr = keystr;
281	key.dsize = strlen(keystr) + 1;
282
283	/* no packing.  static size structure, just write it out */
284
285	data.dptr  = (char*)mask;
286	data.dsize = sizeof(SE_PRIV);
287
288	return ( tdb_store(tdb, key, data, TDB_REPLACE) != -1 );
289}
290
291/****************************************************************************
292 check if the privilege is in the privilege list
293****************************************************************************/
294
295static BOOL is_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
296{
297	SE_PRIV p1, p2;
298
299	if ( !privileges || !check )
300		return False;
301
302	/* everyone has privileges if you aren't checking for any */
303
304	if ( se_priv_empty( check ) ) {
305		DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
306		return True;
307	}
308
309	se_priv_copy( &p1, check );
310
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 */
314
315	se_priv_invert( &p1, check );
316	se_priv_copy( &p2, privileges );
317	se_priv_remove( &p2, &p1 );
318
319	return se_priv_equal( &p2, check );
320}
321
322/****************************************************************************
323 check if the privilege is in the privilege list
324****************************************************************************/
325
326static BOOL is_any_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
327{
328	SE_PRIV p1, p2;
329
330	if ( !privileges || !check )
331		return False;
332
333	/* everyone has privileges if you aren't checking for any */
334
335	if ( se_priv_empty( check ) ) {
336		DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
337		return True;
338	}
339
340	se_priv_copy( &p1, check );
341
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 */
345
346	se_priv_invert( &p1, check );
347	se_priv_copy( &p2, privileges );
348	se_priv_remove( &p2, &p1 );
349
350	/* see if we have any bits left */
351
352	return !se_priv_empty( &p2 );
353}
354
355/****************************************************************************
356 add a privilege to a privilege array
357 ****************************************************************************/
358
359static BOOL privilege_set_add(PRIVILEGE_SET *priv_set, LUID_ATTR set)
360{
361	LUID_ATTR *new_set;
362
363	/* we can allocate memory to add the new privilege */
364
365	new_set = TALLOC_REALLOC_ARRAY(priv_set->mem_ctx, priv_set->set, LUID_ATTR, priv_set->count + 1);
366	if ( !new_set ) {
367		DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
368		return False;
369	}
370
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;
374
375	priv_set->count++;
376	priv_set->set = new_set;
377
378	return True;
379}
380
381/*********************************************************************
382 Generate the LUID_ATTR structure based on a bitmask
383*********************************************************************/
384
385LUID_ATTR get_privilege_luid( SE_PRIV *mask )
386{
387	LUID_ATTR priv_luid;
388	int i;
389
390	priv_luid.attr = 0;
391	priv_luid.luid.high = 0;
392
393	for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
394
395		if ( se_priv_equal( &privs[i].se_priv, mask ) ) {
396			priv_luid.luid.low = GENERATE_LUID_LOW(i);
397			break;
398		}
399	}
400
401	return priv_luid;
402}
403
404/*********************************************************************
405 Generate the LUID_ATTR structure based on a bitmask
406*********************************************************************/
407
408const char* get_privilege_dispname( const char *name )
409{
410	int i;
411
412	for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
413
414		if ( strequal( privs[i].name, name ) ) {
415			return privs[i].description;
416		}
417	}
418
419	return NULL;
420}
421
422/*********************************************************************
423 get a list of all privleges for all sids the in list
424*********************************************************************/
425
426BOOL get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount)
427{
428	SE_PRIV mask;
429	int i;
430	BOOL found = False;
431
432	se_priv_copy( privileges, &se_priv_none );
433
434	for ( i=0; i<scount; i++ ) {
435		/* don't add unless we actually have a privilege assigned */
436
437		if ( !get_privileges( &slist[i], &mask ) )
438			continue;
439
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 );
443
444		se_priv_add( privileges, &mask );
445		found = True;
446	}
447
448	return found;
449}
450
451
452/*********************************************************************
453 travseral functions for privilege_enumerate_accounts
454*********************************************************************/
455
456static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
457{
458	PRIV_SID_LIST *priv = state;
459	int  prefixlen = strlen(PRIVPREFIX);
460	DOM_SID sid;
461	fstring sid_string;
462
463	/* easy check first */
464
465	if ( data.dsize != sizeof(SE_PRIV) )
466		return 0;
467
468	/* check we have a PRIV_+SID entry */
469
470	if ( strncmp(key.dptr, PRIVPREFIX, prefixlen) != 0)
471		return 0;
472
473	/* check to see if we are looking for a particular privilege */
474
475	if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
476		SE_PRIV mask;
477
478		se_priv_copy( &mask, (SE_PRIV*)data.dptr );
479
480		/* if the SID does not have the specified privilege
481		   then just return */
482
483		if ( !is_privilege_assigned( &mask, &priv->privilege) )
484			return 0;
485	}
486
487	fstrcpy( sid_string, &key.dptr[strlen(PRIVPREFIX)] );
488
489	if ( !string_to_sid(&sid, sid_string) ) {
490		DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
491			sid_string));
492		return 0;
493	}
494
495	add_sid_to_array( &sid, &priv->sids.list, &priv->sids.count );
496
497	return 0;
498}
499
500/*********************************************************************
501 Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
502*********************************************************************/
503
504NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
505{
506	TDB_CONTEXT *tdb = get_account_pol_tdb();
507	PRIV_SID_LIST priv;
508
509	ZERO_STRUCT(priv);
510
511	se_priv_copy( &priv.privilege, &se_priv_none );
512
513	tdb_traverse( tdb, priv_traverse_fn, &priv);
514
515	/* give the memory away; caller will free */
516
517	*sids      = priv.sids.list;
518	*num_sids  = priv.sids.count;
519
520	return NT_STATUS_OK;
521}
522
523/***************************************************************************
524 Add privilege to sid
525****************************************************************************/
526
527BOOL grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
528{
529	SE_PRIV old_mask, new_mask;
530
531	if ( get_privileges( sid, &old_mask ) )
532		se_priv_copy( &new_mask, &old_mask );
533	else
534		se_priv_copy( &new_mask, &se_priv_none );
535
536	se_priv_add( &new_mask, priv_mask );
537
538	DEBUG(10,("grant_privilege: %s\n", sid_string_static(sid)));
539
540	DEBUGADD( 10, ("original privilege mask:\n"));
541	dump_se_priv( DBGC_ALL, 10, &old_mask );
542
543	DEBUGADD( 10, ("new privilege mask:\n"));
544	dump_se_priv( DBGC_ALL, 10, &new_mask );
545
546	return set_privileges( sid, &new_mask );
547}
548
549/*********************************************************************
550 Add a privilege based on its name
551*********************************************************************/
552
553BOOL grant_privilege_by_name(DOM_SID *sid, const char *name)
554{
555	int i;
556
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 );
560                }
561        }
562
563        DEBUG(3, ("grant_privilege_by_name: No Such Privilege Found (%s)\n", name));
564
565        return False;
566}
567
568/***************************************************************************
569 Remove privilege from sid
570****************************************************************************/
571
572BOOL revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
573{
574	SE_PRIV mask;
575
576	/* if the user has no privileges, then we can't revoke any */
577
578	if ( !get_privileges( sid, &mask ) )
579		return True;
580
581	DEBUG(10,("revoke_privilege: %s\n", sid_string_static(sid)));
582
583	DEBUGADD( 10, ("original privilege mask:\n"));
584	dump_se_priv( DBGC_ALL, 10, &mask );
585
586	se_priv_remove( &mask, priv_mask );
587
588	DEBUGADD( 10, ("new privilege mask:\n"));
589	dump_se_priv( DBGC_ALL, 10, &mask );
590
591	return set_privileges( sid, &mask );
592}
593
594/*********************************************************************
595 Revoke all privileges
596*********************************************************************/
597
598BOOL revoke_all_privileges( DOM_SID *sid )
599{
600	return revoke_privilege( sid, &se_priv_all );
601}
602
603/*********************************************************************
604 Add a privilege based on its name
605*********************************************************************/
606
607BOOL revoke_privilege_by_name(DOM_SID *sid, const char *name)
608{
609	int i;
610
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 );
614                }
615        }
616
617        DEBUG(3, ("revoke_privilege_by_name: No Such Privilege Found (%s)\n", name));
618
619        return False;
620}
621
622/***************************************************************************
623 Retrieve the SIDs assigned to a given privilege
624****************************************************************************/
625
626NTSTATUS privilege_create_account(const DOM_SID *sid )
627{
628	return ( grant_privilege(sid, &se_priv_none) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
629}
630
631/****************************************************************************
632 initialise a privilege list and set the talloc context
633 ****************************************************************************/
634NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
635{
636	TALLOC_CTX *mem_ctx;
637
638	ZERO_STRUCTP( priv_set );
639
640	mem_ctx = talloc_init("privilege set");
641	if ( !mem_ctx ) {
642		DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n"));
643		return NT_STATUS_NO_MEMORY;
644	}
645
646	priv_set->mem_ctx = mem_ctx;
647
648	return NT_STATUS_OK;
649}
650
651/****************************************************************************
652  initialise a privilege list and with someone else's talloc context
653****************************************************************************/
654
655NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
656{
657	ZERO_STRUCTP( priv_set );
658
659	priv_set->mem_ctx = mem_ctx;
660	priv_set->ext_ctx = True;
661
662	return NT_STATUS_OK;
663}
664
665/****************************************************************************
666 Free all memory used by a PRIVILEGE_SET
667****************************************************************************/
668
669void privilege_set_free(PRIVILEGE_SET *priv_set)
670{
671	if ( !priv_set )
672		return;
673
674	if ( !( priv_set->ext_ctx ) )
675		talloc_destroy( priv_set->mem_ctx );
676
677	ZERO_STRUCTP( priv_set );
678}
679
680/****************************************************************************
681 duplicate alloc luid_attr
682 ****************************************************************************/
683
684NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
685{
686	int i;
687
688	if ( !old_la )
689		return NT_STATUS_OK;
690
691	*new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
692	if ( !*new_la ) {
693		DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count));
694		return NT_STATUS_NO_MEMORY;
695	}
696
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;
701	}
702
703	return NT_STATUS_OK;
704}
705
706/****************************************************************************
707 Does the user have the specified privilege ?  We only deal with one privilege
708 at a time here.
709*****************************************************************************/
710
711BOOL user_has_privileges(NT_USER_TOKEN *token, const SE_PRIV *privilege)
712{
713	if ( !token )
714		return False;
715
716	return is_privilege_assigned( &token->privileges, privilege );
717}
718
719/****************************************************************************
720 Does the user have any of the specified privileges ?  We only deal with one privilege
721 at a time here.
722*****************************************************************************/
723
724BOOL user_has_any_privilege(NT_USER_TOKEN *token, const SE_PRIV *privilege)
725{
726	if ( !token )
727		return False;
728
729	return is_any_privilege_assigned( &token->privileges, privilege );
730}
731
732/****************************************************************************
733 Convert a LUID to a named string
734****************************************************************************/
735
736char* luid_to_privilege_name(const LUID *set)
737{
738	static fstring name;
739	int max = count_all_privileges();
740
741	if (set->high != 0)
742		return NULL;
743
744	if ( set->low > max )
745		return NULL;
746
747	fstrcpy( name, privs[set->low - 1].name );
748
749	return name;
750}
751
752/*******************************************************************
753 return the number of elements in the privlege array
754*******************************************************************/
755
756int count_all_privileges( void )
757{
758	static int count;
759
760	if ( count )
761		return count;
762
763	/* loop over the array and count it */
764	for ( count=0; !se_priv_equal(&privs[count].se_priv, &se_priv_end); count++ ) ;
765
766	return count;
767}
768
769/*******************************************************************
770*******************************************************************/
771
772BOOL se_priv_to_privilege_set( PRIVILEGE_SET *set, SE_PRIV *mask )
773{
774	int i;
775	uint32 num_privs = count_all_privileges();
776	LUID_ATTR luid;
777
778	luid.attr = 0;
779	luid.luid.high = 0;
780
781	for ( i=0; i<num_privs; i++ ) {
782		if ( !is_privilege_assigned(mask, &privs[i].se_priv) )
783			continue;
784
785		luid.luid.low = GENERATE_LUID_LOW(i);
786
787		if ( !privilege_set_add( set, luid ) )
788			return False;
789	}
790
791	return True;
792}
793
794/*******************************************************************
795*******************************************************************/
796
797BOOL privilege_set_to_se_priv( SE_PRIV *mask, PRIVILEGE_SET *privset )
798{
799	int i;
800	uint32 num_privs = count_all_privileges();
801
802	ZERO_STRUCTP( mask );
803
804	for ( i=0; i<privset->count; i++ ) {
805		SE_PRIV r;
806
807		/* sanity check for invalid privilege.  we really
808		   only care about the low 32 bits */
809
810		if ( privset->set[i].luid.high != 0 )
811			return False;
812
813		/* make sure :LUID.low is in range */
814		if ( privset->set[i].luid.low == 0 || privset->set[i].luid.low > num_privs )
815			return False;
816
817		r = privs[privset->set[i].luid.low - 1].se_priv;
818		se_priv_add( mask, &r );
819	}
820
821	return True;
822}
823
824/*******************************************************************
825*******************************************************************/
826
827BOOL is_privileged_sid( DOM_SID *sid )
828{
829	SE_PRIV mask;
830
831	return get_privileges( sid, &mask );
832}
833