1/* 2 * Unix SMB/CIFS implementation. 3 * 4 * Support for OneFS native NTFS ACLs 5 * 6 * Copyright (C) Steven Danneman, 2008 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 3 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, see <http://www.gnu.org/licenses/>. 20 */ 21 22#include "includes.h" 23#include "onefs.h" 24#include "onefs_config.h" 25 26#include <isi_acl/isi_acl_util.h> 27#include <ifs/ifs_syscalls.h> 28#include <sys/isi_acl.h> 29 30const struct enum_list enum_onefs_acl_wire_format[] = { 31 {ACL_FORMAT_RAW, "No Format"}, 32 {ACL_FORMAT_WINDOWS_SD, "Format Windows SD"}, 33 {ACL_FORMAT_ALWAYS, "Always Format SD"}, 34 {-1, NULL} 35}; 36 37/** 38 * Turn SID into UID/GID and setup a struct ifs_identity 39 */ 40static bool 41onefs_sid_to_identity(const DOM_SID *sid, struct ifs_identity *id, 42 bool is_group) 43{ 44 enum ifs_identity_type type = IFS_ID_TYPE_LAST+1; 45 uid_t uid = 0; 46 gid_t gid = 0; 47 48 if (!sid || sid_equal(sid, &global_sid_NULL)) 49 type = IFS_ID_TYPE_NULL; 50 else if (sid_equal(sid, &global_sid_World)) 51 type = IFS_ID_TYPE_EVERYONE; 52 else if (sid_equal(sid, &global_sid_Creator_Owner)) 53 type = IFS_ID_TYPE_CREATOR_OWNER; 54 else if (sid_equal(sid, &global_sid_Creator_Group)) 55 type = IFS_ID_TYPE_CREATOR_GROUP; 56 else if (is_group) { 57 if (!sid_to_gid(sid, &gid)) 58 return false; 59 type = IFS_ID_TYPE_GID; 60 } else { 61 if (sid_to_uid(sid, &uid)) 62 type = IFS_ID_TYPE_UID; 63 else if (sid_to_gid(sid, &gid)) 64 type = IFS_ID_TYPE_GID; 65 else 66 return false; 67 } 68 69 if (aclu_initialize_identity(id, type, uid, gid, is_group)) { 70 DEBUG(3, ("Call to aclu_initialize_identity failed! id=%x, " 71 "type=%d, uid=%u, gid=%u, is_group=%d\n", 72 (unsigned int)id, type, uid, gid, is_group)); 73 return false; 74 } 75 76 return true; 77} 78 79/** 80 * Turn struct ifs_identity into SID 81 */ 82static bool 83onefs_identity_to_sid(struct ifs_identity *id, DOM_SID *sid) 84{ 85 if (!id || !sid) 86 return false; 87 88 if (id->type >= IFS_ID_TYPE_LAST) 89 return false; 90 91 switch (id->type) { 92 case IFS_ID_TYPE_UID: 93 uid_to_sid(sid, id->id.uid); 94 break; 95 case IFS_ID_TYPE_GID: 96 gid_to_sid(sid, id->id.gid); 97 break; 98 case IFS_ID_TYPE_EVERYONE: 99 sid_copy(sid, &global_sid_World); 100 break; 101 case IFS_ID_TYPE_NULL: 102 sid_copy(sid, &global_sid_NULL); 103 break; 104 case IFS_ID_TYPE_CREATOR_OWNER: 105 sid_copy(sid, &global_sid_Creator_Owner); 106 break; 107 case IFS_ID_TYPE_CREATOR_GROUP: 108 sid_copy(sid, &global_sid_Creator_Group); 109 break; 110 default: 111 DEBUG(0, ("Unknown identity type: %d\n", id->type)); 112 return false; 113 } 114 115 return true; 116} 117 118static bool 119onefs_og_to_identity(DOM_SID *sid, struct ifs_identity * ident, 120 bool is_group, int snum) 121{ 122 const DOM_SID *b_admin_sid = &global_sid_Builtin_Administrators; 123 124 if (!onefs_sid_to_identity(sid, ident, is_group)) { 125 if (!lp_parm_bool(snum, PARM_ONEFS_TYPE, 126 PARM_UNMAPPABLE_SIDS_IGNORE, 127 PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) { 128 DEBUG(3, ("Unresolvable SID (%s) found.\n", 129 sid_string_dbg(sid))); 130 return false; 131 } 132 if (!onefs_sid_to_identity(b_admin_sid, ident, is_group)) { 133 return false; 134 } 135 DEBUG(3, ("Mapping unresolvable owner SID (%s) to Builtin " 136 "Administrators group.\n", 137 sid_string_dbg(sid))); 138 } 139 return true; 140} 141 142static bool 143sid_in_ignore_list(DOM_SID * sid, int snum) 144{ 145 const char ** sid_list = NULL; 146 DOM_SID match; 147 148 sid_list = lp_parm_string_list(snum, PARM_ONEFS_TYPE, 149 PARM_UNMAPPABLE_SIDS_IGNORE_LIST, 150 PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT); 151 152 /* Fast path a NULL list */ 153 if (!sid_list || *sid_list == NULL) 154 return false; 155 156 while (*sid_list) { 157 if (string_to_sid(&match, *sid_list)) 158 if (sid_equal(sid, &match)) 159 return true; 160 sid_list++; 161 } 162 163 return false; 164} 165 166/** 167 * Convert a trustee to a struct identity 168 */ 169static bool 170onefs_samba_ace_to_ace(SEC_ACE * samba_ace, struct ifs_ace * ace, 171 bool *mapped, int snum) 172{ 173 struct ifs_identity ident = {.type=IFS_ID_TYPE_LAST, .id.uid=0}; 174 175 SMB_ASSERT(ace); 176 SMB_ASSERT(mapped); 177 SMB_ASSERT(samba_ace); 178 179 if (onefs_sid_to_identity(&samba_ace->trustee, &ident, false)) { 180 *mapped = true; 181 } else { 182 183 SMB_ASSERT(ident.id.uid >= 0); 184 185 /* Ignore the sid if it's in the list */ 186 if (sid_in_ignore_list(&samba_ace->trustee, snum)) { 187 DEBUG(3, ("Silently failing to set ACE for SID (%s) " 188 "because it is in the ignore sids list\n", 189 sid_string_dbg(&samba_ace->trustee))); 190 *mapped = false; 191 } else if ((samba_ace->type == SEC_ACE_TYPE_ACCESS_DENIED) && 192 lp_parm_bool(snum, PARM_ONEFS_TYPE, 193 PARM_UNMAPPABLE_SIDS_DENY_EVERYONE, 194 PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT)) { 195 /* If the ace is deny translated to Everyone */ 196 DEBUG(3, ("Mapping unresolvable deny ACE SID (%s) " 197 "to Everyone.\n", 198 sid_string_dbg(&samba_ace->trustee))); 199 if (aclu_initialize_identity(&ident, 200 IFS_ID_TYPE_EVERYONE, 0, 0, False) != 0) { 201 DEBUG(2, ("aclu_initialize_identity() " 202 "failed making Everyone\n")); 203 return false; 204 } 205 *mapped = true; 206 } else if (lp_parm_bool(snum, PARM_ONEFS_TYPE, 207 PARM_UNMAPPABLE_SIDS_IGNORE, 208 PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) { 209 DEBUG(3, ("Silently failing to set ACE for SID (%s) " 210 "because it is unresolvable\n", 211 sid_string_dbg(&samba_ace->trustee))); 212 *mapped = false; 213 } else { 214 /* Fail for lack of a better option */ 215 return false; 216 } 217 } 218 219 if (*mapped) { 220 if (aclu_initialize_ace(ace, samba_ace->type, 221 samba_ace->access_mask, samba_ace->flags, 0, 222 &ident)) 223 return false; 224 225 if ((ace->trustee.type == IFS_ID_TYPE_CREATOR_OWNER || 226 ace->trustee.type == IFS_ID_TYPE_CREATOR_GROUP) && 227 nt4_compatible_acls()) 228 ace->flags |= SEC_ACE_FLAG_INHERIT_ONLY; 229 } 230 231 return true; 232} 233 234/** 235 * Convert a SEC_ACL to a struct ifs_security_acl 236 */ 237static bool 238onefs_samba_acl_to_acl(SEC_ACL *samba_acl, struct ifs_security_acl **acl, 239 bool * ignore_aces, int snum) 240{ 241 int num_aces = 0; 242 struct ifs_ace *aces = NULL; 243 SEC_ACE *samba_aces; 244 bool mapped; 245 int i, j; 246 247 SMB_ASSERT(ignore_aces); 248 249 if ((!acl) || (!samba_acl)) 250 return false; 251 252 samba_aces = samba_acl->aces; 253 254 if (samba_acl->num_aces > 0 && samba_aces) { 255 /* Setup ACES */ 256 num_aces = samba_acl->num_aces; 257 aces = SMB_MALLOC_ARRAY(struct ifs_ace, num_aces); 258 259 for (i = 0, j = 0; j < num_aces; i++, j++) { 260 if (!onefs_samba_ace_to_ace(&samba_aces[j], 261 &aces[i], &mapped, snum)) 262 goto err_free; 263 264 if (!mapped) 265 i--; 266 } 267 num_aces = i; 268 } 269 270 /* If aces are given but we cannot apply them due to the reasons 271 * above we do not change the SD. However, if we are told to 272 * explicitly set an SD with 0 aces we honor this operation */ 273 *ignore_aces = samba_acl->num_aces > 0 && num_aces < 1; 274 275 if (*ignore_aces == false) 276 if (aclu_initialize_acl(acl, aces, num_aces)) 277 goto err_free; 278 279 /* Currently aclu_initialize_acl should copy the aces over, allowing 280 * us to immediately free */ 281 free(aces); 282 return true; 283 284err_free: 285 free(aces); 286 return false; 287} 288 289/** 290 * Convert a struct ifs_security_acl to a SEC_ACL 291 */ 292static bool 293onefs_acl_to_samba_acl(struct ifs_security_acl *acl, SEC_ACL **samba_acl) 294{ 295 SEC_ACE *samba_aces = NULL; 296 SEC_ACL *tmp_samba_acl = NULL; 297 int i, num_aces = 0; 298 299 if (!samba_acl) 300 return false; 301 302 /* NULL ACL */ 303 if (!acl) { 304 *samba_acl = NULL; 305 return true; 306 } 307 308 /* Determine number of aces in ACL */ 309 if (!acl->aces) 310 num_aces = 0; 311 else 312 num_aces = acl->num_aces; 313 314 /* Allocate the ace list. */ 315 if (num_aces > 0) { 316 if ((samba_aces = SMB_MALLOC_ARRAY(SEC_ACE, num_aces)) == NULL) 317 { 318 DEBUG(0, ("Unable to malloc space for %d aces.\n", 319 num_aces)); 320 return false; 321 } 322 memset(samba_aces, '\0', (num_aces) * sizeof(SEC_ACE)); 323 } 324 325 for (i = 0; i < num_aces; i++) { 326 DOM_SID sid; 327 328 if (!onefs_identity_to_sid(&acl->aces[i].trustee, &sid)) 329 goto err_free; 330 331 init_sec_ace(&samba_aces[i], &sid, acl->aces[i].type, 332 acl->aces[i].access_mask, acl->aces[i].flags); 333 } 334 335 if ((tmp_samba_acl = make_sec_acl(talloc_tos(), acl->revision, num_aces, 336 samba_aces)) == NULL) { 337 DEBUG(0, ("Unable to malloc space for acl.\n")); 338 goto err_free; 339 } 340 341 *samba_acl = tmp_samba_acl; 342 SAFE_FREE(samba_aces); 343 return true; 344err_free: 345 SAFE_FREE(samba_aces); 346 return false; 347} 348 349/** 350 * @brief Reorder ACLs into the "correct" order for Windows Explorer. 351 * 352 * Windows Explorer expects ACLs to be in a standard order (inherited first, 353 * then deny, then permit.) When ACLs are composed from POSIX file permissions 354 * bits, they may not match these expectations, generating an annoying warning 355 * dialog for the user. This function will, if configured appropriately, 356 * reorder the ACLs for these "synthetic" (POSIX-derived) descriptors to prevent 357 * this. The list is changed within the security descriptor passed in. 358 * 359 * @param fsp files_struct with service configs; must not be NULL 360 * @param sd security descriptor being normalized; 361 * sd->dacl->aces is rewritten in-place, so must not be NULL 362 * @return true on success, errno will be set on error 363 * 364 * @bug Although Windows Explorer likes the reordering, they seem to cause 365 * problems with Excel and Word sending back the reordered ACLs to us and 366 * changing policy; see Isilon bug 30165. 367 */ 368static bool 369onefs_canon_acl(files_struct *fsp, struct ifs_security_descriptor *sd) 370{ 371 int error = 0; 372 int cur; 373 struct ifs_ace *new_aces = NULL; 374 int new_aces_count = 0; 375 SMB_STRUCT_STAT sbuf; 376 377 if (sd == NULL || sd->dacl == NULL || sd->dacl->num_aces == 0) 378 return true; 379 380 /* 381 * Find out if this is a windows bit, and if the smb policy wants us to 382 * lie about the sd. 383 */ 384 SMB_ASSERT(fsp != NULL); 385 switch (lp_parm_enum(SNUM(fsp->conn), PARM_ONEFS_TYPE, 386 PARM_ACL_WIRE_FORMAT, enum_onefs_acl_wire_format, 387 PARM_ACL_WIRE_FORMAT_DEFAULT)) { 388 case ACL_FORMAT_RAW: 389 return true; 390 391 case ACL_FORMAT_WINDOWS_SD: 392 error = SMB_VFS_FSTAT(fsp, &sbuf); 393 if (error) 394 return false; 395 396 if ((sbuf.st_ex_flags & SF_HASNTFSACL) != 0) { 397 DEBUG(10, ("Did not canonicalize ACLs because a " 398 "Windows ACL set was found for file %s\n", 399 fsp_str_dbg(fsp))); 400 return true; 401 } 402 break; 403 404 case ACL_FORMAT_ALWAYS: 405 break; 406 407 default: 408 SMB_ASSERT(false); 409 return false; 410 } 411 412 new_aces = SMB_MALLOC_ARRAY(struct ifs_ace, sd->dacl->num_aces); 413 if (new_aces == NULL) 414 return false; 415 416 /* 417 * By walking down the list 3 separate times, we can avoid the need 418 * to create multiple temp buffers and extra copies. 419 */ 420 421 /* Explict deny aces first */ 422 for (cur = 0; cur < sd->dacl->num_aces; cur++) { 423 if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) && 424 (sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED)) 425 new_aces[new_aces_count++] = sd->dacl->aces[cur]; 426 } 427 428 /* Explict allow aces second */ 429 for (cur = 0; cur < sd->dacl->num_aces; cur++) { 430 if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) && 431 !(sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED)) 432 new_aces[new_aces_count++] = sd->dacl->aces[cur]; 433 } 434 435 /* Inherited deny/allow aces third */ 436 for (cur = 0; cur < sd->dacl->num_aces; cur++) { 437 if ((sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE)) 438 new_aces[new_aces_count++] = sd->dacl->aces[cur]; 439 } 440 441 SMB_ASSERT(new_aces_count == sd->dacl->num_aces); 442 DEBUG(10, ("Performed canonicalization of ACLs for file %s\n", 443 fsp_str_dbg(fsp))); 444 445 /* 446 * At this point you would think we could just do this: 447 * SAFE_FREE(sd->dacl->aces); 448 * sd->dacl->aces = new_aces; 449 * However, in some cases the existing aces pointer does not point 450 * to the beginning of an allocated block. So we have to do a more 451 * expensive memcpy() 452 */ 453 memcpy(sd->dacl->aces, new_aces, 454 sizeof(struct ifs_ace) * new_aces_count); 455 456 SAFE_FREE(new_aces); 457 return true; 458} 459 460 461/** 462 * This enum is a helper for onefs_fget_nt_acl() to communicate with 463 * onefs_init_ace(). 464 */ 465enum mode_ident { USR, GRP, OTH }; 466 467/** 468 * Initializes an ACE for addition to a synthetic ACL. 469 */ 470static struct ifs_ace onefs_init_ace(struct connection_struct *conn, 471 mode_t mode, 472 bool isdir, 473 enum mode_ident ident) 474{ 475 struct ifs_ace result; 476 enum ifs_ace_rights r,w,x; 477 478 r = isdir ? UNIX_DIRECTORY_ACCESS_R : UNIX_ACCESS_R; 479 w = isdir ? UNIX_DIRECTORY_ACCESS_W : UNIX_ACCESS_W; 480 x = isdir ? UNIX_DIRECTORY_ACCESS_X : UNIX_ACCESS_X; 481 482 result.type = IFS_ACE_TYPE_ACCESS_ALLOWED; 483 result.ifs_flags = 0; 484 result.flags = isdir ? IFS_ACE_FLAG_CONTAINER_INHERIT : 485 IFS_ACE_FLAG_OBJECT_INHERIT; 486 result.flags |= IFS_ACE_FLAG_INHERIT_ONLY; 487 488 switch (ident) { 489 case USR: 490 result.access_mask = 491 ((mode & S_IRUSR) ? r : 0 ) | 492 ((mode & S_IWUSR) ? w : 0 ) | 493 ((mode & S_IXUSR) ? x : 0 ); 494 if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, 495 PARM_CREATOR_OWNER_GETS_FULL_CONTROL, 496 PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT)) 497 result.access_mask |= GENERIC_ALL_ACCESS; 498 result.trustee.type = IFS_ID_TYPE_CREATOR_OWNER; 499 break; 500 case GRP: 501 result.access_mask = 502 ((mode & S_IRGRP) ? r : 0 ) | 503 ((mode & S_IWGRP) ? w : 0 ) | 504 ((mode & S_IXGRP) ? x : 0 ); 505 result.trustee.type = IFS_ID_TYPE_CREATOR_GROUP; 506 break; 507 case OTH: 508 result.access_mask = 509 ((mode & S_IROTH) ? r : 0 ) | 510 ((mode & S_IWOTH) ? w : 0 ) | 511 ((mode & S_IXOTH) ? x : 0 ); 512 result.trustee.type = IFS_ID_TYPE_EVERYONE; 513 break; 514 } 515 516 return result; 517} 518 519/** 520 * This adds inheritable ACEs to the end of the DACL, with the ACEs 521 * being derived from the mode bits. This is useful for clients that have the 522 * MoveSecurityAttributes regkey set to 0 or are in Simple File Sharing Mode. 523 * 524 * On these clients, when copying files from one folder to another inside the 525 * same volume/share, the DACL is explicitely cleared. Without inheritable 526 * aces on the target folder the mode bits of the copied file are set to 000. 527 * 528 * See Isilon Bug 27990 529 * 530 * Note: This function allocates additional memory onto sd->dacl->aces, that 531 * must be freed by the caller. 532 */ 533static bool add_sfs_aces(files_struct *fsp, struct ifs_security_descriptor *sd) 534{ 535 int error; 536 SMB_STRUCT_STAT sbuf; 537 538 error = SMB_VFS_FSTAT(fsp, &sbuf); 539 if (error) { 540 DEBUG(0, ("Failed to stat %s in simple files sharing " 541 "compatibility mode. errno=%d\n", 542 fsp_str_dbg(fsp), errno)); 543 return false; 544 } 545 546 /* Only continue if this is a synthetic ACL and a directory. */ 547 if (S_ISDIR(sbuf.st_ex_mode) && 548 (sbuf.st_ex_flags & SF_HASNTFSACL) == 0) { 549 struct ifs_ace new_aces[6]; 550 struct ifs_ace *old_aces; 551 int i, num_aces_to_add = 0; 552 mode_t file_mode = 0, dir_mode = 0; 553 554 /* Use existing samba logic to derive the mode bits. */ 555 file_mode = unix_mode(fsp->conn, 0, fsp->fsp_name, NULL); 556 dir_mode = unix_mode(fsp->conn, aDIR, fsp->fsp_name, NULL); 557 558 /* Initialize ACEs. */ 559 new_aces[0] = onefs_init_ace(fsp->conn, file_mode, false, USR); 560 new_aces[1] = onefs_init_ace(fsp->conn, file_mode, false, GRP); 561 new_aces[2] = onefs_init_ace(fsp->conn, file_mode, false, OTH); 562 new_aces[3] = onefs_init_ace(fsp->conn, dir_mode, true, USR); 563 new_aces[4] = onefs_init_ace(fsp->conn, dir_mode, true, GRP); 564 new_aces[5] = onefs_init_ace(fsp->conn, dir_mode, true, OTH); 565 566 for (i = 0; i < 6; i++) 567 if (new_aces[i].access_mask != 0) 568 num_aces_to_add++; 569 570 /* Expand the ACEs array */ 571 if (num_aces_to_add != 0) { 572 old_aces = sd->dacl->aces; 573 574 sd->dacl->aces = SMB_MALLOC_ARRAY(struct ifs_ace, 575 sd->dacl->num_aces + num_aces_to_add); 576 if (!sd->dacl->aces) { 577 DEBUG(0, ("Unable to malloc space for " 578 "new_aces: %d.\n", 579 sd->dacl->num_aces + num_aces_to_add)); 580 return false; 581 } 582 memcpy(sd->dacl->aces, old_aces, 583 sizeof(struct ifs_ace) * sd->dacl->num_aces); 584 585 /* Add the new ACEs to the DACL. */ 586 for (i = 0; i < 6; i++) { 587 if (new_aces[i].access_mask != 0) { 588 sd->dacl->aces[sd->dacl->num_aces] = 589 new_aces[i]; 590 sd->dacl->num_aces++; 591 } 592 } 593 } 594 } 595 return true; 596} 597 598/** 599 * Isilon-specific function for getting an NTFS ACL from an open file. 600 * 601 * @param[out] ppdesc SecDesc to allocate and fill in 602 * 603 * @return NTSTATUS based off errno on error 604 */ 605NTSTATUS 606onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, 607 uint32 security_info, SEC_DESC **ppdesc) 608{ 609 int error; 610 uint32_t sd_size = 0; 611 size_t size = 0; 612 struct ifs_security_descriptor *sd = NULL; 613 DOM_SID owner_sid, group_sid; 614 DOM_SID *ownerp, *groupp; 615 SEC_ACL *dacl, *sacl; 616 SEC_DESC *pdesc; 617 bool alloced = false; 618 bool new_aces_alloced = false; 619 bool fopened = false; 620 NTSTATUS status = NT_STATUS_OK; 621 622 START_PROFILE(syscall_get_sd); 623 624 *ppdesc = NULL; 625 626 DEBUG(5, ("Getting sd for file %s. security_info=%u\n", 627 fsp_str_dbg(fsp), security_info)); 628 629 if (lp_parm_bool(SNUM(fsp->conn), PARM_ONEFS_TYPE, 630 PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) { 631 DEBUG(5, ("Ignoring SACL on %s.\n", fsp_str_dbg(fsp))); 632 security_info &= ~SACL_SECURITY_INFORMATION; 633 } 634 635 if (fsp->fh->fd == -1) { 636 if ((fsp->fh->fd = onefs_sys_create_file(handle->conn, 637 -1, 638 fsp->fsp_name->base_name, 639 0, 640 0, 641 0, 642 0, 643 0, 644 0, 645 INTERNAL_OPEN_ONLY, 646 0, 647 NULL, 648 0, 649 NULL)) == -1) { 650 DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", 651 fsp_str_dbg(fsp), errno, strerror(errno))); 652 status = map_nt_error_from_unix(errno); 653 goto out; 654 } 655 fopened = true; 656 } 657 658 /* Get security descriptor */ 659 sd_size = 0; 660 do { 661 /* Allocate memory for get_security_descriptor */ 662 if (sd_size > 0) { 663 sd = SMB_REALLOC(sd, sd_size); 664 if (!sd) { 665 DEBUG(0, ("Unable to malloc %u bytes of space " 666 "for security descriptor.\n", sd_size)); 667 status = map_nt_error_from_unix(errno); 668 goto out; 669 } 670 671 alloced = true; 672 } 673 674 error = ifs_get_security_descriptor(fsp->fh->fd, security_info, 675 sd_size, &sd_size, sd); 676 if (error && (errno != EMSGSIZE)) { 677 DEBUG(0, ("Failed getting size of security descriptor! " 678 "errno=%d\n", errno)); 679 status = map_nt_error_from_unix(errno); 680 goto out; 681 } 682 } while (error); 683 684 DEBUG(5, ("Got sd, size=%u:\n", sd_size)); 685 686 if (lp_parm_bool(SNUM(fsp->conn), 687 PARM_ONEFS_TYPE, 688 PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE, 689 PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT) && 690 sd->dacl) { 691 if(!(new_aces_alloced = add_sfs_aces(fsp, sd))) 692 goto out; 693 } 694 695 if (!(onefs_canon_acl(fsp, sd))) { 696 status = map_nt_error_from_unix(errno); 697 goto out; 698 } 699 700 DEBUG(5, ("Finished canonicalizing ACL\n")); 701 702 ownerp = NULL; 703 groupp = NULL; 704 dacl = NULL; 705 sacl = NULL; 706 707 /* Copy owner into ppdesc */ 708 if (security_info & OWNER_SECURITY_INFORMATION) { 709 if (!onefs_identity_to_sid(sd->owner, &owner_sid)) { 710 status = NT_STATUS_INVALID_PARAMETER; 711 goto out; 712 } 713 714 ownerp = &owner_sid; 715 } 716 717 /* Copy group into ppdesc */ 718 if (security_info & GROUP_SECURITY_INFORMATION) { 719 if (!onefs_identity_to_sid(sd->group, &group_sid)) { 720 status = NT_STATUS_INVALID_PARAMETER; 721 goto out; 722 } 723 724 groupp = &group_sid; 725 } 726 727 /* Copy DACL into ppdesc */ 728 if (security_info & DACL_SECURITY_INFORMATION) { 729 if (!onefs_acl_to_samba_acl(sd->dacl, &dacl)) { 730 status = NT_STATUS_INVALID_PARAMETER; 731 goto out; 732 } 733 } 734 735 /* Copy SACL into ppdesc */ 736 if (security_info & SACL_SECURITY_INFORMATION) { 737 if (!onefs_acl_to_samba_acl(sd->sacl, &sacl)) { 738 status = NT_STATUS_INVALID_PARAMETER; 739 goto out; 740 } 741 } 742 743 /* AUTO_INHERIT_REQ bits are not returned over the wire so strip them 744 * off. Eventually we should stop storing these in the kernel 745 * all together. See Isilon bug 40364 */ 746 sd->control &= ~(IFS_SD_CTRL_DACL_AUTO_INHERIT_REQ | 747 IFS_SD_CTRL_SACL_AUTO_INHERIT_REQ); 748 749 pdesc = make_sec_desc(talloc_tos(), sd->revision, sd->control, 750 ownerp, groupp, sacl, dacl, &size); 751 752 if (!pdesc) { 753 DEBUG(0, ("Problem with make_sec_desc. Memory?\n")); 754 status = map_nt_error_from_unix(errno); 755 goto out; 756 } 757 758 *ppdesc = pdesc; 759 760 DEBUG(5, ("Finished retrieving/canonicalizing SD!\n")); 761 /* FALLTHROUGH */ 762out: 763 764 END_PROFILE(syscall_get_sd); 765 766 if (alloced && sd) { 767 if (new_aces_alloced && sd->dacl->aces) 768 SAFE_FREE(sd->dacl->aces); 769 770 SAFE_FREE(sd); 771 } 772 773 if (fopened) { 774 close(fsp->fh->fd); 775 fsp->fh->fd = -1; 776 } 777 778 return status; 779} 780 781/** 782 * Isilon-specific function for getting an NTFS ACL from a file path. 783 * 784 * Since onefs_fget_nt_acl() needs to open a filepath if the fd is invalid, 785 * we just mock up a files_struct with the path and bad fd and call into it. 786 * 787 * @param[out] ppdesc SecDesc to allocate and fill in 788 * 789 * @return NTSTATUS based off errno on error 790 */ 791NTSTATUS 792onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, 793 uint32 security_info, SEC_DESC **ppdesc) 794{ 795 files_struct finfo; 796 struct fd_handle fh; 797 NTSTATUS status; 798 799 ZERO_STRUCT(finfo); 800 ZERO_STRUCT(fh); 801 802 finfo.fnum = -1; 803 finfo.conn = handle->conn; 804 finfo.fh = &fh; 805 finfo.fh->fd = -1; 806 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL, 807 &finfo.fsp_name); 808 if (!NT_STATUS_IS_OK(status)) { 809 return status; 810 } 811 812 status = onefs_fget_nt_acl(handle, &finfo, security_info, ppdesc); 813 814 TALLOC_FREE(finfo.fsp_name); 815 return status; 816} 817 818/** 819 * Isilon-specific function for setting up an ifs_security_descriptor, given a 820 * samba SEC_DESC. 821 * 822 * @param[out] sd ifs_security_descriptor to fill in 823 * 824 * @return NTSTATUS_OK if successful 825 */ 826NTSTATUS onefs_samba_sd_to_sd(uint32_t security_info_sent, const SEC_DESC *psd, 827 struct ifs_security_descriptor *sd, int snum, 828 uint32_t *security_info_effective) 829{ 830 struct ifs_security_acl *daclp, *saclp; 831 struct ifs_identity owner, group, *ownerp, *groupp; 832 bool ignore_aces; 833 834 ownerp = NULL; 835 groupp = NULL; 836 daclp = NULL; 837 saclp = NULL; 838 839 *security_info_effective = security_info_sent; 840 841 /* Setup owner */ 842 if (security_info_sent & OWNER_SECURITY_INFORMATION) { 843 if (!onefs_og_to_identity(psd->owner_sid, &owner, false, snum)) 844 return NT_STATUS_ACCESS_DENIED; 845 846 SMB_ASSERT(owner.id.uid >= 0); 847 848 ownerp = &owner; 849 } 850 851 /* Setup group */ 852 if (security_info_sent & GROUP_SECURITY_INFORMATION) { 853 if (!onefs_og_to_identity(psd->group_sid, &group, true, snum)) 854 return NT_STATUS_ACCESS_DENIED; 855 856 SMB_ASSERT(group.id.gid >= 0); 857 858 groupp = &group; 859 } 860 861 /* Setup DACL */ 862 if ((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl)) { 863 if (!onefs_samba_acl_to_acl(psd->dacl, &daclp, &ignore_aces, 864 snum)) 865 return NT_STATUS_ACCESS_DENIED; 866 867 if (ignore_aces == true) 868 *security_info_effective &= ~DACL_SECURITY_INFORMATION; 869 } 870 871 /* Setup SACL */ 872 if (security_info_sent & SACL_SECURITY_INFORMATION) { 873 874 if (lp_parm_bool(snum, PARM_ONEFS_TYPE, 875 PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) { 876 DEBUG(5, ("Ignoring SACL.\n")); 877 *security_info_effective &= ~SACL_SECURITY_INFORMATION; 878 } else { 879 if (psd->sacl) { 880 if (!onefs_samba_acl_to_acl(psd->sacl, 881 &saclp, &ignore_aces, snum)) 882 return NT_STATUS_ACCESS_DENIED; 883 884 if (ignore_aces == true) { 885 *security_info_effective &= 886 ~SACL_SECURITY_INFORMATION; 887 } 888 } 889 } 890 } 891 892 /* Setup ifs_security_descriptor */ 893 DEBUG(5,("Setting up SD\n")); 894 if (aclu_initialize_sd(sd, psd->type, ownerp, groupp, 895 (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false)) 896 return NT_STATUS_ACCESS_DENIED; 897 898 DEBUG(10, ("sec_info_sent: 0x%x, sec_info_effective: 0x%x.\n", 899 security_info_sent, *security_info_effective)); 900 901 return NT_STATUS_OK; 902} 903 904/** 905 * Isilon-specific function for setting an NTFS ACL on an open file. 906 * 907 * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off 908 * errno on syscall errors 909 */ 910NTSTATUS 911onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, 912 uint32_t sec_info_sent, const SEC_DESC *psd) 913{ 914 struct ifs_security_descriptor sd = {}; 915 int fd = -1; 916 bool fopened = false; 917 NTSTATUS status; 918 uint32_t sec_info_effective = 0; 919 920 START_PROFILE(syscall_set_sd); 921 922 DEBUG(5,("Setting SD on file %s.\n", fsp_str_dbg(fsp))); 923 924 status = onefs_samba_sd_to_sd(sec_info_sent, psd, &sd, 925 SNUM(handle->conn), &sec_info_effective); 926 927 if (!NT_STATUS_IS_OK(status)) { 928 DEBUG(3, ("SD initialization failure: %s\n", nt_errstr(status))); 929 goto out; 930 } 931 932 fd = fsp->fh->fd; 933 if (fd == -1) { 934 DEBUG(10,("Reopening file %s.\n", fsp_str_dbg(fsp))); 935 if ((fd = onefs_sys_create_file(handle->conn, 936 -1, 937 fsp->fsp_name->base_name, 938 0, 939 0, 940 0, 941 0, 942 0, 943 0, 944 INTERNAL_OPEN_ONLY, 945 0, 946 NULL, 947 0, 948 NULL)) == -1) { 949 DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", 950 fsp_str_dbg(fsp), errno, strerror(errno))); 951 status = map_nt_error_from_unix(errno); 952 goto out; 953 } 954 fopened = true; 955 } 956 957 errno = 0; 958 if (ifs_set_security_descriptor(fd, sec_info_effective, &sd)) { 959 DEBUG(0, ("Error setting security descriptor = %s\n", 960 strerror(errno))); 961 status = map_nt_error_from_unix(errno); 962 goto out; 963 } 964 965 DEBUG(5, ("Security descriptor set correctly!\n")); 966 status = NT_STATUS_OK; 967 968 /* FALLTHROUGH */ 969out: 970 END_PROFILE(syscall_set_sd); 971 972 if (fopened) 973 close(fd); 974 975 aclu_free_sd(&sd, false); 976 return status; 977} 978