1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stddef.h> 27 #include <strings.h> 28 #include <assert.h> 29 30 #include <smbsrv/ntifs.h> 31 #include <smbsrv/smb_sid.h> 32 #include <smbsrv/smb_idmap.h> 33 #include <smbsrv/ntstatus.h> 34 #include <smbsrv/ntaccess.h> 35 36 #define ACE_ALL_TYPES 0x001F 37 38 /* 39 * ACE groups within a DACL 40 * 41 * This is from lower to higher ACE order priority 42 */ 43 #define SMB_AG_START 0 44 #define SMB_AG_ALW_INHRT 0 45 #define SMB_AG_DNY_INHRT 1 46 #define SMB_AG_ALW_DRCT 2 47 #define SMB_AG_DNY_DRCT 3 48 #define SMB_AG_NUM 4 49 50 /* 51 * SID for Everyone group: S-1-1-0. 52 */ 53 smb_sid_t everyone_sid = { 54 NT_SID_REVISION, 55 1, 56 NT_SECURITY_WORLD_AUTH, 57 { 0 } 58 }; 59 60 #define DEFAULT_DACL_ACENUM 2 61 acl_t *acl_alloc(enum acl_type); 62 63 static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *, uid_t, gid_t); 64 static acl_t *smb_fsacl_null_empty(boolean_t); 65 static uint16_t smb_ace_len(smb_ace_t *); 66 static uint32_t smb_ace_mask_g2s(uint32_t); 67 static uint16_t smb_ace_flags_tozfs(uint8_t); 68 static uint8_t smb_ace_flags_fromzfs(uint16_t); 69 70 smb_acl_t * 71 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt) 72 { 73 smb_acl_t *acl; 74 int size; 75 76 size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t)); 77 if ((acl = malloc(size)) == NULL) 78 return (NULL); 79 80 acl->sl_revision = revision; 81 acl->sl_bsize = bsize; 82 acl->sl_acecnt = acecnt; 83 acl->sl_aces = (smb_ace_t *)(acl + 1); 84 85 list_create(&acl->sl_sorted, sizeof (smb_ace_t), 86 offsetof(smb_ace_t, se_sln)); 87 return (acl); 88 } 89 90 void 91 smb_acl_free(smb_acl_t *acl) 92 { 93 int i; 94 void *ace; 95 96 if (acl == NULL) 97 return; 98 99 for (i = 0; i < acl->sl_acecnt; i++) 100 smb_sid_free(acl->sl_aces[i].se_sid); 101 102 while ((ace = list_head(&acl->sl_sorted)) != NULL) 103 list_remove(&acl->sl_sorted, ace); 104 list_destroy(&acl->sl_sorted); 105 free(acl); 106 107 } 108 109 /* 110 * smb_acl_len 111 * 112 * Returns the size of given ACL in bytes. Note that this 113 * is not an in-memory size, it's the ACL's size as it would 114 * appear on the wire 115 */ 116 uint16_t 117 smb_acl_len(smb_acl_t *acl) 118 { 119 return ((acl) ? acl->sl_bsize : 0); 120 } 121 122 /*ARGSUSED*/ 123 boolean_t 124 smb_acl_isvalid(smb_acl_t *acl, int which_acl) 125 { 126 if (acl->sl_bsize < SMB_ACL_HDRSIZE) 127 return (B_FALSE); 128 129 if (acl->sl_revision != ACL_REVISION) { 130 /* 131 * we are rejecting ACLs with object-specific ACEs for now 132 */ 133 return (B_FALSE); 134 } 135 136 return (B_TRUE); 137 } 138 139 /* 140 * smb_acl_sort 141 * 142 * Sorts the given ACL in place if it needs to be sorted. 143 * 144 * The following is an excerpt from MSDN website. 145 * 146 * Order of ACEs in a DACL 147 * 148 * For Windows NT versions 4.0 and earlier, the preferred order of ACEs 149 * is simple: In a DACL, all access-denied ACEs should precede any 150 * access-allowed ACEs. 151 * 152 * For Windows 2000 or later, the proper order of ACEs is more complicated 153 * because of the introduction of object-specific ACEs and automatic 154 * inheritance. 155 * 156 * The following describes the preferred order: 157 * 158 * To ensure that noninherited ACEs have precedence over inherited ACEs, 159 * place all noninherited ACEs in a group before any inherited ACEs. This 160 * ordering ensures, for example, that a noninherited access-denied ACE 161 * is enforced regardless of any inherited ACE that allows access. 162 * Within the groups of noninherited ACEs and inherited ACEs, order ACEs 163 * according to ACE type, as the following shows: 164 * . Access-denied ACEs that apply to the object itself 165 * . Access-denied ACEs that apply to a subobject of the 166 * object, such as a property set or property 167 * . Access-allowed ACEs that apply to the object itself 168 * . Access-allowed ACEs that apply to a subobject of the object 169 * 170 * So, here is the desired ACE order 171 * 172 * deny-direct, allow-direct, deny-inherited, allow-inherited 173 * 174 * Of course, not all ACE types are required in an ACL. 175 */ 176 void 177 smb_acl_sort(smb_acl_t *acl) 178 { 179 list_t ace_grps[SMB_AG_NUM]; 180 list_t *alist; 181 smb_ace_t *ace; 182 uint8_t ace_flags; 183 int ag, i; 184 185 assert(acl); 186 187 if (acl->sl_acecnt == 0) { 188 /* 189 * ACL with no entry is a valid ACL and it means 190 * no access for anybody. 191 */ 192 return; 193 } 194 195 for (i = SMB_AG_START; i < SMB_AG_NUM; i++) { 196 list_create(&ace_grps[i], sizeof (smb_ace_t), 197 offsetof(smb_ace_t, se_sln)); 198 } 199 200 for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) { 201 ace_flags = ace->se_hdr.se_flags; 202 203 switch (ace->se_hdr.se_type) { 204 case ACCESS_DENIED_ACE_TYPE: 205 ag = (ace_flags & INHERITED_ACE) ? 206 SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT; 207 break; 208 209 case ACCESS_ALLOWED_ACE_TYPE: 210 ag = (ace_flags & INHERITED_ACE) ? 211 SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT; 212 break; 213 214 default: 215 /* 216 * This is the lowest priority group so we put 217 * evertything unknown here. 218 */ 219 ag = SMB_AG_ALW_INHRT; 220 break; 221 } 222 223 /* Add the ACE to the selected group */ 224 list_insert_tail(&ace_grps[ag], ace); 225 } 226 227 /* 228 * start with highest priority ACE group and append 229 * the ACEs to the ACL. 230 */ 231 for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) { 232 alist = &ace_grps[i]; 233 while ((ace = list_head(alist)) != NULL) { 234 list_remove(alist, ace); 235 list_insert_tail(&acl->sl_sorted, ace); 236 } 237 list_destroy(alist); 238 } 239 } 240 241 /* 242 * smb_acl_from_zfs 243 * 244 * Converts given ZFS ACL to a Windows ACL. 245 * 246 * A pointer to allocated memory for the Windows ACL will be 247 * returned upon successful conversion. 248 */ 249 smb_acl_t * 250 smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid) 251 { 252 ace_t *zace; 253 int numaces; 254 smb_acl_t *acl; 255 smb_ace_t *ace; 256 smb_idmap_batch_t sib; 257 smb_idmap_t *sim; 258 idmap_stat idm_stat; 259 260 idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt, 261 SMB_IDMAP_ID2SID); 262 if (idm_stat != IDMAP_SUCCESS) 263 return (NULL); 264 265 if (smb_fsacl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) { 266 smb_idmap_batch_destroy(&sib); 267 return (NULL); 268 } 269 270 acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt); 271 272 sim = sib.sib_maps; 273 for (numaces = 0, zace = zacl->acl_aclp; 274 numaces < zacl->acl_cnt; 275 zace++, numaces++, sim++) { 276 assert(sim->sim_sid); 277 if (sim->sim_sid == NULL) { 278 smb_acl_free(acl); 279 acl = NULL; 280 break; 281 } 282 283 ace = &acl->sl_aces[numaces]; 284 ace->se_hdr.se_type = zace->a_type; 285 ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags); 286 ace->se_mask = zace->a_access_mask; 287 ace->se_sid = smb_sid_dup(sim->sim_sid); 288 ace->se_hdr.se_bsize = smb_ace_len(ace); 289 290 acl->sl_bsize += ace->se_hdr.se_bsize; 291 } 292 293 smb_idmap_batch_destroy(&sib); 294 return (acl); 295 } 296 297 /* 298 * smb_acl_to_zfs 299 * 300 * Converts given Windows ACL to a ZFS ACL. 301 * 302 * fs_acl will contain a pointer to the created ZFS ACL. 303 * The allocated memory should be freed by calling 304 * smb_fsacl_free(). 305 * 306 * Since the output parameter, fs_acl, is allocated in this 307 * function, the caller has to make sure *fs_acl is NULL which 308 * means it's not pointing to any memory. 309 */ 310 uint32_t 311 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl) 312 { 313 smb_ace_t *ace; 314 acl_t *zacl; 315 ace_t *zace; 316 smb_idmap_batch_t sib; 317 smb_idmap_t *sim; 318 idmap_stat idm_stat; 319 int i; 320 321 assert(fs_acl); 322 assert(*fs_acl == NULL); 323 324 if (acl && !smb_acl_isvalid(acl, which_acl)) 325 return (NT_STATUS_INVALID_ACL); 326 327 if ((acl == NULL) || (acl->sl_acecnt == 0)) { 328 if (which_acl == SMB_DACL_SECINFO) { 329 *fs_acl = smb_fsacl_null_empty(acl == NULL); 330 } 331 332 return (NT_STATUS_SUCCESS); 333 } 334 335 idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt, 336 SMB_IDMAP_SID2ID); 337 if (idm_stat != IDMAP_SUCCESS) 338 return (NT_STATUS_INTERNAL_ERROR); 339 340 zacl = smb_fsacl_alloc(acl->sl_acecnt, flags); 341 342 zace = zacl->acl_aclp; 343 ace = acl->sl_aces; 344 sim = sib.sib_maps; 345 346 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 347 zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES; 348 zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask); 349 zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags); 350 351 if (smb_sid_cmp(ace->se_sid, &everyone_sid)) 352 zace->a_flags |= ACE_EVERYONE; 353 else { 354 sim->sim_id = &zace->a_who; 355 idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, 356 ace->se_sid, -1); 357 358 if (idm_stat != IDMAP_SUCCESS) { 359 smb_fsacl_free(zacl); 360 smb_idmap_batch_destroy(&sib); 361 return (NT_STATUS_INTERNAL_ERROR); 362 } 363 } 364 } 365 366 idm_stat = smb_idmap_batch_getmappings(&sib); 367 if (idm_stat != IDMAP_SUCCESS) { 368 smb_fsacl_free(zacl); 369 smb_idmap_batch_destroy(&sib); 370 return (NT_STATUS_NONE_MAPPED); 371 } 372 373 /* 374 * Set the ACEs group flag based on the type of ID returned. 375 */ 376 zace = zacl->acl_aclp; 377 ace = acl->sl_aces; 378 sim = sib.sib_maps; 379 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 380 if (zace->a_flags & ACE_EVERYONE) 381 continue; 382 383 if (sim->sim_idtype == SMB_IDMAP_GROUP) 384 zace->a_flags |= ACE_IDENTIFIER_GROUP; 385 } 386 387 smb_idmap_batch_destroy(&sib); 388 389 *fs_acl = zacl; 390 return (NT_STATUS_SUCCESS); 391 } 392 393 /* 394 * smb_fsacl_getsids 395 * 396 * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs. 397 */ 398 static idmap_stat 399 smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid) 400 { 401 ace_t *zace; 402 idmap_stat idm_stat; 403 smb_idmap_t *sim; 404 uid_t id; 405 int i, idtype; 406 407 sim = sib->sib_maps; 408 409 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; 410 zace++, i++, sim++) { 411 switch (zace->a_flags & ACE_TYPE_FLAGS) { 412 case ACE_OWNER: 413 id = uid; 414 idtype = SMB_IDMAP_USER; 415 break; 416 417 case (ACE_GROUP | ACE_IDENTIFIER_GROUP): 418 /* owning group */ 419 id = gid; 420 idtype = SMB_IDMAP_GROUP; 421 break; 422 423 case ACE_IDENTIFIER_GROUP: 424 /* regular group */ 425 id = zace->a_who; 426 idtype = SMB_IDMAP_GROUP; 427 break; 428 429 case ACE_EVERYONE: 430 idtype = SMB_IDMAP_EVERYONE; 431 break; 432 433 default: 434 /* user entry */ 435 id = zace->a_who; 436 idtype = SMB_IDMAP_USER; 437 } 438 439 idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim, 440 id, idtype); 441 442 if (idm_stat != IDMAP_SUCCESS) { 443 return (idm_stat); 444 } 445 } 446 447 idm_stat = smb_idmap_batch_getmappings(sib); 448 return (idm_stat); 449 } 450 451 /* 452 * smb_fsacl_null_empty 453 * 454 * NULL DACL means everyone full-access 455 * Empty DACL means everyone full-deny 456 * 457 * ZFS ACL must have at least one entry so smb server has 458 * to simulate the aforementioned expected behavior by adding 459 * an entry in case the requested DACL is null or empty. Adding 460 * a everyone full-deny entry has proved to be problematic in 461 * tests since a deny entry takes precedence over allow entries. 462 * So, instead of adding a everyone full-deny, an owner ACE with 463 * owner implicit permissions will be set. 464 */ 465 static acl_t * 466 smb_fsacl_null_empty(boolean_t null) 467 { 468 acl_t *zacl; 469 ace_t *zace; 470 471 zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT); 472 zace = zacl->acl_aclp; 473 474 zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 475 if (null) { 476 zace->a_access_mask = ACE_ALL_PERMS; 477 zace->a_flags = ACE_EVERYONE; 478 } else { 479 zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL | 480 ACE_READ_ATTRIBUTES; 481 zace->a_flags = ACE_OWNER; 482 } 483 484 return (zacl); 485 } 486 487 /* 488 * FS ACL (acl_t) Functions 489 */ 490 acl_t * 491 smb_fsacl_alloc(int acenum, int flags) 492 { 493 acl_t *acl; 494 495 acl = acl_alloc(ACE_T); 496 acl->acl_cnt = acenum; 497 if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL) 498 return (NULL); 499 500 acl->acl_flags = flags; 501 return (acl); 502 } 503 504 void 505 smb_fsacl_free(acl_t *acl) 506 { 507 if (acl) 508 acl_free(acl); 509 } 510 511 /* 512 * ACE Functions 513 */ 514 515 /* 516 * smb_ace_len 517 * 518 * Returns the length of the given ACE as it appears in an 519 * ACL on the wire (i.e. a flat buffer which contains the SID) 520 */ 521 static uint16_t 522 smb_ace_len(smb_ace_t *ace) 523 { 524 assert(ace); 525 assert(ace->se_sid); 526 527 if (ace == NULL) 528 return (0); 529 530 return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) + 531 smb_sid_len(ace->se_sid)); 532 } 533 534 /* 535 * smb_ace_mask_g2s 536 * 537 * Converts generic access bits in the given mask (if any) 538 * to file specific bits. Generic access masks shouldn't be 539 * stored in filesystem ACEs. 540 */ 541 static uint32_t 542 smb_ace_mask_g2s(uint32_t mask) 543 { 544 if (mask & GENERIC_ALL) { 545 mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE 546 | GENERIC_EXECUTE); 547 548 mask |= FILE_ALL_ACCESS; 549 return (mask); 550 } 551 552 if (mask & GENERIC_READ) { 553 mask &= ~GENERIC_READ; 554 mask |= FILE_GENERIC_READ; 555 } 556 557 if (mask & GENERIC_WRITE) { 558 mask &= ~GENERIC_WRITE; 559 mask |= FILE_GENERIC_WRITE; 560 } 561 562 if (mask & GENERIC_EXECUTE) { 563 mask &= ~GENERIC_EXECUTE; 564 mask |= FILE_GENERIC_EXECUTE; 565 } 566 567 return (mask); 568 } 569 570 /* 571 * smb_ace_flags_tozfs 572 * 573 * This function maps the flags which have different values 574 * in Windows and Solaris. The ones with the same value are 575 * transferred untouched. 576 */ 577 static uint16_t 578 smb_ace_flags_tozfs(uint8_t c_flags) 579 { 580 uint16_t z_flags = 0; 581 582 if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG) 583 z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG; 584 585 if (c_flags & FAILED_ACCESS_ACE_FLAG) 586 z_flags |= ACE_FAILED_ACCESS_ACE_FLAG; 587 588 if (c_flags & INHERITED_ACE) 589 z_flags |= ACE_INHERITED_ACE; 590 591 z_flags |= (c_flags & ACE_INHERIT_FLAGS); 592 593 return (z_flags); 594 } 595 596 static uint8_t 597 smb_ace_flags_fromzfs(uint16_t z_flags) 598 { 599 uint8_t c_flags; 600 601 c_flags = z_flags & ACE_INHERIT_FLAGS; 602 603 if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 604 c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG; 605 606 if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG) 607 c_flags |= FAILED_ACCESS_ACE_FLAG; 608 609 if (z_flags & ACE_INHERITED_ACE) 610 c_flags |= INHERITED_ACE; 611 612 return (c_flags); 613 } 614