r4724: Add support for Windows privileges in Samba 3.0
[bbaumbach/samba-autobuild/.git] / source3 / lib / privileges.c
1 /*
2    Unix SMB/CIFS implementation.
3    Privileges handling functions
4    Copyright (C) Jean François Micouleau        1998-2001
5    Copyright (C) Simo Sorce                     2002-2003
6    Copyright (C) Gerald (Jerry) Carter          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 )
91 {
92         TDB_CONTEXT *tdb = get_account_pol_tdb();
93         fstring keystr;
94         uint32 priv_mask;
95         
96         if ( !tdb )
97                 return 0;
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 0;
105         }
106         
107         return priv_mask;
108 }
109
110 /***************************************************************************
111  Store the privilege mask (set) for a given SID
112 ****************************************************************************/
113
114 static BOOL set_privileges( const DOM_SID *sid, uint32 mask )
115 {
116         TDB_CONTEXT *tdb = get_account_pol_tdb();
117         fstring keystr;
118         
119         if ( !tdb )
120                 return False;
121
122         fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
123
124         return tdb_store_uint32( tdb, keystr, mask );
125 }
126
127 /****************************************************************************
128  check if the privilege is in the privilege list
129 ****************************************************************************/
130
131 static BOOL check_priv_in_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
132 {
133         int i;
134
135         if ( !priv_set )
136                 return False;
137
138         for ( i = 0; i < priv_set->count; i++ ) {
139                 LUID_ATTR *cur_set;
140
141                 cur_set = &priv_set->set[i];
142
143                 /* check only the low and high part. Checking the attr 
144                    field has no meaning */
145
146                 if ( (cur_set->luid.low == set.luid.low) 
147                         && (cur_set->luid.high == set.luid.high) ) 
148                 {
149                         return True;
150                 }
151         }
152
153         return False;
154 }
155
156 /****************************************************************************
157  add a privilege to a privilege array
158  ****************************************************************************/
159
160 static NTSTATUS add_privilege(PRIVILEGE_SET *priv_set, LUID_ATTR set)
161 {
162         NTSTATUS ret;
163         LUID_ATTR *new_set;
164
165         /* check if the privilege is not already in the list */
166
167         if ( check_priv_in_privilege(priv_set, set) )
168                 return NT_STATUS_OK;
169
170         /* we can allocate memory to add the new privilege */
171
172         new_set = TALLOC_REALLOC_ARRAY(priv_set->mem_ctx, priv_set->set, LUID_ATTR, priv_set->count + 1);
173         ALLOC_CHECK(new_set, ret, done, "add_privilege");
174
175         new_set[priv_set->count].luid.high = set.luid.high;
176         new_set[priv_set->count].luid.low = set.luid.low;
177         new_set[priv_set->count].attr = set.attr;
178
179         priv_set->count++;
180         priv_set->set = new_set;
181
182         ret = NT_STATUS_OK;
183
184 done:
185         return ret;
186 }
187
188 /*********************************************************************
189  Generate the LUID_ATTR structure based on a bitmask
190 *********************************************************************/
191
192 static LUID_ATTR get_privilege_luid( uint32 mask )
193 {
194         LUID_ATTR priv_luid;
195
196         priv_luid.attr = 0;
197         priv_luid.luid.high = 0;
198         priv_luid.luid.low = mask;
199
200         return priv_luid;
201 }
202
203 /*********************************************************************
204  Convert a privilege mask to an LUID_ATTR[] and add the privileges to 
205  the PRIVILEGE_SET
206 *********************************************************************/
207
208 static void add_privilege_set( PRIVILEGE_SET *privset, uint32 mask )
209 {
210         LUID_ATTR luid;
211         int i;
212         
213         for (i=0; privs[i].se_priv != SE_END; i++) {
214
215                 /* skip if the privilege is not part of the mask */
216
217                 if ( !(mask & privs[i].se_priv) ) 
218                         continue;
219
220                 /* remove the bit from the mask */
221
222                 mask &= ~privs[i].se_priv;      
223                 
224                 luid = get_privilege_luid( privs[i].se_priv );
225                 
226                 add_privilege( privset, luid );
227         }
228
229         /* log an error if we have anything left at this point */
230         if ( mask )
231                 DEBUG(0,("add_privilege_set: leftover bits! [0x%x]\n", mask ));
232 }
233
234 /*********************************************************************
235  get a list of all privleges for all sids the in list
236 *********************************************************************/
237
238 void get_privileges_for_sids(PRIVILEGE_SET *privset, DOM_SID *slist, int scount)
239 {
240         uint32 priv_mask;
241         int i;
242         
243         for ( i=0; i<scount; i++ ) {
244                 priv_mask = get_privileges( &slist[i] );
245
246                 /* don't add unless we actually have a privilege assigned */
247
248                 if ( priv_mask == 0 )
249                         continue;
250                 
251                 DEBUG(5,("get_privileges_for_sids: sid = %s, privilege mask = 0x%x\n",
252                         sid_string_static(&slist[i]), priv_mask));
253                         
254                 add_privilege_set( privset, priv_mask );
255         }
256 }
257
258
259 /*********************************************************************
260  travseral functions for privilege_enumerate_accounts
261 *********************************************************************/
262
263 static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
264 {
265         PRIV_SID_LIST *priv = state;
266         int  prefixlen = strlen(PRIVPREFIX);
267         DOM_SID sid;
268         fstring sid_string;
269
270         /* check we have a PRIV_+SID entry */
271
272         if ( strncmp(key.dptr, PRIVPREFIX, prefixlen) != 0)
273                 return 0;
274                 
275         /* check to see if we are looking for a particular privilege */
276
277         if ( priv->se_priv != SE_NONE ) {
278                 uint32 mask = SVAL(data.dptr, 0);
279                 
280                 /* if the SID does not have the specified privilege 
281                    then just return */
282                    
283                 if ( !(mask & priv->se_priv) )
284                         return 0;
285         }
286                 
287         fstrcpy( sid_string, &key.dptr[strlen(PRIVPREFIX)] );
288
289         if ( !string_to_sid(&sid, sid_string) ) {
290                 DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
291                         sid_string));
292                 return 0;
293         }
294
295         add_sid_to_array( &sid, &priv->sids.list, &priv->sids.count );
296         
297         return 0;
298 }
299
300 /*********************************************************************
301  Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
302 *********************************************************************/
303
304 NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
305 {
306         TDB_CONTEXT *tdb = get_account_pol_tdb();
307         PRIV_SID_LIST priv;
308         
309         ZERO_STRUCT(priv);
310         priv.se_priv = SE_NONE;
311
312         tdb_traverse( tdb, priv_traverse_fn, &priv);
313
314         /* give the memory away; caller will free */
315         
316         *sids      = priv.sids.list;
317         *num_sids  = priv.sids.count;
318
319         return NT_STATUS_OK;
320 }
321
322 /***************************************************************************
323  Retrieve the SIDs assigned to a given privilege
324 ****************************************************************************/
325
326 NTSTATUS priv_get_sids(const char *privname, DOM_SID **sids, int *num_sids)
327 {
328         TDB_CONTEXT *tdb = get_account_pol_tdb();
329         PRIV_SID_LIST priv;
330         
331         ZERO_STRUCT(priv);      
332         priv.se_priv = 
333         
334
335         tdb_traverse( tdb, priv_traverse_fn, &priv);
336
337         /* give the memory away; caller will free */
338         
339         *sids      = priv.sids.list;
340         *num_sids  = priv.sids.count;
341
342         return NT_STATUS_OK;
343 }
344
345 /***************************************************************************
346  Add privilege to sid
347 ****************************************************************************/
348
349 BOOL grant_privilege(const DOM_SID *sid, uint32 priv_mask)
350 {
351         uint32 old_mask, new_mask;
352         
353         old_mask = get_privileges( sid );
354         
355         new_mask = old_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  Remove privilege from sid
365 ****************************************************************************/
366
367 BOOL revoke_privilege(const DOM_SID *sid, uint32 priv_mask)
368 {
369         uint32 old_mask, new_mask;
370         
371         old_mask = get_privileges( sid );
372         
373         new_mask = old_mask & ~priv_mask;
374
375         DEBUG(10,("revoke_privilege: %s, orig priv set = 0x%x, new priv set = 0x%x\n",
376                 sid_string_static(sid), old_mask, new_mask ));
377         
378         return set_privileges( sid, new_mask );
379 }
380
381 /***************************************************************************
382  Retrieve the SIDs assigned to a given privilege
383 ****************************************************************************/
384
385 NTSTATUS privilege_create_account(const DOM_SID *sid )
386 {
387         return ( grant_privilege( sid, SE_NONE ) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
388 }
389
390 /****************************************************************************
391  initialise a privilege list and set the talloc context 
392  ****************************************************************************/
393 NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
394 {
395         NTSTATUS ret;
396         
397         ZERO_STRUCTP( priv_set );
398
399         TALLOC_CTX *mem_ctx = talloc_init("privilege set");
400         ALLOC_CHECK(mem_ctx, ret, done, "init_privilege");
401
402         priv_set->mem_ctx = mem_ctx;
403
404         ret = NT_STATUS_OK;
405
406 done:
407         return ret;
408 }
409
410 /****************************************************************************
411   initialise a privilege list and with someone else's talloc context 
412 ****************************************************************************/
413
414 NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
415 {
416         ZERO_STRUCTP( priv_set );
417         
418         priv_set->mem_ctx = mem_ctx;
419         priv_set->ext_ctx = True;
420
421         return NT_STATUS_OK;
422 }
423
424 /****************************************************************************
425  Free all memory used by a PRIVILEGE_SET
426 ****************************************************************************/
427
428 void privilege_set_free(PRIVILEGE_SET *priv_set)
429 {
430         if ( !priv_set )
431                 return;
432
433         if ( !( priv_set->ext_ctx ) )
434                 talloc_destroy( priv_set->mem_ctx );
435
436         ZERO_STRUCTP( priv_set );
437 }
438
439 /****************************************************************************
440  duplicate alloc luid_attr
441  ****************************************************************************/
442
443 NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
444 {
445         NTSTATUS ret;
446         int i;
447
448         /* don't crash if the source pointer is NULL (since we don't
449            do priviledges now anyways) */
450
451         if ( !old_la )
452                 return NT_STATUS_OK;
453
454         *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
455         ALLOC_CHECK(new_la, ret, done, "dupalloc_luid_attr");
456
457         for (i=0; i<count; i++) {
458                 (*new_la)[i].luid.high = old_la[i].luid.high;
459                 (*new_la)[i].luid.low = old_la[i].luid.low;
460                 (*new_la)[i].attr = old_la[i].attr;
461         }
462         
463         ret = NT_STATUS_OK;
464
465 done:
466         return ret;
467 }
468
469 /****************************************************************************
470  Performa deep copy of a PRIVILEGE_SET structure.  Assumes an initialized 
471  destination structure.
472 *****************************************************************************/
473
474 BOOL dup_privilege_set( PRIVILEGE_SET *dest, PRIVILEGE_SET *src )
475 {
476         NTSTATUS result;
477         
478         if ( !dest || !src )
479                 return False;
480
481         result = dup_luid_attr( dest->mem_ctx, &dest->set, src->set, src->count );
482         if ( !NT_STATUS_IS_OK(result) ) {
483                 DEBUG(0,("dup_privilege_set: Failed to dup LUID_ATTR array [%s]\n", 
484                         nt_errstr(result) ));
485                 return False;
486         }
487         
488         dest->control  = src->control;
489         dest->count    = src->count;
490
491         return True;
492 }
493
494 /****************************************************************************
495  Does the user have the specified privilege ?  We only deal with one privilege
496  at a time here.
497 *****************************************************************************/
498
499 BOOL user_has_privilege(NT_USER_TOKEN *token, uint32 privilege)
500 {
501         return check_priv_in_privilege( &token->privileges, get_privilege_luid(privilege) );
502 }
503
504 /****************************************************************************
505  Convert a LUID to a named string
506 ****************************************************************************/
507
508 char* luid_to_privilege_name(const LUID *set)
509 {
510         static fstring name;
511         int i = 0;
512
513         if (set->high != 0)
514                 return NULL;
515
516         for ( i=0; privs[i].se_priv!=SE_END; i++ ) {
517                 if (set->low == privs[i].se_priv) {
518                         fstrcpy(name, privs[i].name);
519                         return name;
520                 }
521         }
522
523         return NULL;
524 }
525
526 /****************************************************************************
527  Convert an LUID to a 32-bit mask
528 ****************************************************************************/
529
530 uint32 luid_to_privilege_mask(const LUID *set)
531 {
532         int i = 0;
533
534         if (set->high != 0)
535                 return SE_END;
536
537         for ( i=0; privs[i].se_priv != SE_END; i++ ) {
538                 if (set->low == privs[i].se_priv)
539                         return privs[i].se_priv;
540         }
541
542         return SE_END;
543 }
544
545 /*******************************************************************
546  return the number of elements in the privlege array
547 *******************************************************************/
548
549 int count_all_privileges( void )
550 {
551         static int count;
552         
553         if ( count )
554                 return count;
555
556         /* loop over the array and count it */  
557         for ( count=0; privs[count].se_priv != SE_END; count++ ) ;
558
559         return count;
560 }
561