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 /* 27 * This module provides Security Descriptor handling functions. 28 */ 29 30 #include <strings.h> 31 #include <assert.h> 32 #include <smbsrv/ntifs.h> 33 #include <smbsrv/smb_idmap.h> 34 #include <smbsrv/ntstatus.h> 35 #include <smbsrv/libsmb.h> 36 37 #define SMB_SHR_ACE_READ_PERMS (ACE_READ_PERMS | ACE_EXECUTE | ACE_SYNCHRONIZE) 38 #define SMB_SHR_ACE_CONTROL_PERMS (ACE_MODIFY_PERMS & (~ACE_DELETE_CHILD)) 39 40 #define SMB_SHR_ACE_MODIFY_PERMS (ACE_MODIFY_PERMS & \ 41 (~(ACE_READ_DATA | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | \ 42 ACE_EXECUTE | ACE_DELETE_CHILD))) 43 44 static struct { 45 int am_ace_perms; 46 int am_share_perms; 47 } smb_ace_map[] = { 48 { ACE_ALL_PERMS, ACE_ALL_PERMS }, 49 { ACE_MODIFY_PERMS, SMB_SHR_ACE_CONTROL_PERMS }, 50 { ACE_MODIFY_PERMS, SMB_SHR_ACE_MODIFY_PERMS }, 51 { ACE_READ_PERMS, SMB_SHR_ACE_READ_PERMS } 52 }; 53 54 #define SMB_ACE_MASK_MAP_SIZE (sizeof (smb_ace_map)/sizeof (smb_ace_map[0])) 55 56 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int); 57 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int); 58 59 void 60 smb_sd_init(smb_sd_t *sd, uint8_t revision) 61 { 62 bzero(sd, sizeof (smb_sd_t)); 63 sd->sd_revision = revision; 64 } 65 66 /* 67 * smb_sd_term 68 * 69 * Free non-NULL members of 'sd' which has to be in 70 * absolute (pointer) form. 71 */ 72 void 73 smb_sd_term(smb_sd_t *sd) 74 { 75 assert(sd); 76 assert((sd->sd_control & SE_SELF_RELATIVE) == 0); 77 78 smb_sid_free(sd->sd_owner); 79 smb_sid_free(sd->sd_group); 80 smb_acl_free(sd->sd_dacl); 81 smb_acl_free(sd->sd_sacl); 82 83 bzero(sd, sizeof (smb_sd_t)); 84 } 85 86 uint32_t 87 smb_sd_len(smb_sd_t *sd, uint32_t secinfo) 88 { 89 uint32_t length = SMB_SD_HDRSIZE; 90 91 if (secinfo & SMB_OWNER_SECINFO) 92 length += smb_sid_len(sd->sd_owner); 93 94 if (secinfo & SMB_GROUP_SECINFO) 95 length += smb_sid_len(sd->sd_group); 96 97 if (secinfo & SMB_DACL_SECINFO) 98 length += smb_acl_len(sd->sd_dacl); 99 100 if (secinfo & SMB_SACL_SECINFO) 101 length += smb_acl_len(sd->sd_sacl); 102 103 return (length); 104 } 105 106 /* 107 * smb_sd_get_secinfo 108 * 109 * Return the security information mask for the specified security 110 * descriptor. 111 */ 112 uint32_t 113 smb_sd_get_secinfo(smb_sd_t *sd) 114 { 115 uint32_t sec_info = 0; 116 117 if (sd == NULL) 118 return (0); 119 120 if (sd->sd_owner) 121 sec_info |= SMB_OWNER_SECINFO; 122 123 if (sd->sd_group) 124 sec_info |= SMB_GROUP_SECINFO; 125 126 if (sd->sd_dacl) 127 sec_info |= SMB_DACL_SECINFO; 128 129 if (sd->sd_sacl) 130 sec_info |= SMB_SACL_SECINFO; 131 132 return (sec_info); 133 } 134 135 /* 136 * Adjust the Access Mask so that ZFS ACE mask and Windows ACE read mask match. 137 */ 138 static int 139 smb_sd_adjust_read_mask(int mask) 140 { 141 int i; 142 143 for (i = 0; i < SMB_ACE_MASK_MAP_SIZE; ++i) { 144 if (smb_ace_map[i].am_ace_perms == mask) 145 return (smb_ace_map[i].am_share_perms); 146 } 147 148 return (-1); 149 } 150 151 /* 152 * Get ZFS acl from the share path via acl_get() method. 153 */ 154 static uint32_t 155 smb_sd_read_acl(char *path, smb_fssd_t *fs_sd) 156 { 157 acl_t *z_acl; 158 ace_t *z_ace; 159 int mask; 160 161 fs_sd->sd_gid = fs_sd->sd_uid = 0; 162 if (acl_trivial(path) != 1) 163 return (NT_STATUS_INTERNAL_ERROR); 164 165 if (acl_get(path, ACL_NO_TRIVIAL, &z_acl) != 0) 166 return (NT_STATUS_INTERNAL_ERROR); 167 168 if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL) 169 return (NT_STATUS_INVALID_ACL); 170 171 for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++) { 172 mask = smb_sd_adjust_read_mask(z_ace->a_access_mask); 173 if (mask == -1) 174 return (NT_STATUS_INVALID_ACL); 175 z_ace->a_access_mask = mask; 176 } 177 178 fs_sd->sd_zdacl = z_acl; 179 fs_sd->sd_zsacl = NULL; 180 return (NT_STATUS_SUCCESS); 181 } 182 183 /* 184 * smb_sd_read 185 * 186 * Reads ZFS acl from filesystem using acl_get() method. Convert the ZFS acl to 187 * a Win SD and return the Win SD in absolute form. 188 * 189 * NOTE: upon successful return caller MUST free the memory allocated 190 * for the returned SD by calling smb_sd_term(). 191 */ 192 uint32_t 193 smb_sd_read(char *path, smb_sd_t *sd, uint32_t secinfo) 194 { 195 smb_fssd_t fs_sd; 196 uint32_t status = NT_STATUS_SUCCESS; 197 uint32_t sd_flags; 198 int error; 199 200 sd_flags = SMB_FSSD_FLAGS_DIR; 201 smb_fssd_init(&fs_sd, secinfo, sd_flags); 202 203 error = smb_sd_read_acl(path, &fs_sd); 204 if (error != NT_STATUS_SUCCESS) { 205 smb_fssd_term(&fs_sd); 206 return (error); 207 } 208 209 status = smb_sd_fromfs(&fs_sd, sd); 210 smb_fssd_term(&fs_sd); 211 212 return (status); 213 } 214 215 /* 216 * Adjust the Access Mask so that ZFS ACE mask and Windows ACE write mask match. 217 */ 218 static int 219 smb_sd_adjust_write_mask(int mask) 220 { 221 int i; 222 223 for (i = 0; i < SMB_ACE_MASK_MAP_SIZE; ++i) { 224 if (smb_ace_map[i].am_share_perms == mask) 225 return (smb_ace_map[i].am_ace_perms); 226 } 227 228 return (-1); 229 } 230 231 /* 232 * Apply ZFS acl to the share path via acl_set() method. 233 */ 234 static uint32_t 235 smb_sd_write_acl(char *path, smb_fssd_t *fs_sd) 236 { 237 acl_t *z_acl; 238 ace_t *z_ace; 239 int mask; 240 uint32_t status = NT_STATUS_SUCCESS; 241 242 if ((z_acl = fs_sd->sd_zdacl) == NULL) 243 return (NT_STATUS_INVALID_ACL); 244 245 if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL) 246 return (NT_STATUS_INVALID_ACL); 247 248 for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++) { 249 mask = smb_sd_adjust_write_mask(z_ace->a_access_mask); 250 if (mask == -1) 251 return (NT_STATUS_INVALID_ACL); 252 z_ace->a_access_mask = mask; 253 } 254 255 fs_sd->sd_gid = fs_sd->sd_uid = 0; 256 if (acl_set(path, z_acl) != 0) 257 status = NT_STATUS_INTERNAL_ERROR; 258 259 return (status); 260 } 261 262 /* 263 * smb_sd_write 264 * 265 * Takes a Win SD in absolute form, converts it to 266 * ZFS acl and applies the acl to the share path via acl_set() method. 267 */ 268 uint32_t 269 smb_sd_write(char *path, smb_sd_t *sd, uint32_t secinfo) 270 { 271 smb_fssd_t fs_sd; 272 uint32_t status = NT_STATUS_SUCCESS; 273 uint32_t sd_flags; 274 int error; 275 276 sd_flags = SMB_FSSD_FLAGS_DIR; 277 smb_fssd_init(&fs_sd, secinfo, sd_flags); 278 279 error = smb_sd_tofs(sd, &fs_sd); 280 if (error != NT_STATUS_SUCCESS) { 281 smb_fssd_term(&fs_sd); 282 return (error); 283 } 284 285 status = smb_sd_write_acl(path, &fs_sd); 286 smb_fssd_term(&fs_sd); 287 288 return (status); 289 } 290 291 /* 292 * smb_sd_tofs 293 * 294 * Creates a filesystem security structure based on the given 295 * Windows security descriptor. 296 */ 297 uint32_t 298 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd) 299 { 300 smb_sid_t *sid; 301 uint32_t status = NT_STATUS_SUCCESS; 302 uint16_t sd_control; 303 idmap_stat idm_stat; 304 int idtype; 305 int flags = 0; 306 307 sd_control = sd->sd_control; 308 309 /* 310 * ZFS only has one set of flags so for now only 311 * Windows DACL flags are taken into account. 312 */ 313 if (sd_control & SE_DACL_DEFAULTED) 314 flags |= ACL_DEFAULTED; 315 if (sd_control & SE_DACL_AUTO_INHERITED) 316 flags |= ACL_AUTO_INHERIT; 317 if (sd_control & SE_DACL_PROTECTED) 318 flags |= ACL_PROTECTED; 319 320 if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) 321 flags |= ACL_IS_DIR; 322 323 /* Owner */ 324 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 325 sid = sd->sd_owner; 326 if (!smb_sid_isvalid(sid)) 327 return (NT_STATUS_INVALID_SID); 328 329 idtype = SMB_IDMAP_USER; 330 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype); 331 if (idm_stat != IDMAP_SUCCESS) { 332 return (NT_STATUS_NONE_MAPPED); 333 } 334 } 335 336 /* Group */ 337 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 338 sid = sd->sd_group; 339 if (!smb_sid_isvalid(sid)) 340 return (NT_STATUS_INVALID_SID); 341 342 idtype = SMB_IDMAP_GROUP; 343 idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype); 344 if (idm_stat != IDMAP_SUCCESS) { 345 return (NT_STATUS_NONE_MAPPED); 346 } 347 } 348 349 /* DACL */ 350 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 351 if (sd->sd_control & SE_DACL_PRESENT) { 352 status = smb_acl_to_zfs(sd->sd_dacl, flags, 353 SMB_DACL_SECINFO, &fs_sd->sd_zdacl); 354 if (status != NT_STATUS_SUCCESS) 355 return (status); 356 } 357 else 358 return (NT_STATUS_INVALID_ACL); 359 } 360 361 /* SACL */ 362 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) { 363 if (sd->sd_control & SE_SACL_PRESENT) { 364 status = smb_acl_to_zfs(sd->sd_sacl, flags, 365 SMB_SACL_SECINFO, &fs_sd->sd_zsacl); 366 if (status != NT_STATUS_SUCCESS) { 367 return (status); 368 } 369 } else { 370 return (NT_STATUS_INVALID_ACL); 371 } 372 } 373 374 return (status); 375 } 376 377 /* 378 * smb_sd_fromfs 379 * 380 * Makes an Windows style security descriptor in absolute form 381 * based on the given filesystem security information. 382 * 383 * Should call smb_sd_term() for the returned sd to free allocated 384 * members. 385 */ 386 uint32_t 387 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd) 388 { 389 uint32_t status = NT_STATUS_SUCCESS; 390 smb_acl_t *acl = NULL; 391 smb_sid_t *sid; 392 idmap_stat idm_stat; 393 394 assert(fs_sd); 395 assert(sd); 396 397 smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION); 398 399 /* Owner */ 400 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 401 idm_stat = smb_idmap_getsid(fs_sd->sd_uid, 402 SMB_IDMAP_USER, &sid); 403 404 if (idm_stat != IDMAP_SUCCESS) { 405 smb_sd_term(sd); 406 return (NT_STATUS_NONE_MAPPED); 407 } 408 409 sd->sd_owner = sid; 410 } 411 412 /* Group */ 413 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 414 idm_stat = smb_idmap_getsid(fs_sd->sd_gid, 415 SMB_IDMAP_GROUP, &sid); 416 417 if (idm_stat != IDMAP_SUCCESS) { 418 smb_sd_term(sd); 419 return (NT_STATUS_NONE_MAPPED); 420 } 421 422 sd->sd_group = sid; 423 } 424 425 /* DACL */ 426 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 427 if (fs_sd->sd_zdacl != NULL) { 428 acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid, 429 fs_sd->sd_gid); 430 if (acl == NULL) { 431 smb_sd_term(sd); 432 return (NT_STATUS_INTERNAL_ERROR); 433 } 434 435 /* 436 * Need to sort the ACL before send it to Windows 437 * clients. Winodws GUI is sensitive about the order 438 * of ACEs. 439 */ 440 smb_acl_sort(acl); 441 smb_sd_set_dacl(sd, acl, B_TRUE, 442 fs_sd->sd_zdacl->acl_flags); 443 } else { 444 smb_sd_set_dacl(sd, NULL, B_FALSE, 0); 445 } 446 } 447 448 /* SACL */ 449 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) { 450 if (fs_sd->sd_zsacl != NULL) { 451 acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid, 452 fs_sd->sd_gid); 453 if (acl == NULL) { 454 smb_sd_term(sd); 455 return (NT_STATUS_INTERNAL_ERROR); 456 } 457 458 smb_sd_set_sacl(sd, acl, B_TRUE, 459 fs_sd->sd_zsacl->acl_flags); 460 } else { 461 smb_sd_set_sacl(sd, NULL, B_FALSE, 0); 462 } 463 } 464 465 return (status); 466 } 467 468 static void 469 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags) 470 { 471 assert((sd->sd_control & SE_SELF_RELATIVE) == 0); 472 473 sd->sd_dacl = acl; 474 475 if (flags & ACL_DEFAULTED) 476 sd->sd_control |= SE_DACL_DEFAULTED; 477 if (flags & ACL_AUTO_INHERIT) 478 sd->sd_control |= SE_DACL_AUTO_INHERITED; 479 if (flags & ACL_PROTECTED) 480 sd->sd_control |= SE_DACL_PROTECTED; 481 482 if (present) 483 sd->sd_control |= SE_DACL_PRESENT; 484 } 485 486 static void 487 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags) 488 { 489 assert((sd->sd_control & SE_SELF_RELATIVE) == 0); 490 491 sd->sd_sacl = acl; 492 493 if (flags & ACL_DEFAULTED) 494 sd->sd_control |= SE_SACL_DEFAULTED; 495 if (flags & ACL_AUTO_INHERIT) 496 sd->sd_control |= SE_SACL_AUTO_INHERITED; 497 if (flags & ACL_PROTECTED) 498 sd->sd_control |= SE_SACL_PROTECTED; 499 500 if (present) 501 sd->sd_control |= SE_SACL_PRESENT; 502 } 503 504 /* 505 * smb_fssd_init 506 * 507 * Initializes the given FS SD structure. 508 */ 509 void 510 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags) 511 { 512 bzero(fs_sd, sizeof (smb_fssd_t)); 513 fs_sd->sd_secinfo = secinfo; 514 fs_sd->sd_flags = flags; 515 } 516 517 /* 518 * smb_fssd_term 519 * 520 * Frees allocated memory for acl fields. 521 */ 522 void 523 smb_fssd_term(smb_fssd_t *fs_sd) 524 { 525 assert(fs_sd); 526 527 acl_free(fs_sd->sd_zdacl); 528 acl_free(fs_sd->sd_zsacl); 529 530 bzero(fs_sd, sizeof (smb_fssd_t)); 531 } 532