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