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