1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22f96bd5c8SAlan Wright * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24*a90cf9f2SGordon Ross * 25*a90cf9f2SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26da6c28aaSamw */ 27da6c28aaSamw 28da6c28aaSamw /* 29da6c28aaSamw * This module provides Security Descriptor handling functions. 30da6c28aaSamw */ 31da6c28aaSamw 3255bf511dSas200622 #include <smbsrv/smb_kproto.h> 33da6c28aaSamw #include <smbsrv/smb_fsops.h> 34da6c28aaSamw #include <smbsrv/smb_idmap.h> 35da6c28aaSamw 3655bf511dSas200622 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int); 3755bf511dSas200622 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int); 3855bf511dSas200622 static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *); 39da6c28aaSamw 40da6c28aaSamw void 41da6c28aaSamw smb_sd_init(smb_sd_t *sd, uint8_t revision) 42da6c28aaSamw { 43da6c28aaSamw bzero(sd, sizeof (smb_sd_t)); 4455bf511dSas200622 sd->sd_revision = revision; 45da6c28aaSamw } 46da6c28aaSamw 47da6c28aaSamw /* 48da6c28aaSamw * smb_sd_term 49da6c28aaSamw * 50da6c28aaSamw * Free non-NULL members of 'sd' which has to be in 51da6c28aaSamw * absolute (pointer) form. 52da6c28aaSamw */ 53da6c28aaSamw void 54da6c28aaSamw smb_sd_term(smb_sd_t *sd) 55da6c28aaSamw { 56da6c28aaSamw ASSERT(sd); 5755bf511dSas200622 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0); 58da6c28aaSamw 596537f381Sas200622 smb_sid_free(sd->sd_owner); 606537f381Sas200622 smb_sid_free(sd->sd_group); 6155bf511dSas200622 smb_acl_free(sd->sd_dacl); 6255bf511dSas200622 smb_acl_free(sd->sd_sacl); 63da6c28aaSamw 64da6c28aaSamw bzero(sd, sizeof (smb_sd_t)); 65da6c28aaSamw } 66da6c28aaSamw 67da6c28aaSamw uint32_t 6855bf511dSas200622 smb_sd_len(smb_sd_t *sd, uint32_t secinfo) 69da6c28aaSamw { 7055bf511dSas200622 uint32_t length = SMB_SD_HDRSIZE; 71da6c28aaSamw 7255bf511dSas200622 if (secinfo & SMB_OWNER_SECINFO) 736537f381Sas200622 length += smb_sid_len(sd->sd_owner); 74da6c28aaSamw 7555bf511dSas200622 if (secinfo & SMB_GROUP_SECINFO) 766537f381Sas200622 length += smb_sid_len(sd->sd_group); 77da6c28aaSamw 7855bf511dSas200622 if (secinfo & SMB_DACL_SECINFO) 7955bf511dSas200622 length += smb_acl_len(sd->sd_dacl); 80da6c28aaSamw 8155bf511dSas200622 if (secinfo & SMB_SACL_SECINFO) 8255bf511dSas200622 length += smb_acl_len(sd->sd_sacl); 83da6c28aaSamw 84da6c28aaSamw return (length); 85da6c28aaSamw } 86da6c28aaSamw 87da6c28aaSamw /* 88da6c28aaSamw * smb_sd_get_secinfo 89da6c28aaSamw * 90da6c28aaSamw * Return the security information mask for the specified security 91da6c28aaSamw * descriptor. 92da6c28aaSamw */ 93da6c28aaSamw uint32_t 9455bf511dSas200622 smb_sd_get_secinfo(smb_sd_t *sd) 95da6c28aaSamw { 96da6c28aaSamw uint32_t sec_info = 0; 97da6c28aaSamw 9855bf511dSas200622 if (sd == NULL) 99da6c28aaSamw return (0); 100da6c28aaSamw 10155bf511dSas200622 if (sd->sd_owner) 102da6c28aaSamw sec_info |= SMB_OWNER_SECINFO; 103da6c28aaSamw 10455bf511dSas200622 if (sd->sd_group) 105da6c28aaSamw sec_info |= SMB_GROUP_SECINFO; 106da6c28aaSamw 10755bf511dSas200622 if (sd->sd_dacl) 108da6c28aaSamw sec_info |= SMB_DACL_SECINFO; 109da6c28aaSamw 11055bf511dSas200622 if (sd->sd_sacl) 111da6c28aaSamw sec_info |= SMB_SACL_SECINFO; 112da6c28aaSamw 113da6c28aaSamw return (sec_info); 114da6c28aaSamw } 115da6c28aaSamw 116da6c28aaSamw /* 11755bf511dSas200622 * smb_sd_read 118da6c28aaSamw * 11955bf511dSas200622 * Read uid, gid and ACL from filesystem. The returned ACL from read 12055bf511dSas200622 * routine is always in ZFS format. Convert the ZFS acl to a Win acl 12155bf511dSas200622 * and return the Win SD in absolute form. 122da6c28aaSamw * 12355bf511dSas200622 * NOTE: upon successful return caller MUST free the memory allocated 12455bf511dSas200622 * for the returned SD by calling smb_sd_term(). 125da6c28aaSamw */ 12655bf511dSas200622 uint32_t 12755bf511dSas200622 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo) 128da6c28aaSamw { 12955bf511dSas200622 smb_fssd_t fs_sd; 13055bf511dSas200622 smb_node_t *node; 131da6c28aaSamw uint32_t status = NT_STATUS_SUCCESS; 13255bf511dSas200622 uint32_t sd_flags; 13355bf511dSas200622 int error; 134da6c28aaSamw 13555bf511dSas200622 node = sr->fid_ofile->f_node; 1369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0; 13755bf511dSas200622 smb_fssd_init(&fs_sd, secinfo, sd_flags); 138da6c28aaSamw 13955bf511dSas200622 error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd); 140*a90cf9f2SGordon Ross if (error) 141*a90cf9f2SGordon Ross return (smb_errno2status(error)); 142da6c28aaSamw 14355bf511dSas200622 status = smb_sd_fromfs(&fs_sd, sd); 14455bf511dSas200622 smb_fssd_term(&fs_sd); 145da6c28aaSamw 146da6c28aaSamw return (status); 147da6c28aaSamw } 148da6c28aaSamw 149da6c28aaSamw /* 15055bf511dSas200622 * smb_sd_write 15155bf511dSas200622 * 15255bf511dSas200622 * Takes a Win SD in absolute form, converts it to 15355bf511dSas200622 * ZFS format and write it to filesystem. The write routine 15455bf511dSas200622 * converts ZFS acl to Posix acl if required. 15555bf511dSas200622 */ 15655bf511dSas200622 uint32_t 15755bf511dSas200622 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo) 15855bf511dSas200622 { 15955bf511dSas200622 smb_node_t *node; 16055bf511dSas200622 smb_fssd_t fs_sd; 16155bf511dSas200622 uint32_t status; 16255bf511dSas200622 uint32_t sd_flags; 16355bf511dSas200622 int error; 16455bf511dSas200622 16555bf511dSas200622 node = sr->fid_ofile->f_node; 1669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0; 16755bf511dSas200622 smb_fssd_init(&fs_sd, secinfo, sd_flags); 16855bf511dSas200622 16955bf511dSas200622 status = smb_sd_tofs(sd, &fs_sd); 17055bf511dSas200622 if (status != NT_STATUS_SUCCESS) { 17155bf511dSas200622 smb_fssd_term(&fs_sd); 17255bf511dSas200622 return (status); 17355bf511dSas200622 } 17455bf511dSas200622 17555bf511dSas200622 error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0); 17655bf511dSas200622 smb_fssd_term(&fs_sd); 17755bf511dSas200622 17855bf511dSas200622 if (error) { 1792c1b14e5Sjose borrego if (error == EBADE) 1802c1b14e5Sjose borrego return (NT_STATUS_INVALID_OWNER); 181*a90cf9f2SGordon Ross return (smb_errno2status(error)); 18255bf511dSas200622 } 18355bf511dSas200622 18455bf511dSas200622 return (NT_STATUS_SUCCESS); 18555bf511dSas200622 } 18655bf511dSas200622 18755bf511dSas200622 18855bf511dSas200622 /* 189da6c28aaSamw * smb_sd_tofs 190da6c28aaSamw * 191da6c28aaSamw * Creates a filesystem security structure based on the given 192da6c28aaSamw * Windows security descriptor. 193da6c28aaSamw */ 194da6c28aaSamw uint32_t 19555bf511dSas200622 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd) 196da6c28aaSamw { 1976537f381Sas200622 smb_sid_t *sid; 198da6c28aaSamw uint32_t status = NT_STATUS_SUCCESS; 199da6c28aaSamw uint16_t sd_control; 200da6c28aaSamw idmap_stat idm_stat; 201da6c28aaSamw int idtype; 202da6c28aaSamw int flags = 0; 203da6c28aaSamw 20455bf511dSas200622 sd_control = sd->sd_control; 205da6c28aaSamw 206da6c28aaSamw /* 207da6c28aaSamw * ZFS only has one set of flags so for now only 208da6c28aaSamw * Windows DACL flags are taken into account. 209da6c28aaSamw */ 210da6c28aaSamw if (sd_control & SE_DACL_DEFAULTED) 211da6c28aaSamw flags |= ACL_DEFAULTED; 212da6c28aaSamw if (sd_control & SE_DACL_AUTO_INHERITED) 213da6c28aaSamw flags |= ACL_AUTO_INHERIT; 214da6c28aaSamw if (sd_control & SE_DACL_PROTECTED) 215da6c28aaSamw flags |= ACL_PROTECTED; 216da6c28aaSamw 217da6c28aaSamw if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) 218da6c28aaSamw flags |= ACL_IS_DIR; 219da6c28aaSamw 220da6c28aaSamw /* Owner */ 221da6c28aaSamw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 22255bf511dSas200622 sid = sd->sd_owner; 2236537f381Sas200622 if (!smb_sid_isvalid(sid)) 224da6c28aaSamw return (NT_STATUS_INVALID_SID); 225da6c28aaSamw 2262c1b14e5Sjose borrego idtype = SMB_IDMAP_USER; 227da6c28aaSamw idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype); 228da6c28aaSamw if (idm_stat != IDMAP_SUCCESS) { 229da6c28aaSamw return (NT_STATUS_NONE_MAPPED); 230da6c28aaSamw } 231da6c28aaSamw } 232da6c28aaSamw 233da6c28aaSamw /* Group */ 234da6c28aaSamw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 23555bf511dSas200622 sid = sd->sd_group; 2366537f381Sas200622 if (!smb_sid_isvalid(sid)) 237da6c28aaSamw return (NT_STATUS_INVALID_SID); 238da6c28aaSamw 2392c1b14e5Sjose borrego idtype = SMB_IDMAP_GROUP; 240da6c28aaSamw idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype); 241da6c28aaSamw if (idm_stat != IDMAP_SUCCESS) { 242da6c28aaSamw return (NT_STATUS_NONE_MAPPED); 243da6c28aaSamw } 244da6c28aaSamw } 245da6c28aaSamw 246da6c28aaSamw /* DACL */ 247da6c28aaSamw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 24855bf511dSas200622 if (sd->sd_control & SE_DACL_PRESENT) { 24955bf511dSas200622 status = smb_acl_to_zfs(sd->sd_dacl, flags, 250da6c28aaSamw SMB_DACL_SECINFO, &fs_sd->sd_zdacl); 251da6c28aaSamw if (status != NT_STATUS_SUCCESS) 252da6c28aaSamw return (status); 253da6c28aaSamw } 254da6c28aaSamw else 255da6c28aaSamw return (NT_STATUS_INVALID_ACL); 256da6c28aaSamw } 257da6c28aaSamw 258da6c28aaSamw /* SACL */ 259da6c28aaSamw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) { 26055bf511dSas200622 if (sd->sd_control & SE_SACL_PRESENT) { 26155bf511dSas200622 status = smb_acl_to_zfs(sd->sd_sacl, flags, 262da6c28aaSamw SMB_SACL_SECINFO, &fs_sd->sd_zsacl); 263da6c28aaSamw if (status != NT_STATUS_SUCCESS) { 264da6c28aaSamw return (status); 265da6c28aaSamw } 266da6c28aaSamw } else { 267da6c28aaSamw return (NT_STATUS_INVALID_ACL); 268da6c28aaSamw } 269da6c28aaSamw } 270da6c28aaSamw 271da6c28aaSamw return (status); 272da6c28aaSamw } 273da6c28aaSamw 274da6c28aaSamw /* 27555bf511dSas200622 * smb_sd_fromfs 276da6c28aaSamw * 27755bf511dSas200622 * Makes an Windows style security descriptor in absolute form 27855bf511dSas200622 * based on the given filesystem security information. 279da6c28aaSamw * 28055bf511dSas200622 * Should call smb_sd_term() for the returned sd to free allocated 28155bf511dSas200622 * members. 282da6c28aaSamw */ 28355bf511dSas200622 static uint32_t 28455bf511dSas200622 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd) 285da6c28aaSamw { 286da6c28aaSamw uint32_t status = NT_STATUS_SUCCESS; 28755bf511dSas200622 smb_acl_t *acl = NULL; 2886537f381Sas200622 smb_sid_t *sid; 28955bf511dSas200622 idmap_stat idm_stat; 290da6c28aaSamw 29155bf511dSas200622 ASSERT(fs_sd); 29255bf511dSas200622 ASSERT(sd); 293da6c28aaSamw 29455bf511dSas200622 smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION); 295da6c28aaSamw 29655bf511dSas200622 /* Owner */ 29755bf511dSas200622 if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 29855bf511dSas200622 idm_stat = smb_idmap_getsid(fs_sd->sd_uid, 29955bf511dSas200622 SMB_IDMAP_USER, &sid); 300da6c28aaSamw 30155bf511dSas200622 if (idm_stat != IDMAP_SUCCESS) { 30255bf511dSas200622 smb_sd_term(sd); 30355bf511dSas200622 return (NT_STATUS_NONE_MAPPED); 304da6c28aaSamw } 305da6c28aaSamw 30655bf511dSas200622 sd->sd_owner = sid; 30755bf511dSas200622 } 30855bf511dSas200622 30955bf511dSas200622 /* Group */ 31055bf511dSas200622 if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 31155bf511dSas200622 idm_stat = smb_idmap_getsid(fs_sd->sd_gid, 31255bf511dSas200622 SMB_IDMAP_GROUP, &sid); 31355bf511dSas200622 31455bf511dSas200622 if (idm_stat != IDMAP_SUCCESS) { 31555bf511dSas200622 smb_sd_term(sd); 31655bf511dSas200622 return (NT_STATUS_NONE_MAPPED); 31755bf511dSas200622 } 31855bf511dSas200622 31955bf511dSas200622 sd->sd_group = sid; 32055bf511dSas200622 } 32155bf511dSas200622 32255bf511dSas200622 /* DACL */ 32355bf511dSas200622 if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 32455bf511dSas200622 if (fs_sd->sd_zdacl != NULL) { 325f96bd5c8SAlan Wright acl = smb_acl_from_zfs(fs_sd->sd_zdacl); 32655bf511dSas200622 if (acl == NULL) { 32755bf511dSas200622 smb_sd_term(sd); 32855bf511dSas200622 return (NT_STATUS_INTERNAL_ERROR); 32955bf511dSas200622 } 33055bf511dSas200622 331da6c28aaSamw /* 33255bf511dSas200622 * Need to sort the ACL before send it to Windows 33355bf511dSas200622 * clients. Winodws GUI is sensitive about the order 33455bf511dSas200622 * of ACEs. 335da6c28aaSamw */ 33655bf511dSas200622 smb_acl_sort(acl); 33755bf511dSas200622 smb_sd_set_dacl(sd, acl, B_TRUE, 33855bf511dSas200622 fs_sd->sd_zdacl->acl_flags); 33955bf511dSas200622 } else { 34055bf511dSas200622 smb_sd_set_dacl(sd, NULL, B_FALSE, 0); 34155bf511dSas200622 } 342da6c28aaSamw } 343da6c28aaSamw 34455bf511dSas200622 /* SACL */ 34555bf511dSas200622 if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) { 34655bf511dSas200622 if (fs_sd->sd_zsacl != NULL) { 347f96bd5c8SAlan Wright acl = smb_acl_from_zfs(fs_sd->sd_zsacl); 34855bf511dSas200622 if (acl == NULL) { 34955bf511dSas200622 smb_sd_term(sd); 35055bf511dSas200622 return (NT_STATUS_INTERNAL_ERROR); 351da6c28aaSamw } 352da6c28aaSamw 35355bf511dSas200622 smb_sd_set_sacl(sd, acl, B_TRUE, 35455bf511dSas200622 fs_sd->sd_zsacl->acl_flags); 35555bf511dSas200622 } else { 35655bf511dSas200622 smb_sd_set_sacl(sd, NULL, B_FALSE, 0); 35755bf511dSas200622 } 358da6c28aaSamw } 359da6c28aaSamw 36055bf511dSas200622 return (status); 36155bf511dSas200622 } 36255bf511dSas200622 36355bf511dSas200622 static void 36455bf511dSas200622 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags) 36555bf511dSas200622 { 36655bf511dSas200622 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0); 36755bf511dSas200622 36855bf511dSas200622 sd->sd_dacl = acl; 36955bf511dSas200622 37055bf511dSas200622 if (flags & ACL_DEFAULTED) 37155bf511dSas200622 sd->sd_control |= SE_DACL_DEFAULTED; 37255bf511dSas200622 if (flags & ACL_AUTO_INHERIT) 37355bf511dSas200622 sd->sd_control |= SE_DACL_AUTO_INHERITED; 37455bf511dSas200622 if (flags & ACL_PROTECTED) 37555bf511dSas200622 sd->sd_control |= SE_DACL_PROTECTED; 37655bf511dSas200622 37755bf511dSas200622 if (present) 37855bf511dSas200622 sd->sd_control |= SE_DACL_PRESENT; 37955bf511dSas200622 } 38055bf511dSas200622 38155bf511dSas200622 static void 38255bf511dSas200622 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags) 38355bf511dSas200622 { 38455bf511dSas200622 ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0); 38555bf511dSas200622 38655bf511dSas200622 sd->sd_sacl = acl; 38755bf511dSas200622 38855bf511dSas200622 if (flags & ACL_DEFAULTED) 38955bf511dSas200622 sd->sd_control |= SE_SACL_DEFAULTED; 39055bf511dSas200622 if (flags & ACL_AUTO_INHERIT) 39155bf511dSas200622 sd->sd_control |= SE_SACL_AUTO_INHERITED; 39255bf511dSas200622 if (flags & ACL_PROTECTED) 39355bf511dSas200622 sd->sd_control |= SE_SACL_PROTECTED; 39455bf511dSas200622 39555bf511dSas200622 if (present) 39655bf511dSas200622 sd->sd_control |= SE_SACL_PRESENT; 39755bf511dSas200622 } 39855bf511dSas200622 39955bf511dSas200622 /* 40055bf511dSas200622 * smb_fssd_init 40155bf511dSas200622 * 40255bf511dSas200622 * Initializes the given FS SD structure. 40355bf511dSas200622 */ 40455bf511dSas200622 void 40555bf511dSas200622 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags) 40655bf511dSas200622 { 40755bf511dSas200622 bzero(fs_sd, sizeof (smb_fssd_t)); 40855bf511dSas200622 fs_sd->sd_secinfo = secinfo; 40955bf511dSas200622 fs_sd->sd_flags = flags; 41055bf511dSas200622 } 41155bf511dSas200622 41255bf511dSas200622 /* 41355bf511dSas200622 * smb_fssd_term 41455bf511dSas200622 * 41555bf511dSas200622 * Frees allocated memory for acl fields. 41655bf511dSas200622 */ 41755bf511dSas200622 void 41855bf511dSas200622 smb_fssd_term(smb_fssd_t *fs_sd) 41955bf511dSas200622 { 42055bf511dSas200622 ASSERT(fs_sd); 42155bf511dSas200622 42255bf511dSas200622 smb_fsacl_free(fs_sd->sd_zdacl); 42355bf511dSas200622 smb_fsacl_free(fs_sd->sd_zsacl); 42455bf511dSas200622 bzero(fs_sd, sizeof (smb_fssd_t)); 425da6c28aaSamw } 426