09a868fc277079ff95778b99c3bc7c4b893afffb
[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 ALLOC_CHECK(ptr, err, label, str) do { if ((ptr) == NULL) \
29         { DEBUG(0, ("%s: out of memory!\n", str)); err = NT_STATUS_NO_MEMORY; goto label; } } while(0)
30         
31 PRIVS privs[] = {
32         {SE_NETWORK_LOGON,              "SeNetworkLogonRight",                  "Access this computer from the network"},
33         {SE_INTERACTIVE_LOGON,          "SeInteractiveLogonRight",              "Log on locally"},
34         {SE_BATCH_LOGON,                "SeBatchLogonRight",                    "Log on as a batch job"},
35         {SE_SERVICE_LOGON,              "SeServiceLogonRight",                  "Log on as a service"},
36
37         {SE_MACHINE_ACCOUNT,            "SeMachineAccountPrivilege",            "Add machines to domain"},
38         {SE_PRINT_OPERATOR,             "SePrintOperatorPrivilege",             "Printer Admin"},
39         {SE_ADD_USERS,                  "SeAddUsersPrivilege",                  "Add users and groups to the domain"},
40
41         {SE_END,                        "",                                     ""}
42 };
43         
44
45 #if 0   /* not needed currently */
46 PRIVS privs[] = {
47         {SE_ASSIGN_PRIMARY_TOKEN,       "SeAssignPrimaryTokenPrivilege",        "Assign Primary Token"},
48         {SE_CREATE_TOKEN,               "SeCreateTokenPrivilege",               "Create Token"},
49         {SE_LOCK_MEMORY,                "SeLockMemoryPrivilege",                "Lock Memory"},
50         {SE_INCREASE_QUOTA,             "SeIncreaseQuotaPrivilege",             "Increase Quota"},
51         {SE_UNSOLICITED_INPUT,          "SeUnsolicitedInputPrivilege",          "Unsolicited Input"},
52         {SE_MACHINE_ACCOUNT,            "SeMachineAccountPrivilege",            "Can add Machine Accounts to the Domain"},
53         {SE_TCB,                        "SeTcbPrivilege",                       "Act as part of the operating system"},
54         {SE_SECURITY,                   "SeSecurityPrivilege",                  "Security Privilege"},
55         {SE_TAKE_OWNERSHIP,             "SeTakeOwnershipPrivilege",             "Take Ownership Privilege"},
56         {SE_LOAD_DRIVER,                "SeLocalDriverPrivilege",               "Local Driver Privilege"},
57         {SE_SYSTEM_PROFILE,             "SeSystemProfilePrivilege",             "System Profile Privilege"},
58         {SE_SYSTEM_TIME,                "SeSystemtimePrivilege",                "System Time"},
59         {SE_PROF_SINGLE_PROCESS,        "SeProfileSingleProcessPrivilege",      "Profile Single Process Privilege"},
60         {SE_INC_BASE_PRIORITY,          "SeIncreaseBasePriorityPrivilege",      "Increase Base Priority Privilege"},
61         {SE_CREATE_PAGEFILE,            "SeCreatePagefilePrivilege",            "Create Pagefile Privilege"},
62         {SE_CREATE_PERMANENT,           "SeCreatePermanentPrivilege",           "Create Permanent"},
63         {SE_BACKUP,                     "SeBackupPrivilege",                    "Backup Privilege"},
64         {SE_RESTORE,                    "SeRestorePrivilege",                   "Restore Privilege"},
65         {SE_SHUTDOWN,                   "SeShutdownPrivilege",                  "Shutdown Privilege"},
66         {SE_DEBUG,                      "SeDebugPrivilege",                     "Debug Privilege"},
67         {SE_AUDIT,                      "SeAuditPrivilege",                     "Audit"},
68         {SE_SYSTEM_ENVIRONMENT,         "SeSystemEnvironmentPrivilege",         "System Environment Privilege"},
69         {SE_CHANGE_NOTIFY,              "SeChangeNotifyPrivilege",              "Change Notify"},
70         {SE_REMOTE_SHUTDOWN,            "SeRemoteShutdownPrivilege",            "Remote Shutdown Privilege"},
71         {SE_UNDOCK,                     "SeUndockPrivilege",                    "Undock"},
72         {SE_SYNC_AGENT,                 "SeSynchronizationAgentPrivilege",      "Synchronization Agent"},
73         {SE_ENABLE_DELEGATION,          "SeEnableDelegationPrivilege",          "Enable Delegation"},
74         {SE_PRINT_OPERATOR,             "SePrintOperatorPrivilege",             "Printer Operator"},
75         {SE_ADD_USERS,                  "SeAddUsersPrivilege",                  "Add Users"},
76         {SE_ALL_PRIVS,                  "SeAllPrivileges",                      "All Privileges"}
77         {SE_END,                        "",                                     ""}
78 };
79 #endif
80
81 typedef struct priv_sid_list {
82         uint32 se_priv;
83         SID_LIST sids;
84 } PRIV_SID_LIST;
85
86 /***************************************************************************
87  Retrieve the privilege mask (set) for a given SID
88 ****************************************************************************/
89
90 static uint32 get_privileges( const DOM_SID *sid, uint32 *mask )
91 {
92         TDB_CONTEXT *tdb = get_account_pol_tdb();
93         fstring keystr;
94         uint32 priv_mask;
95         
96         if ( !tdb )
97                 return False;
98
99         fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
100
101         if ( !tdb_fetch_uint32( tdb, keystr, &priv_mask ) ) {
102                 DEBUG(3,("get_privileges: No privileges assigned to SID [%s]\n",
103                         sid_string_static(sid)));
104                 return False;
105         }
106         
107         *mask = priv_mask;
108         return True;
109 }
110
111 /***************************************************************************
112  Store the privilege mask (set) for a given SID
113 ****************************************************************************/
114
115 static BOOL set_privileges( const DOM_SID *sid, uint32 mask )
116 {
117         TDB_CONTEXT *tdb = get_account_pol_tdb();
118         fstring keystr;
119         
120         if ( !tdb )
121                 return False;
122
123         fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
124
125         return tdb_store_uint32( tdb, keystr, mask );
126 }
127
128 /****************************************************************************
129  check if the privilege is in the privilege list
130 ****************************************************************************/
131
132 static BOOL check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
133 {
134         int i;
135
136         if ( !priv_set )
137                 return False;
138
139         for ( i = 0; i < priv_set->count; i++ ) {
140                 LUID_ATTR *cur_set;
141
142                 cur_set = &priv_set->set[i];
143
144                 /* check only the low and high part. Checking the attr 
145                    field has no meaning */
146
147                 if ( (cur_set->luid.low == set.luid.low) 
148                         && (cur_set->luid.high == set.luid.high) ) 
149                 {
150                         return True;
151                 }
152         }
153
154         return False;
155 }
156
157 /****************************************************************************
158  add a privilege to a privilege array
159  ****************************************************************************/
160
161 static NTSTATUS add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
162 {
163         NTSTATUS ret;
164         LUID_ATTR *new_set;
165
166         /* check if the privilege is not already in the list */
167
168         if ( check_priv_in_privilege(priv_set, set) )
169                 return NT_STATUS_OK;
170
171         /* we can allocate memory to add the new privilege */
172
173         new_set = TALLOC_REALLOC_ARRAY(priv_set->mem_ctx, priv_set->set, LUID_ATTR, priv_set->count + 1);
174         ALLOC_CHECK(new_set, ret, done, "add_privilege");
175
176         new_set[priv_set->count].luid.high = set.luid.high;
177         new_set[priv_set->count].luid.low = set.luid.low;
178         new_set[priv_set->count].attr = set.attr;
179
180         priv_set->count++;
181         priv_set->set = new_set;
182
183         ret = NT_STATUS_OK;
184
185 done:
186         return ret;
187 }
188
189 /*********************************************************************
190  Generate the LUID_ATTR structure based on a bitmask
191 *********************************************************************/
192
193 static LUID_ATTR get_privilege_luid( uint32 mask )
194 {
195         LUID_ATTR priv_luid;
196
197         priv_luid.attr = 0;
198         priv_luid.luid.high = 0;
199         priv_luid.luid.low = mask;
200
201         return priv_luid;
202 }
203
204 /*********************************************************************
205  Convert a privilege mask to an LUID_ATTR[] and add the privileges to 
206  the PRIVILEGE_SET
207 *********************************************************************/
208
209 static void add_privilege_set( PRIVILEGE_SET *privset, uint32 mask )
210 {
211         LUID_ATTR luid;
212         int i;
213         
214         for (i=0; privs[i].se_priv != SE_END; i++) {
215
216                 /* skip if the privilege is not part of the mask */
217
218                 if ( !(mask & privs[i].se_priv) ) 
219                         continue;
220
221                 /* remove the bit from the mask */
222
223                 mask &= ~privs[i].se_priv;      
224                 
225                 luid = get_privilege_luid( privs[i].se_priv );
226                 
227                 add_privilege( privset, luid );
228         }
229
230         /* log an error if we have anything left at this point */
231         if ( mask )
232                 DEBUG(0,("add_privilege_set: leftover bits! [0x%x]\n", mask ));
233 }
234
235 /*********************************************************************
236  get a list of all privleges for all sids the in list
237 *********************************************************************/
238
239 void get_privileges_for_sids(PRIVILEGE_SET *privset, DOM_SID *slist, int scount)
240 {
241         uint32 priv_mask;
242         int i;
243         
244         for ( i=0; i<scount; i++ ) {
245                 /* don't add unless we actually have a privilege assigned */
246
247                 if ( !get_privileges( &slist[i], &priv_mask ) )
248                         continue;
249
250                 DEBUG(5,("get_privileges_for_sids: sid = %s, privilege mask = 0x%x\n",
251                         sid_string_static(&slist[i]), priv_mask));
252                         
253                 add_privilege_set( privset, priv_mask );
254         }
255 }
256
257
258 /*********************************************************************
259  travseral functions for privilege_enumerate_accounts
260 *********************************************************************/
261
262 static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
263 {
264         PRIV_SID_LIST *priv = state;
265         int  prefixlen = strlen(PRIVPREFIX);
266         DOM_SID sid;
267         fstring sid_string;
268
269         /* check we have a PRIV_+SID entry */
270
271         if ( strncmp(key.dptr, PRIVPREFIX, prefixlen) != 0)
272                 return 0;
273                 
274         /* check to see if we are looking for a particular privilege */
275
276         if ( priv->se_priv != SE_NONE ) {
277                 uint32 mask = SVAL(data.dptr, 0);
278                 
279                 /* if the SID does not have the specified privilege 
280                    then just return */
281                    
282                 if ( !(mask & priv->se_priv) )
283                         return 0;
284         }
285                 
286         fstrcpy( sid_string, &key.dptr[strlen(PRIVPREFIX)] );
287
288         if ( !string_to_sid(&sid, sid_string) ) {
289                 DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
290                         sid_string));
291                 return 0;
292         }
293
294         add_sid_to_array( &sid, &priv->sids.list, &priv->sids.count );
295         
296         return 0;
297 }
298
299 /*********************************************************************
300  Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
301 *********************************************************************/
302
303 NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
304 {
305         TDB_CONTEXT *tdb = get_account_pol_tdb();
306         PRIV_SID_LIST priv;
307         
308         ZERO_STRUCT(priv);
309         priv.se_priv = SE_NONE;
310
311         tdb_traverse( tdb, priv_traverse_fn, &priv);
312
313         /* give the memory away; caller will free */
314         
315         *sids      = priv.sids.list;
316         *num_sids  = priv.sids.count;
317
318         return NT_STATUS_OK;
319 }
320
321 /***************************************************************************
322  Retrieve the SIDs assigned to a given privilege
323 ****************************************************************************/
324
325 NTSTATUS priv_get_sids(const char *privname, DOM_SID **sids, int *num_sids)
326 {
327         TDB_CONTEXT *tdb = get_account_pol_tdb();
328         PRIV_SID_LIST priv;
329         
330         ZERO_STRUCT(priv);      
331         priv.se_priv = 
332         
333
334         tdb_traverse( tdb, priv_traverse_fn, &priv);
335
336         /* give the memory away; caller will free */
337         
338         *sids      = priv.sids.list;
339         *num_sids  = priv.sids.count;
340
341         return NT_STATUS_OK;
342 }
343
344 /***************************************************************************
345  Add privilege to sid
346 ****************************************************************************/
347
348 BOOL grant_privilege(const DOM_SID *sid, uint32 priv_mask)
349 {
350         uint32 old_mask, new_mask;
351         
352         if ( get_privileges( sid, &old_mask ) )
353                 new_mask = old_mask | priv_mask;
354         else
355                 new_mask = priv_mask;
356
357         DEBUG(10,("grant_privilege: %s, orig priv set = 0x%x, new privilege set = 0x%x\n",
358                 sid_string_static(sid), old_mask, new_mask ));
359         
360         return set_privileges( sid, new_mask );
361 }
362
363 /*********************************************************************
364  Add a privilege based on its name
365 *********************************************************************/
366
367 BOOL grant_privilege_by_name(DOM_SID *sid, const char *name)
368 {
369         int i;
370
371         for ( i = 0; privs[i].se_priv != SE_END; i++ ) {
372                 if ( strequal(privs[i].name, name) ) {
373                         return grant_privilege( sid, privs[i].se_priv );
374                 }
375         }
376
377         DEBUG(3, ("grant_privilege_by_name: No Such Privilege Found (%s)\n", name));
378
379         return False;
380 }
381
382 /***************************************************************************
383  Remove privilege from sid
384 ****************************************************************************/
385
386 BOOL revoke_privilege(const DOM_SID *sid, uint32 priv_mask)
387 {
388         uint32 old_mask, new_mask;
389         
390         if ( get_privileges( sid, &old_mask ) )
391                 new_mask = old_mask | priv_mask;
392         else
393                 new_mask = priv_mask;
394         
395         new_mask = old_mask & ~priv_mask;
396
397         DEBUG(10,("revoke_privilege: %s, orig priv set = 0x%x, new priv set = 0x%x\n",
398                 sid_string_static(sid), old_mask, new_mask ));
399         
400         return set_privileges( sid, new_mask );
401 }
402
403 /*********************************************************************
404  Add a privilege based on its name
405 *********************************************************************/
406
407 BOOL revoke_privilege_by_name(DOM_SID *sid, const char *name)
408 {
409         int i;
410
411         for ( i = 0; privs[i].se_priv != SE_END; i++ ) {
412                 if ( strequal(privs[i].name, name) ) {
413                         return revoke_privilege( sid, privs[i].se_priv );
414                 }
415         }
416
417         DEBUG(3, ("revoke_privilege_by_name: No Such Privilege Found (%s)\n", name));
418
419         return False;
420 }
421
422 /***************************************************************************
423  Retrieve the SIDs assigned to a given privilege
424 ****************************************************************************/
425
426 NTSTATUS privilege_create_account(const DOM_SID *sid )
427 {
428         return ( grant_privilege( sid, SE_NONE ) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
429 }
430
431 /****************************************************************************
432  initialise a privilege list and set the talloc context 
433  ****************************************************************************/
434 NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
435 {
436         NTSTATUS ret;
437         TALLOC_CTX *mem_ctx;
438         
439         ZERO_STRUCTP( priv_set );
440
441         mem_ctx = talloc_init("privilege set");
442         ALLOC_CHECK(mem_ctx, ret, done, "init_privilege");
443
444         priv_set->mem_ctx = mem_ctx;
445
446         ret = NT_STATUS_OK;
447
448 done:
449         return ret;
450 }
451
452 /****************************************************************************
453   initialise a privilege list and with someone else's talloc context 
454 ****************************************************************************/
455
456 NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
457 {
458         ZERO_STRUCTP( priv_set );
459         
460         priv_set->mem_ctx = mem_ctx;
461         priv_set->ext_ctx = True;
462
463         return NT_STATUS_OK;
464 }
465
466 /****************************************************************************
467  Free all memory used by a PRIVILEGE_SET
468 ****************************************************************************/
469
470 void privilege_set_free(PRIVILEGE_SET *priv_set)
471 {
472         if ( !priv_set )
473                 return;
474
475         if ( !( priv_set->ext_ctx ) )
476                 talloc_destroy( priv_set->mem_ctx );
477
478         ZERO_STRUCTP( priv_set );
479 }
480
481 /****************************************************************************
482  duplicate alloc luid_attr
483  ****************************************************************************/
484
485 NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
486 {
487         NTSTATUS ret;
488         int i;
489
490         /* don't crash if the source pointer is NULL (since we don't
491            do priviledges now anyways) */
492
493         if ( !old_la )
494                 return NT_STATUS_OK;
495
496         *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
497         ALLOC_CHECK(new_la, ret, done, "dupalloc_luid_attr");
498
499         for (i=0; i<count; i++) {
500                 (*new_la)[i].luid.high = old_la[i].luid.high;
501                 (*new_la)[i].luid.low = old_la[i].luid.low;
502                 (*new_la)[i].attr = old_la[i].attr;
503         }
504         
505         ret = NT_STATUS_OK;
506
507 done:
508         return ret;
509 }
510
511 /****************************************************************************
512  Performa deep copy of a PRIVILEGE_SET structure.  Assumes an initialized 
513  destination structure.
514 *****************************************************************************/
515
516 BOOL dup_privilege_set( PRIVILEGE_SET *dest, PRIVILEGE_SET *src )
517 {
518         NTSTATUS result;
519         
520         if ( !dest || !src )
521                 return False;
522
523         result = dup_luid_attr( dest->mem_ctx, &dest->set, src->set, src->count );
524         if ( !NT_STATUS_IS_OK(result) ) {
525                 DEBUG(0,("dup_privilege_set: Failed to dup LUID_ATTR array [%s]\n", 
526                         nt_errstr(result) ));
527                 return False;
528         }
529         
530         dest->control  = src->control;
531         dest->count    = src->count;
532
533         return True;
534 }
535
536 /****************************************************************************
537  Does the user have the specified privilege ?  We only deal with one privilege
538  at a time here.
539 *****************************************************************************/
540
541 BOOL user_has_privilege(NT_USER_TOKEN *token, uint32 privilege)
542 {
543         return check_priv_in_privilege( &token->privileges, get_privilege_luid(privilege) );
544 }
545
546 /****************************************************************************
547  Convert a LUID to a named string
548 ****************************************************************************/
549
550 char* luid_to_privilege_name(const LUID *set)
551 {
552         static fstring name;
553         int i = 0;
554
555         if (set->high != 0)
556                 return NULL;
557
558         for ( i=0; privs[i].se_priv!=SE_END; i++ ) {
559                 if (set->low == privs[i].se_priv) {
560                         fstrcpy(name, privs[i].name);
561                         return name;
562                 }
563         }
564
565         return NULL;
566 }
567
568 /****************************************************************************
569  Convert an LUID to a 32-bit mask
570 ****************************************************************************/
571
572 uint32 luid_to_privilege_mask(const LUID *set)
573 {
574         int i = 0;
575
576         if (set->high != 0)
577                 return SE_END;
578
579         for ( i=0; privs[i].se_priv != SE_END; i++ ) {
580                 if (set->low == privs[i].se_priv)
581                         return privs[i].se_priv;
582         }
583
584         return SE_END;
585 }
586
587 /*******************************************************************
588  return the number of elements in the privlege array
589 *******************************************************************/
590
591 int count_all_privileges( void )
592 {
593         static int count;
594         
595         if ( count )
596                 return count;
597
598         /* loop over the array and count it */  
599         for ( count=0; privs[count].se_priv != SE_END; count++ ) ;
600
601         return count;
602 }
603
604 /*******************************************************************
605 *******************************************************************/
606
607 BOOL is_privileged_sid( DOM_SID *sid ) 
608 {
609         int mask;
610
611         /* check if the lookup succeeds */
612
613         return get_privileges( sid, &mask );
614 }
615