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