1/* 2 * Unix SMB/Netbios implementation. 3 * SEC_DESC handling functions 4 * Copyright (C) Andrew Tridgell 1992-1998, 5 * Copyright (C) Jeremy R. Allison 1995-2003. 6 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998, 7 * Copyright (C) Paul Ashton 1997-1998. 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 2 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, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24#include "includes.h" 25 26/* Map generic permissions to file object specific permissions */ 27 28struct generic_mapping file_generic_mapping = { 29 FILE_GENERIC_READ, 30 FILE_GENERIC_WRITE, 31 FILE_GENERIC_EXECUTE, 32 FILE_GENERIC_ALL 33}; 34 35/******************************************************************* 36 Works out the linearization size of a SEC_DESC. 37********************************************************************/ 38 39size_t sec_desc_size(SEC_DESC *psd) 40{ 41 size_t offset; 42 43 if (!psd) return 0; 44 45 offset = SEC_DESC_HEADER_SIZE; 46 47 /* don't align */ 48 49 if (psd->owner_sid != NULL) 50 offset += sid_size(psd->owner_sid); 51 52 if (psd->group_sid != NULL) 53 offset += sid_size(psd->group_sid); 54 55 if (psd->sacl != NULL) 56 offset += psd->sacl->size; 57 58 if (psd->dacl != NULL) 59 offset += psd->dacl->size; 60 61 return offset; 62} 63 64/******************************************************************* 65 Compares two SEC_DESC structures 66********************************************************************/ 67 68BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2) 69{ 70 /* Trivial case */ 71 72 if (!s1 && !s2) { 73 goto done; 74 } 75 76 if (!s1 || !s2) { 77 return False; 78 } 79 80 /* Check top level stuff */ 81 82 if (s1->revision != s2->revision) { 83 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n", 84 s1->revision, s2->revision)); 85 return False; 86 } 87 88 if (s1->type!= s2->type) { 89 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n", 90 s1->type, s2->type)); 91 return False; 92 } 93 94 /* Check owner and group */ 95 96 if (!sid_equal(s1->owner_sid, s2->owner_sid)) { 97 fstring str1, str2; 98 99 sid_to_string(str1, s1->owner_sid); 100 sid_to_string(str2, s2->owner_sid); 101 102 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n", 103 str1, str2)); 104 return False; 105 } 106 107 if (!sid_equal(s1->group_sid, s2->group_sid)) { 108 fstring str1, str2; 109 110 sid_to_string(str1, s1->group_sid); 111 sid_to_string(str2, s2->group_sid); 112 113 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n", 114 str1, str2)); 115 return False; 116 } 117 118 /* Check ACLs present in one but not the other */ 119 120 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) || 121 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) { 122 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n")); 123 return False; 124 } 125 126 /* Sigh - we have to do it the hard way by iterating over all 127 the ACEs in the ACLs */ 128 129 if (!sec_acl_equal(s1->dacl, s2->dacl) || 130 !sec_acl_equal(s1->sacl, s2->sacl)) { 131 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n")); 132 return False; 133 } 134 135 done: 136 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n")); 137 return True; 138} 139 140/******************************************************************* 141 Merge part of security descriptor old_sec in to the empty sections of 142 security descriptor new_sec. 143********************************************************************/ 144 145SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb) 146{ 147 DOM_SID *owner_sid, *group_sid; 148 SEC_DESC_BUF *return_sdb; 149 SEC_ACL *dacl, *sacl; 150 SEC_DESC *psd = NULL; 151 uint16 secdesc_type; 152 size_t secdesc_size; 153 154 /* Copy over owner and group sids. There seems to be no flag for 155 this so just check the pointer values. */ 156 157 owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid : 158 old_sdb->sec->owner_sid; 159 160 group_sid = new_sdb->sec->group_sid ? new_sdb->sec->group_sid : 161 old_sdb->sec->group_sid; 162 163 secdesc_type = new_sdb->sec->type; 164 165 /* Ignore changes to the system ACL. This has the effect of making 166 changes through the security tab audit button not sticking. 167 Perhaps in future Samba could implement these settings somehow. */ 168 169 sacl = NULL; 170 secdesc_type &= ~SEC_DESC_SACL_PRESENT; 171 172 /* Copy across discretionary ACL */ 173 174 if (secdesc_type & SEC_DESC_DACL_PRESENT) { 175 dacl = new_sdb->sec->dacl; 176 } else { 177 dacl = old_sdb->sec->dacl; 178 } 179 180 /* Create new security descriptor from bits */ 181 182 psd = make_sec_desc(ctx, new_sdb->sec->revision, secdesc_type, 183 owner_sid, group_sid, sacl, dacl, &secdesc_size); 184 185 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd); 186 187 return(return_sdb); 188} 189 190/******************************************************************* 191 Creates a SEC_DESC structure 192********************************************************************/ 193 194SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, uint16 type, 195 const DOM_SID *owner_sid, const DOM_SID *group_sid, 196 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size) 197{ 198 SEC_DESC *dst; 199 uint32 offset = 0; 200 201 *sd_size = 0; 202 203 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL) 204 return NULL; 205 206 dst->revision = revision; 207 dst->type = type; 208 209 if (sacl) 210 dst->type |= SEC_DESC_SACL_PRESENT; 211 if (dacl) 212 dst->type |= SEC_DESC_DACL_PRESENT; 213 214 dst->off_owner_sid = 0; 215 dst->off_grp_sid = 0; 216 dst->off_sacl = 0; 217 dst->off_dacl = 0; 218 219 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL)) 220 goto error_exit; 221 222 if(group_sid && ((dst->group_sid = sid_dup_talloc(ctx,group_sid)) == NULL)) 223 goto error_exit; 224 225 if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL)) 226 goto error_exit; 227 228 if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL)) 229 goto error_exit; 230 231 offset = SEC_DESC_HEADER_SIZE; 232 233 /* 234 * Work out the linearization sizes. 235 */ 236 237 if (dst->sacl != NULL) { 238 dst->off_sacl = offset; 239 offset += dst->sacl->size; 240 } 241 if (dst->dacl != NULL) { 242 dst->off_dacl = offset; 243 offset += dst->dacl->size; 244 } 245 246 if (dst->owner_sid != NULL) { 247 dst->off_owner_sid = offset; 248 offset += sid_size(dst->owner_sid); 249 } 250 251 if (dst->group_sid != NULL) { 252 dst->off_grp_sid = offset; 253 offset += sid_size(dst->group_sid); 254 } 255 256 *sd_size = (size_t)offset; 257 return dst; 258 259error_exit: 260 261 *sd_size = 0; 262 return NULL; 263} 264 265/******************************************************************* 266 Duplicate a SEC_DESC structure. 267********************************************************************/ 268 269SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src) 270{ 271 size_t dummy; 272 273 if(src == NULL) 274 return NULL; 275 276 return make_sec_desc( ctx, src->revision, src->type, 277 src->owner_sid, src->group_sid, src->sacl, 278 src->dacl, &dummy); 279} 280 281/******************************************************************* 282 Creates a SEC_DESC structure with typical defaults. 283********************************************************************/ 284 285SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *group_sid, 286 SEC_ACL *dacl, size_t *sd_size) 287{ 288 return make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, 289 owner_sid, group_sid, NULL, dacl, sd_size); 290} 291 292/******************************************************************* 293 Creates a SEC_DESC_BUF structure. 294********************************************************************/ 295 296SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc) 297{ 298 SEC_DESC_BUF *dst; 299 300 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL) 301 return NULL; 302 303 /* max buffer size (allocated size) */ 304 dst->max_len = (uint32)len; 305 dst->len = (uint32)len; 306 307 if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) { 308 return NULL; 309 } 310 311 dst->ptr = 0x1; 312 313 return dst; 314} 315 316/******************************************************************* 317 Duplicates a SEC_DESC_BUF structure. 318********************************************************************/ 319 320SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src) 321{ 322 if(src == NULL) 323 return NULL; 324 325 return make_sec_desc_buf( ctx, src->len, src->sec); 326} 327 328/******************************************************************* 329 Add a new SID with its permissions to SEC_DESC. 330********************************************************************/ 331 332NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size) 333{ 334 SEC_DESC *sd = 0; 335 SEC_ACL *dacl = 0; 336 SEC_ACE *ace = 0; 337 NTSTATUS status; 338 339 if (!ctx || !psd || !sid || !sd_size) 340 return NT_STATUS_INVALID_PARAMETER; 341 342 *sd_size = 0; 343 344 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask); 345 346 if (!NT_STATUS_IS_OK(status)) 347 return status; 348 349 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace))) 350 return NT_STATUS_UNSUCCESSFUL; 351 352 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid, 353 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size))) 354 return NT_STATUS_UNSUCCESSFUL; 355 356 *psd = sd; 357 sd = 0; 358 return NT_STATUS_OK; 359} 360 361/******************************************************************* 362 Modify a SID's permissions in a SEC_DESC. 363********************************************************************/ 364 365NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask) 366{ 367 NTSTATUS status; 368 369 if (!sd || !sid) 370 return NT_STATUS_INVALID_PARAMETER; 371 372 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask); 373 374 if (!NT_STATUS_IS_OK(status)) 375 return status; 376 377 return NT_STATUS_OK; 378} 379 380/******************************************************************* 381 Delete a SID from a SEC_DESC. 382********************************************************************/ 383 384NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size) 385{ 386 SEC_DESC *sd = 0; 387 SEC_ACL *dacl = 0; 388 SEC_ACE *ace = 0; 389 NTSTATUS status; 390 391 if (!ctx || !psd[0] || !sid || !sd_size) 392 return NT_STATUS_INVALID_PARAMETER; 393 394 *sd_size = 0; 395 396 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid); 397 398 if (!NT_STATUS_IS_OK(status)) 399 return status; 400 401 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace))) 402 return NT_STATUS_UNSUCCESSFUL; 403 404 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid, 405 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size))) 406 return NT_STATUS_UNSUCCESSFUL; 407 408 *psd = sd; 409 sd = 0; 410 return NT_STATUS_OK; 411} 412 413/* Create a child security descriptor using another security descriptor as 414 the parent container. This child object can either be a container or 415 non-container object. */ 416 417SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr, 418 BOOL child_container) 419{ 420 SEC_DESC_BUF *sdb; 421 SEC_DESC *sd; 422 SEC_ACL *new_dacl, *the_acl; 423 SEC_ACE *new_ace_list = NULL; 424 unsigned int new_ace_list_ndx = 0, i; 425 size_t size; 426 427 /* Currently we only process the dacl when creating the child. The 428 sacl should also be processed but this is left out as sacls are 429 not implemented in Samba at the moment.*/ 430 431 the_acl = parent_ctr->dacl; 432 433 if (the_acl->num_aces) { 434 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces))) 435 return NULL; 436 } else { 437 new_ace_list = NULL; 438 } 439 440 for (i = 0; i < the_acl->num_aces; i++) { 441 SEC_ACE *ace = &the_acl->aces[i]; 442 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx]; 443 uint8 new_flags = 0; 444 BOOL inherit = False; 445 fstring sid_str; 446 447 /* The OBJECT_INHERIT_ACE flag causes the ACE to be 448 inherited by non-container children objects. Container 449 children objects will inherit it as an INHERIT_ONLY 450 ACE. */ 451 452 if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) { 453 454 if (!child_container) { 455 new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT; 456 } else { 457 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY; 458 } 459 460 inherit = True; 461 } 462 463 /* The CONAINER_INHERIT_ACE flag means all child container 464 objects will inherit and use the ACE. */ 465 466 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) { 467 if (!child_container) { 468 inherit = False; 469 } else { 470 new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT; 471 } 472 } 473 474 /* The INHERIT_ONLY_ACE is not used by the se_access_check() 475 function for the parent container, but is inherited by 476 all child objects as a normal ACE. */ 477 478 if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) { 479 /* Move along, nothing to see here */ 480 } 481 482 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE 483 is inherited by child objects but not grandchildren 484 objects. We clear the object inherit and container 485 inherit flags in the inherited ACE. */ 486 487 if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { 488 new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT | 489 SEC_ACE_FLAG_CONTAINER_INHERIT); 490 } 491 492 /* Add ACE to ACE list */ 493 494 if (!inherit) 495 continue; 496 497 init_sec_access(&new_ace->access_mask, ace->access_mask); 498 init_sec_ace(new_ace, &ace->trustee, ace->type, 499 new_ace->access_mask, new_flags); 500 501 sid_to_string(sid_str, &ace->trustee); 502 503 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x " 504 " inherited as %s:%d/0x%02x/0x%08x\n", sid_str, 505 ace->type, ace->flags, ace->access_mask, 506 sid_str, new_ace->type, new_ace->flags, 507 new_ace->access_mask)); 508 509 new_ace_list_ndx++; 510 } 511 512 /* Create child security descriptor to return */ 513 514 new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list); 515 516 /* Use the existing user and group sids. I don't think this is 517 correct. Perhaps the user and group should be passed in as 518 parameters by the caller? */ 519 520 sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, 521 parent_ctr->owner_sid, 522 parent_ctr->group_sid, 523 parent_ctr->sacl, 524 new_dacl, &size); 525 526 sdb = make_sec_desc_buf(ctx, size, sd); 527 528 return sdb; 529} 530 531/******************************************************************* 532 Sets up a SEC_ACCESS structure. 533********************************************************************/ 534 535void init_sec_access(SEC_ACCESS *t, uint32 mask) 536{ 537 *t = mask; 538} 539