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 /*ARGSUSED*/ 112 boolean_t 113 smb_acl_isvalid(smb_acl_t *acl, int which_acl) 114 { 115 if (acl->sl_bsize < SMB_ACL_HDRSIZE) 116 return (B_FALSE); 117 118 if (acl->sl_revision != ACL_REVISION) { 119 /* 120 * we are rejecting ACLs with object-specific ACEs for now 121 */ 122 return (B_FALSE); 123 } 124 125 return (B_TRUE); 126 } 127 128 /* 129 * smb_acl_sort 130 * 131 * Sorts the given ACL in place if it needs to be sorted. 132 * 133 * The following is an excerpt from MSDN website. 134 * 135 * Order of ACEs in a DACL 136 * 137 * For Windows NT versions 4.0 and earlier, the preferred order of ACEs 138 * is simple: In a DACL, all access-denied ACEs should precede any 139 * access-allowed ACEs. 140 * 141 * For Windows 2000 or later, the proper order of ACEs is more complicated 142 * because of the introduction of object-specific ACEs and automatic 143 * inheritance. 144 * 145 * The following describes the preferred order: 146 * 147 * To ensure that noninherited ACEs have precedence over inherited ACEs, 148 * place all noninherited ACEs in a group before any inherited ACEs. This 149 * ordering ensures, for example, that a noninherited access-denied ACE 150 * is enforced regardless of any inherited ACE that allows access. 151 * Within the groups of noninherited ACEs and inherited ACEs, order ACEs 152 * according to ACE type, as the following shows: 153 * . Access-denied ACEs that apply to the object itself 154 * . Access-denied ACEs that apply to a subobject of the 155 * object, such as a property set or property 156 * . Access-allowed ACEs that apply to the object itself 157 * . Access-allowed ACEs that apply to a subobject of the object 158 * 159 * So, here is the desired ACE order 160 * 161 * deny-direct, allow-direct, deny-inherited, allow-inherited 162 * 163 * Of course, not all ACE types are required in an ACL. 164 */ 165 void 166 smb_acl_sort(smb_acl_t *acl) 167 { 168 list_t ace_grps[SMB_AG_NUM]; 169 list_t *alist; 170 smb_ace_t *ace; 171 uint8_t ace_flags; 172 int ag, i; 173 174 assert(acl); 175 176 if (acl->sl_acecnt == 0) { 177 /* 178 * ACL with no entry is a valid ACL and it means 179 * no access for anybody. 180 */ 181 return; 182 } 183 184 for (i = SMB_AG_START; i < SMB_AG_NUM; i++) { 185 list_create(&ace_grps[i], sizeof (smb_ace_t), 186 offsetof(smb_ace_t, se_sln)); 187 } 188 189 for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) { 190 ace_flags = ace->se_hdr.se_flags; 191 192 switch (ace->se_hdr.se_type) { 193 case ACCESS_DENIED_ACE_TYPE: 194 ag = (ace_flags & INHERITED_ACE) ? 195 SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT; 196 break; 197 198 case ACCESS_ALLOWED_ACE_TYPE: 199 ag = (ace_flags & INHERITED_ACE) ? 200 SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT; 201 break; 202 203 default: 204 /* 205 * This is the lowest priority group so we put 206 * evertything unknown here. 207 */ 208 ag = SMB_AG_ALW_INHRT; 209 break; 210 } 211 212 /* Add the ACE to the selected group */ 213 list_insert_tail(&ace_grps[ag], ace); 214 } 215 216 /* 217 * start with highest priority ACE group and append 218 * the ACEs to the ACL. 219 */ 220 for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) { 221 alist = &ace_grps[i]; 222 while ((ace = list_head(alist)) != NULL) { 223 list_remove(alist, ace); 224 list_insert_tail(&acl->sl_sorted, ace); 225 } 226 list_destroy(alist); 227 } 228 } 229 230 /* 231 * smb_acl_from_zfs 232 * 233 * Converts given ZFS ACL to a Windows ACL. 234 * 235 * A pointer to allocated memory for the Windows ACL will be 236 * returned upon successful conversion. 237 */ 238 smb_acl_t * 239 smb_acl_from_zfs(acl_t *zacl) 240 { 241 ace_t *zace; 242 int numaces; 243 smb_acl_t *acl; 244 smb_ace_t *ace; 245 smb_idmap_batch_t sib; 246 smb_idmap_t *sim; 247 idmap_stat idm_stat; 248 249 idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt, 250 SMB_IDMAP_ID2SID); 251 if (idm_stat != IDMAP_SUCCESS) 252 return (NULL); 253 254 if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) { 255 smb_idmap_batch_destroy(&sib); 256 return (NULL); 257 } 258 259 acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt); 260 261 sim = sib.sib_maps; 262 for (numaces = 0, zace = zacl->acl_aclp; 263 numaces < zacl->acl_cnt; 264 zace++, numaces++, sim++) { 265 assert(sim->sim_sid); 266 if (sim->sim_sid == NULL) { 267 smb_acl_free(acl); 268 acl = NULL; 269 break; 270 } 271 272 ace = &acl->sl_aces[numaces]; 273 ace->se_hdr.se_type = zace->a_type; 274 ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags); 275 ace->se_mask = zace->a_access_mask; 276 ace->se_sid = smb_sid_dup(sim->sim_sid); 277 ace->se_hdr.se_bsize = smb_ace_len(ace); 278 279 acl->sl_bsize += ace->se_hdr.se_bsize; 280 } 281 282 smb_idmap_batch_destroy(&sib); 283 return (acl); 284 } 285 286 /* 287 * smb_acl_to_zfs 288 * 289 * Converts given Windows ACL to a ZFS ACL. 290 * 291 * fs_acl will contain a pointer to the created ZFS ACL. 292 * The allocated memory should be freed by calling 293 * smb_fsacl_free(). 294 * 295 * Since the output parameter, fs_acl, is allocated in this 296 * function, the caller has to make sure *fs_acl is NULL which 297 * means it's not pointing to any memory. 298 */ 299 uint32_t 300 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl) 301 { 302 char sidstr[SMB_SID_STRSZ]; 303 smb_ace_t *ace; 304 acl_t *zacl; 305 ace_t *zace; 306 smb_idmap_batch_t sib; 307 smb_idmap_t *sim; 308 idmap_stat idm_stat; 309 int i; 310 311 assert(fs_acl); 312 assert(*fs_acl == NULL); 313 314 if (acl && !smb_acl_isvalid(acl, which_acl)) 315 return (NT_STATUS_INVALID_ACL); 316 317 if ((acl == NULL) || (acl->sl_acecnt == 0)) { 318 if (which_acl == SMB_DACL_SECINFO) { 319 *fs_acl = smb_fsacl_null_empty(acl == NULL); 320 } 321 322 return (NT_STATUS_SUCCESS); 323 } 324 325 idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt, 326 SMB_IDMAP_SID2ID); 327 if (idm_stat != IDMAP_SUCCESS) 328 return (NT_STATUS_INTERNAL_ERROR); 329 330 zacl = smb_fsacl_alloc(acl->sl_acecnt, flags); 331 332 zace = zacl->acl_aclp; 333 ace = acl->sl_aces; 334 sim = sib.sib_maps; 335 336 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 337 zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES; 338 zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask); 339 zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags); 340 zace->a_who = (uid_t)-1; 341 342 smb_sid_tostr(ace->se_sid, sidstr); 343 344 if (!smb_ace_wellknown_update(sidstr, zace)) { 345 sim->sim_id = &zace->a_who; 346 idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, 347 ace->se_sid, SMB_IDMAP_UNKNOWN); 348 349 if (idm_stat != IDMAP_SUCCESS) { 350 smb_fsacl_free(zacl); 351 smb_idmap_batch_destroy(&sib); 352 return (NT_STATUS_INTERNAL_ERROR); 353 } 354 } 355 } 356 357 idm_stat = smb_idmap_batch_getmappings(&sib); 358 if (idm_stat != IDMAP_SUCCESS) { 359 smb_fsacl_free(zacl); 360 smb_idmap_batch_destroy(&sib); 361 return (NT_STATUS_NONE_MAPPED); 362 } 363 364 /* 365 * Set the ACEs group flag based on the type of ID returned. 366 */ 367 zace = zacl->acl_aclp; 368 ace = acl->sl_aces; 369 sim = sib.sib_maps; 370 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 371 if (zace->a_who == (uid_t)-1) 372 continue; 373 374 if (sim->sim_idtype == SMB_IDMAP_GROUP) 375 zace->a_flags |= ACE_IDENTIFIER_GROUP; 376 } 377 378 smb_idmap_batch_destroy(&sib); 379 380 *fs_acl = zacl; 381 return (NT_STATUS_SUCCESS); 382 } 383 384 static boolean_t 385 smb_ace_wellknown_update(const char *sid, ace_t *zace) 386 { 387 struct { 388 char *sid; 389 uint16_t flags; 390 } map[] = { 391 { NT_WORLD_SIDSTR, ACE_EVERYONE }, 392 { NT_BUILTIN_CURRENT_OWNER_SIDSTR, ACE_OWNER }, 393 { NT_BUILTIN_CURRENT_GROUP_SIDSTR, 394 (ACE_GROUP | ACE_IDENTIFIER_GROUP) }, 395 }; 396 397 int i; 398 399 for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) { 400 if (strcmp(sid, map[i].sid) == 0) { 401 zace->a_flags |= map[i].flags; 402 return (B_TRUE); 403 } 404 } 405 406 return (B_FALSE); 407 } 408 409 /* 410 * smb_fsacl_getsids 411 * 412 * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs. 413 */ 414 static idmap_stat 415 smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl) 416 { 417 ace_t *zace; 418 idmap_stat idm_stat; 419 smb_idmap_t *sim; 420 uid_t id; 421 int i, idtype; 422 423 sim = sib->sib_maps; 424 425 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; 426 zace++, i++, sim++) { 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