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 Copyright (C) Michael Adam 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #define PRIVPREFIX "PRIV_"
39 static BOOL
get_privileges( const DOM_SID
*sid
, SE_PRIV
*mask
)
41 TDB_CONTEXT
*tdb
= get_account_pol_tdb();
45 /* Fail if the admin has not enable privileges */
47 if ( !lp_enable_privileges() ) {
54 /* PRIV_<SID> (NULL terminated) as the key */
56 fstr_sprintf( keystr
, "%s%s", PRIVPREFIX
, sid_string_static(sid
) );
58 data
= tdb_fetch_bystring( tdb
, keystr
);
61 DEBUG(3,("get_privileges: No privileges assigned to SID [%s]\n",
62 sid_string_static(sid
)));
66 SMB_ASSERT( data
.dsize
== sizeof( SE_PRIV
) );
68 se_priv_copy( mask
, (SE_PRIV
*)data
.dptr
);
74 /***************************************************************************
75 Store the privilege mask (set) for a given SID
76 ****************************************************************************/
78 static BOOL
set_privileges( const DOM_SID
*sid
, SE_PRIV
*mask
)
80 TDB_CONTEXT
*tdb
= get_account_pol_tdb();
84 if ( !lp_enable_privileges() )
90 if ( !sid
|| (sid
->num_auths
== 0) ) {
91 DEBUG(0,("set_privileges: Refusing to store empty SID!\n"));
95 /* PRIV_<SID> (NULL terminated) as the key */
97 fstr_sprintf( keystr
, "%s%s", PRIVPREFIX
, sid_string_static(sid
) );
99 /* no packing. static size structure, just write it out */
101 data
.dptr
= (uint8
*)mask
;
102 data
.dsize
= sizeof(SE_PRIV
);
104 return ( tdb_store_bystring(tdb
, keystr
, data
, TDB_REPLACE
) != -1 );
107 /*********************************************************************
108 get a list of all privleges for all sids the in list
109 *********************************************************************/
111 BOOL
get_privileges_for_sids(SE_PRIV
*privileges
, DOM_SID
*slist
, int scount
)
117 se_priv_copy( privileges
, &se_priv_none
);
119 for ( i
=0; i
<scount
; i
++ ) {
120 /* don't add unless we actually have a privilege assigned */
122 if ( !get_privileges( &slist
[i
], &mask
) )
125 DEBUG(5,("get_privileges_for_sids: sid = %s\nPrivilege set:\n",
126 sid_string_static(&slist
[i
])));
127 dump_se_priv( DBGC_ALL
, 5, &mask
);
129 se_priv_add( privileges
, &mask
);
137 /*********************************************************************
138 travseral functions for privilege_enumerate_accounts
139 *********************************************************************/
141 static int priv_traverse_fn(TDB_CONTEXT
*t
, TDB_DATA key
, TDB_DATA data
, void *state
)
143 PRIV_SID_LIST
*priv
= (PRIV_SID_LIST
*)state
;
144 int prefixlen
= strlen(PRIVPREFIX
);
148 /* easy check first */
150 if ( data
.dsize
!= sizeof(SE_PRIV
) )
153 /* check we have a PRIV_+SID entry */
155 if ( strncmp((const char *)key
.dptr
, PRIVPREFIX
, prefixlen
) != 0)
158 /* check to see if we are looking for a particular privilege */
160 if ( !se_priv_equal(&priv
->privilege
, &se_priv_none
) ) {
163 se_priv_copy( &mask
, (SE_PRIV
*)data
.dptr
);
165 /* if the SID does not have the specified privilege
168 if ( !is_privilege_assigned( &mask
, &priv
->privilege
) )
172 fstrcpy( sid_string
, (const char *)&key
.dptr
[strlen(PRIVPREFIX
)] );
174 /* this is a last ditch safety check to preventing returning
175 and invalid SID (i've somehow run into this on development branches) */
177 if ( strcmp( "S-0-0", sid_string
) == 0 )
180 if ( !string_to_sid(&sid
, sid_string
) ) {
181 DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
186 if (!add_sid_to_array( NULL
, &sid
, &priv
->sids
.list
, &priv
->sids
.count
)) {
193 /*********************************************************************
194 Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
195 *********************************************************************/
197 NTSTATUS
privilege_enumerate_accounts(DOM_SID
**sids
, int *num_sids
)
199 TDB_CONTEXT
*tdb
= get_account_pol_tdb();
203 return NT_STATUS_ACCESS_DENIED
;
208 se_priv_copy( &priv
.privilege
, &se_priv_none
);
210 tdb_traverse( tdb
, priv_traverse_fn
, &priv
);
212 /* give the memory away; caller will free */
214 *sids
= priv
.sids
.list
;
215 *num_sids
= priv
.sids
.count
;
220 /***************************************************************************
222 ****************************************************************************/
224 BOOL
grant_privilege(const DOM_SID
*sid
, const SE_PRIV
*priv_mask
)
226 SE_PRIV old_mask
, new_mask
;
228 ZERO_STRUCT( old_mask
);
229 ZERO_STRUCT( new_mask
);
231 if ( get_privileges( sid
, &old_mask
) )
232 se_priv_copy( &new_mask
, &old_mask
);
234 se_priv_copy( &new_mask
, &se_priv_none
);
236 se_priv_add( &new_mask
, priv_mask
);
238 DEBUG(10,("grant_privilege: %s\n", sid_string_static(sid
)));
240 DEBUGADD( 10, ("original privilege mask:\n"));
241 dump_se_priv( DBGC_ALL
, 10, &old_mask
);
243 DEBUGADD( 10, ("new privilege mask:\n"));
244 dump_se_priv( DBGC_ALL
, 10, &new_mask
);
246 return set_privileges( sid
, &new_mask
);
249 /*********************************************************************
250 Add a privilege based on its name
251 *********************************************************************/
253 BOOL
grant_privilege_by_name(DOM_SID
*sid
, const char *name
)
257 if (! se_priv_from_name(name
, &mask
)) {
258 DEBUG(3, ("grant_privilege_by_name: "
259 "No Such Privilege Found (%s)\n", name
));
263 return grant_privilege( sid
, &mask
);
266 /***************************************************************************
267 Remove privilege from sid
268 ****************************************************************************/
270 BOOL
revoke_privilege(const DOM_SID
*sid
, const SE_PRIV
*priv_mask
)
274 /* if the user has no privileges, then we can't revoke any */
276 if ( !get_privileges( sid
, &mask
) )
279 DEBUG(10,("revoke_privilege: %s\n", sid_string_static(sid
)));
281 DEBUGADD( 10, ("original privilege mask:\n"));
282 dump_se_priv( DBGC_ALL
, 10, &mask
);
284 se_priv_remove( &mask
, priv_mask
);
286 DEBUGADD( 10, ("new privilege mask:\n"));
287 dump_se_priv( DBGC_ALL
, 10, &mask
);
289 return set_privileges( sid
, &mask
);
292 /*********************************************************************
293 Revoke all privileges
294 *********************************************************************/
296 BOOL
revoke_all_privileges( DOM_SID
*sid
)
298 return revoke_privilege( sid
, &se_priv_all
);
301 /*********************************************************************
302 Add a privilege based on its name
303 *********************************************************************/
305 BOOL
revoke_privilege_by_name(DOM_SID
*sid
, const char *name
)
309 if (! se_priv_from_name(name
, &mask
)) {
310 DEBUG(3, ("revoke_privilege_by_name: "
311 "No Such Privilege Found (%s)\n", name
));
315 return revoke_privilege(sid
, &mask
);
319 /***************************************************************************
320 Retrieve the SIDs assigned to a given privilege
321 ****************************************************************************/
323 NTSTATUS
privilege_create_account(const DOM_SID
*sid
)
325 return ( grant_privilege(sid
, &se_priv_none
) ? NT_STATUS_OK
: NT_STATUS_UNSUCCESSFUL
);
328 /****************************************************************************
329 initialise a privilege list and set the talloc context
330 ****************************************************************************/
332 NTSTATUS
privilege_set_init(PRIVILEGE_SET
*priv_set
)
336 ZERO_STRUCTP( priv_set
);
338 mem_ctx
= talloc_init("privilege set");
340 DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n"));
341 return NT_STATUS_NO_MEMORY
;
344 priv_set
->mem_ctx
= mem_ctx
;
349 /****************************************************************************
350 initialise a privilege list and with someone else's talloc context
351 ****************************************************************************/
353 NTSTATUS
privilege_set_init_by_ctx(TALLOC_CTX
*mem_ctx
, PRIVILEGE_SET
*priv_set
)
355 ZERO_STRUCTP( priv_set
);
357 priv_set
->mem_ctx
= mem_ctx
;
358 priv_set
->ext_ctx
= True
;
363 /****************************************************************************
364 Free all memory used by a PRIVILEGE_SET
365 ****************************************************************************/
367 void privilege_set_free(PRIVILEGE_SET
*priv_set
)
372 if ( !( priv_set
->ext_ctx
) )
373 talloc_destroy( priv_set
->mem_ctx
);
375 ZERO_STRUCTP( priv_set
);
378 /****************************************************************************
379 duplicate alloc luid_attr
380 ****************************************************************************/
382 NTSTATUS
dup_luid_attr(TALLOC_CTX
*mem_ctx
, LUID_ATTR
**new_la
, LUID_ATTR
*old_la
, int count
)
390 *new_la
= TALLOC_ARRAY(mem_ctx
, LUID_ATTR
, count
);
392 DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count
));
393 return NT_STATUS_NO_MEMORY
;
399 for (i
=0; i
<count
; i
++) {
400 (*new_la
)[i
].luid
.high
= old_la
[i
].luid
.high
;
401 (*new_la
)[i
].luid
.low
= old_la
[i
].luid
.low
;
402 (*new_la
)[i
].attr
= old_la
[i
].attr
;
408 /*******************************************************************
409 *******************************************************************/
411 BOOL
is_privileged_sid( const DOM_SID
*sid
)
415 return get_privileges( sid
, &mask
);
418 /*******************************************************************
419 *******************************************************************/
421 BOOL
grant_all_privileges( const DOM_SID
*sid
)
425 if (!se_priv_put_all_privileges(&mask
)) {
429 return grant_privilege( sid
, &mask
);