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