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