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 Copyright (C) Michael Adam 2007 8 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. 13 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. 18 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/>. 21*/ 22 23 24#include "includes.h" 25 26#define PRIVPREFIX "PRIV_" 27 28typedef struct { 29 size_t count; 30 DOM_SID *list; 31} SID_LIST; 32 33typedef struct { 34 TALLOC_CTX *mem_ctx; 35 SE_PRIV privilege; 36 SID_LIST sids; 37} PRIV_SID_LIST; 38 39 40static bool get_privileges( const DOM_SID *sid, SE_PRIV *mask ) 41{ 42 struct db_context *db = get_account_pol_db(); 43 fstring tmp, keystr; 44 TDB_DATA data; 45 46 /* Fail if the admin has not enable privileges */ 47 48 if ( !lp_enable_privileges() ) { 49 return False; 50 } 51 52 if ( db == NULL ) 53 return False; 54 55 /* PRIV_<SID> (NULL terminated) as the key */ 56 57 fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid)); 58 59 data = dbwrap_fetch_bystring( db, talloc_tos(), keystr ); 60 61 if ( !data.dptr ) { 62 DEBUG(3, ("get_privileges: No privileges assigned to SID " 63 "[%s]\n", sid_string_dbg(sid))); 64 return False; 65 } 66 67 SMB_ASSERT( data.dsize == sizeof( SE_PRIV ) ); 68 69 se_priv_copy( mask, (SE_PRIV*)data.dptr ); 70 TALLOC_FREE(data.dptr); 71 72 return True; 73} 74 75/*************************************************************************** 76 Store the privilege mask (set) for a given SID 77****************************************************************************/ 78 79static bool set_privileges( const DOM_SID *sid, SE_PRIV *mask ) 80{ 81 struct db_context *db = get_account_pol_db(); 82 fstring tmp, keystr; 83 TDB_DATA data; 84 85 if ( !lp_enable_privileges() ) 86 return False; 87 88 if ( db == NULL ) 89 return False; 90 91 if ( !sid || (sid->num_auths == 0) ) { 92 DEBUG(0,("set_privileges: Refusing to store empty SID!\n")); 93 return False; 94 } 95 96 /* PRIV_<SID> (NULL terminated) as the key */ 97 98 fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid)); 99 100 /* no packing. static size structure, just write it out */ 101 102 data.dptr = (uint8 *)mask; 103 data.dsize = sizeof(SE_PRIV); 104 105 return NT_STATUS_IS_OK(dbwrap_store_bystring(db, keystr, data, 106 TDB_REPLACE)); 107} 108 109/********************************************************************* 110 get a list of all privileges for all sids in the list 111*********************************************************************/ 112 113bool get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount) 114{ 115 SE_PRIV mask; 116 int i; 117 bool found = False; 118 119 se_priv_copy( privileges, &se_priv_none ); 120 121 for ( i=0; i<scount; i++ ) { 122 /* don't add unless we actually have a privilege assigned */ 123 124 if ( !get_privileges( &slist[i], &mask ) ) 125 continue; 126 127 DEBUG(5,("get_privileges_for_sids: sid = %s\nPrivilege " 128 "set:\n", sid_string_dbg(&slist[i]))); 129 dump_se_priv( DBGC_ALL, 5, &mask ); 130 131 se_priv_add( privileges, &mask ); 132 found = True; 133 } 134 135 return found; 136} 137 138 139/********************************************************************* 140 traversal functions for privilege_enumerate_accounts 141*********************************************************************/ 142 143static int priv_traverse_fn(struct db_record *rec, void *state) 144{ 145 PRIV_SID_LIST *priv = (PRIV_SID_LIST *)state; 146 int prefixlen = strlen(PRIVPREFIX); 147 DOM_SID sid; 148 fstring sid_string; 149 150 /* easy check first */ 151 152 if (rec->value.dsize != sizeof(SE_PRIV) ) 153 return 0; 154 155 /* check we have a PRIV_+SID entry */ 156 157 if ( strncmp((char *)rec->key.dptr, PRIVPREFIX, prefixlen) != 0) 158 return 0; 159 160 /* check to see if we are looking for a particular privilege */ 161 162 if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) { 163 SE_PRIV mask; 164 165 se_priv_copy( &mask, (SE_PRIV*)rec->value.dptr ); 166 167 /* if the SID does not have the specified privilege 168 then just return */ 169 170 if ( !is_privilege_assigned( &mask, &priv->privilege) ) 171 return 0; 172 } 173 174 fstrcpy( sid_string, (char *)&(rec->key.dptr[strlen(PRIVPREFIX)]) ); 175 176 /* this is a last ditch safety check to preventing returning 177 and invalid SID (i've somehow run into this on development branches) */ 178 179 if ( strcmp( "S-0-0", sid_string ) == 0 ) 180 return 0; 181 182 if ( !string_to_sid(&sid, sid_string) ) { 183 DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n", 184 sid_string)); 185 return 0; 186 } 187 188 if (!NT_STATUS_IS_OK(add_sid_to_array(priv->mem_ctx, &sid, 189 &priv->sids.list, 190 &priv->sids.count))) 191 { 192 return 0; 193 } 194 195 return 0; 196} 197 198/********************************************************************* 199 Retreive list of privileged SIDs (for _lsa_enumerate_accounts() 200*********************************************************************/ 201 202NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids) 203{ 204 struct db_context *db = get_account_pol_db(); 205 PRIV_SID_LIST priv; 206 207 if (db == NULL) { 208 return NT_STATUS_ACCESS_DENIED; 209 } 210 211 ZERO_STRUCT(priv); 212 213 se_priv_copy( &priv.privilege, &se_priv_none ); 214 215 db->traverse_read(db, priv_traverse_fn, &priv); 216 217 /* give the memory away; caller will free */ 218 219 *sids = priv.sids.list; 220 *num_sids = priv.sids.count; 221 222 return NT_STATUS_OK; 223} 224 225/********************************************************************* 226 Retrieve list of SIDs granted a particular privilege 227*********************************************************************/ 228 229NTSTATUS privilege_enum_sids(const SE_PRIV *mask, TALLOC_CTX *mem_ctx, 230 DOM_SID **sids, int *num_sids) 231{ 232 struct db_context *db = get_account_pol_db(); 233 PRIV_SID_LIST priv; 234 235 if (db == NULL) { 236 return NT_STATUS_ACCESS_DENIED; 237 } 238 239 ZERO_STRUCT(priv); 240 241 se_priv_copy(&priv.privilege, mask); 242 priv.mem_ctx = mem_ctx; 243 244 db->traverse_read(db, priv_traverse_fn, &priv); 245 246 /* give the memory away; caller will free */ 247 248 *sids = priv.sids.list; 249 *num_sids = priv.sids.count; 250 251 return NT_STATUS_OK; 252} 253 254/*************************************************************************** 255 Add privilege to sid 256****************************************************************************/ 257 258bool grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask) 259{ 260 SE_PRIV old_mask, new_mask; 261 262 ZERO_STRUCT( old_mask ); 263 ZERO_STRUCT( new_mask ); 264 265 if ( get_privileges( sid, &old_mask ) ) 266 se_priv_copy( &new_mask, &old_mask ); 267 else 268 se_priv_copy( &new_mask, &se_priv_none ); 269 270 se_priv_add( &new_mask, priv_mask ); 271 272 DEBUG(10,("grant_privilege: %s\n", sid_string_dbg(sid))); 273 274 DEBUGADD( 10, ("original privilege mask:\n")); 275 dump_se_priv( DBGC_ALL, 10, &old_mask ); 276 277 DEBUGADD( 10, ("new privilege mask:\n")); 278 dump_se_priv( DBGC_ALL, 10, &new_mask ); 279 280 return set_privileges( sid, &new_mask ); 281} 282 283/********************************************************************* 284 Add a privilege based on its name 285*********************************************************************/ 286 287bool grant_privilege_by_name(DOM_SID *sid, const char *name) 288{ 289 SE_PRIV mask; 290 291 if (! se_priv_from_name(name, &mask)) { 292 DEBUG(3, ("grant_privilege_by_name: " 293 "No Such Privilege Found (%s)\n", name)); 294 return False; 295 } 296 297 return grant_privilege( sid, &mask ); 298} 299 300/*************************************************************************** 301 Remove privilege from sid 302****************************************************************************/ 303 304bool revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask) 305{ 306 SE_PRIV mask; 307 308 /* if the user has no privileges, then we can't revoke any */ 309 310 if ( !get_privileges( sid, &mask ) ) 311 return True; 312 313 DEBUG(10,("revoke_privilege: %s\n", sid_string_dbg(sid))); 314 315 DEBUGADD( 10, ("original privilege mask:\n")); 316 dump_se_priv( DBGC_ALL, 10, &mask ); 317 318 se_priv_remove( &mask, priv_mask ); 319 320 DEBUGADD( 10, ("new privilege mask:\n")); 321 dump_se_priv( DBGC_ALL, 10, &mask ); 322 323 return set_privileges( sid, &mask ); 324} 325 326/********************************************************************* 327 Revoke all privileges 328*********************************************************************/ 329 330bool revoke_all_privileges( DOM_SID *sid ) 331{ 332 return revoke_privilege( sid, &se_priv_all ); 333} 334 335/********************************************************************* 336 Add a privilege based on its name 337*********************************************************************/ 338 339bool revoke_privilege_by_name(DOM_SID *sid, const char *name) 340{ 341 SE_PRIV mask; 342 343 if (! se_priv_from_name(name, &mask)) { 344 DEBUG(3, ("revoke_privilege_by_name: " 345 "No Such Privilege Found (%s)\n", name)); 346 return False; 347 } 348 349 return revoke_privilege(sid, &mask); 350 351} 352 353/*************************************************************************** 354 Retrieve the SIDs assigned to a given privilege 355****************************************************************************/ 356 357NTSTATUS privilege_create_account(const DOM_SID *sid ) 358{ 359 return ( grant_privilege(sid, &se_priv_none) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL); 360} 361 362/*************************************************************************** 363 Delete a privileged account 364****************************************************************************/ 365 366NTSTATUS privilege_delete_account(const struct dom_sid *sid) 367{ 368 struct db_context *db = get_account_pol_db(); 369 fstring tmp, keystr; 370 371 if (!lp_enable_privileges()) { 372 return NT_STATUS_OK; 373 } 374 375 if (!db) { 376 return NT_STATUS_INVALID_HANDLE; 377 } 378 379 if (!sid || (sid->num_auths == 0)) { 380 return NT_STATUS_INVALID_SID; 381 } 382 383 /* PRIV_<SID> (NULL terminated) as the key */ 384 385 fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid)); 386 387 return dbwrap_delete_bystring(db, keystr); 388} 389 390/**************************************************************************** 391 initialise a privilege list and set the talloc context 392 ****************************************************************************/ 393 394NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set) 395{ 396 TALLOC_CTX *mem_ctx; 397 398 ZERO_STRUCTP( priv_set ); 399 400 mem_ctx = talloc_init("privilege set"); 401 if ( !mem_ctx ) { 402 DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n")); 403 return NT_STATUS_NO_MEMORY; 404 } 405 406 priv_set->mem_ctx = mem_ctx; 407 408 return NT_STATUS_OK; 409} 410 411/**************************************************************************** 412 initialise a privilege list and with someone else's talloc context 413****************************************************************************/ 414 415NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set) 416{ 417 ZERO_STRUCTP( priv_set ); 418 419 priv_set->mem_ctx = mem_ctx; 420 priv_set->ext_ctx = True; 421 422 return NT_STATUS_OK; 423} 424 425/**************************************************************************** 426 Free all memory used by a PRIVILEGE_SET 427****************************************************************************/ 428 429void privilege_set_free(PRIVILEGE_SET *priv_set) 430{ 431 if ( !priv_set ) 432 return; 433 434 if ( !( priv_set->ext_ctx ) ) 435 talloc_destroy( priv_set->mem_ctx ); 436 437 ZERO_STRUCTP( priv_set ); 438} 439 440/**************************************************************************** 441 duplicate alloc luid_attr 442 ****************************************************************************/ 443 444NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count) 445{ 446 int i; 447 448 if ( !old_la ) 449 return NT_STATUS_OK; 450 451 if (count) { 452 *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count); 453 if ( !*new_la ) { 454 DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count)); 455 return NT_STATUS_NO_MEMORY; 456 } 457 } else { 458 *new_la = NULL; 459 } 460 461 for (i=0; i<count; i++) { 462 (*new_la)[i].luid.high = old_la[i].luid.high; 463 (*new_la)[i].luid.low = old_la[i].luid.low; 464 (*new_la)[i].attr = old_la[i].attr; 465 } 466 467 return NT_STATUS_OK; 468} 469 470/******************************************************************* 471*******************************************************************/ 472 473bool is_privileged_sid( const DOM_SID *sid ) 474{ 475 SE_PRIV mask; 476 477 return get_privileges( sid, &mask ); 478} 479 480/******************************************************************* 481*******************************************************************/ 482 483bool grant_all_privileges( const DOM_SID *sid ) 484{ 485 SE_PRIV mask; 486 487 if (!se_priv_put_all_privileges(&mask)) { 488 return False; 489 } 490 491 return grant_privilege( sid, &mask ); 492} 493