r5726: merge LsaLookupPrivValue() code from trunk
[sfrench/samba-autobuild/.git] / source3 / lib / privileges.c
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
30 static const SE_PRIV se_priv_all  = SE_ALL_PRIVS;
31 static 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
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;
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
80 PRIVS 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
98 typedef 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
108 BOOL 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
122 void 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
136 void 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
149 static 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
162 static 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
171 static 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
189 BOOL 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
207 void 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
224 static 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
265 static 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
295 static 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
326 static 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
359 static 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
385 LUID_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
408 const 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
426 BOOL 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
456 static 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
504 NTSTATUS 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
527 BOOL 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
553 BOOL 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
572 BOOL 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
598 BOOL 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
607 BOOL 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
626 NTSTATUS 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  ****************************************************************************/
634 NTSTATUS 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
655 NTSTATUS 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
669 void 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
684 NTSTATUS 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
711 BOOL 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
724 BOOL 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
736 char* 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
756 int 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
772 BOOL 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
797 BOOL 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
827 BOOL is_privileged_sid( DOM_SID *sid )
828 {
829         SE_PRIV mask;
830         
831         return get_privileges( sid, &mask );
832 }