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