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