xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_sd.c (revision 11963:061945695ce1)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
2211447Samw@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw /*
275331Samw  * This module provides Security Descriptor handling functions.
285331Samw  */
295331Samw 
305521Sas200622 #include <smbsrv/smb_kproto.h>
315331Samw #include <smbsrv/smb_fsops.h>
325331Samw #include <smbsrv/smb_idmap.h>
335331Samw 
345521Sas200622 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
355521Sas200622 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
365521Sas200622 static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
375331Samw 
385331Samw void
smb_sd_init(smb_sd_t * sd,uint8_t revision)395331Samw smb_sd_init(smb_sd_t *sd, uint8_t revision)
405331Samw {
415331Samw 	bzero(sd, sizeof (smb_sd_t));
425521Sas200622 	sd->sd_revision = revision;
435331Samw }
445331Samw 
455331Samw /*
465331Samw  * smb_sd_term
475331Samw  *
485331Samw  * Free non-NULL members of 'sd' which has to be in
495331Samw  * absolute (pointer) form.
505331Samw  */
515331Samw void
smb_sd_term(smb_sd_t * sd)525331Samw smb_sd_term(smb_sd_t *sd)
535331Samw {
545331Samw 	ASSERT(sd);
555521Sas200622 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
565331Samw 
576432Sas200622 	smb_sid_free(sd->sd_owner);
586432Sas200622 	smb_sid_free(sd->sd_group);
595521Sas200622 	smb_acl_free(sd->sd_dacl);
605521Sas200622 	smb_acl_free(sd->sd_sacl);
615331Samw 
625331Samw 	bzero(sd, sizeof (smb_sd_t));
635331Samw }
645331Samw 
655521Sas200622 uint32_t
smb_sd_len(smb_sd_t * sd,uint32_t secinfo)665521Sas200622 smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
675331Samw {
685521Sas200622 	uint32_t length = SMB_SD_HDRSIZE;
695331Samw 
705521Sas200622 	if (secinfo & SMB_OWNER_SECINFO)
716432Sas200622 		length += smb_sid_len(sd->sd_owner);
725331Samw 
735521Sas200622 	if (secinfo & SMB_GROUP_SECINFO)
746432Sas200622 		length += smb_sid_len(sd->sd_group);
755331Samw 
765521Sas200622 	if (secinfo & SMB_DACL_SECINFO)
775521Sas200622 		length += smb_acl_len(sd->sd_dacl);
785331Samw 
795521Sas200622 	if (secinfo & SMB_SACL_SECINFO)
805521Sas200622 		length += smb_acl_len(sd->sd_sacl);
815331Samw 
825331Samw 	return (length);
835331Samw }
845331Samw 
855331Samw /*
865331Samw  * smb_sd_get_secinfo
875331Samw  *
885331Samw  * Return the security information mask for the specified security
895331Samw  * descriptor.
905331Samw  */
915331Samw uint32_t
smb_sd_get_secinfo(smb_sd_t * sd)925521Sas200622 smb_sd_get_secinfo(smb_sd_t *sd)
935331Samw {
945331Samw 	uint32_t sec_info = 0;
955331Samw 
965521Sas200622 	if (sd == NULL)
975331Samw 		return (0);
985331Samw 
995521Sas200622 	if (sd->sd_owner)
1005331Samw 		sec_info |= SMB_OWNER_SECINFO;
1015331Samw 
1025521Sas200622 	if (sd->sd_group)
1035331Samw 		sec_info |= SMB_GROUP_SECINFO;
1045331Samw 
1055521Sas200622 	if (sd->sd_dacl)
1065331Samw 		sec_info |= SMB_DACL_SECINFO;
1075331Samw 
1085521Sas200622 	if (sd->sd_sacl)
1095331Samw 		sec_info |= SMB_SACL_SECINFO;
1105331Samw 
1115331Samw 	return (sec_info);
1125331Samw }
1135331Samw 
1145331Samw /*
1155521Sas200622  * smb_sd_read
1165331Samw  *
1175521Sas200622  * Read uid, gid and ACL from filesystem. The returned ACL from read
1185521Sas200622  * routine is always in ZFS format. Convert the ZFS acl to a Win acl
1195521Sas200622  * and return the Win SD in absolute form.
1205331Samw  *
1215521Sas200622  * NOTE: upon successful return caller MUST free the memory allocated
1225521Sas200622  * for the returned SD by calling smb_sd_term().
1235331Samw  */
1245521Sas200622 uint32_t
smb_sd_read(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)1255521Sas200622 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
1265331Samw {
1275521Sas200622 	smb_fssd_t fs_sd;
1285521Sas200622 	smb_error_t smb_err;
1295521Sas200622 	smb_node_t *node;
1305521Sas200622 	uint32_t status = NT_STATUS_SUCCESS;
1315521Sas200622 	uint32_t sd_flags;
1325521Sas200622 	int error;
1335521Sas200622 
1345521Sas200622 	node = sr->fid_ofile->f_node;
135*11963SAfshin.Ardakani@Sun.COM 	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
1365521Sas200622 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
1375521Sas200622 
1385521Sas200622 	error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
1395521Sas200622 	if (error) {
1405772Sas200622 		smbsr_map_errno(error, &smb_err);
1415521Sas200622 		return (smb_err.status);
1425521Sas200622 	}
1435521Sas200622 
1445521Sas200622 	status = smb_sd_fromfs(&fs_sd, sd);
1455521Sas200622 	smb_fssd_term(&fs_sd);
1465521Sas200622 
1475521Sas200622 	return (status);
1485521Sas200622 }
1495521Sas200622 
1505521Sas200622 /*
1515521Sas200622  * smb_sd_write
1525521Sas200622  *
1535521Sas200622  * Takes a Win SD in absolute form, converts it to
1545521Sas200622  * ZFS format and write it to filesystem. The write routine
1555521Sas200622  * converts ZFS acl to Posix acl if required.
1565521Sas200622  */
1575521Sas200622 uint32_t
smb_sd_write(smb_request_t * sr,smb_sd_t * sd,uint32_t secinfo)1585521Sas200622 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
1595521Sas200622 {
1605521Sas200622 	smb_node_t *node;
1615521Sas200622 	smb_fssd_t fs_sd;
1625521Sas200622 	smb_error_t smb_err;
1635521Sas200622 	uint32_t status;
1645521Sas200622 	uint32_t sd_flags;
1655521Sas200622 	int error;
1665521Sas200622 
1675521Sas200622 	node = sr->fid_ofile->f_node;
168*11963SAfshin.Ardakani@Sun.COM 	sd_flags = smb_node_is_dir(node) ? SMB_FSSD_FLAGS_DIR : 0;
1695521Sas200622 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
1705331Samw 
1715521Sas200622 	status = smb_sd_tofs(sd, &fs_sd);
1725521Sas200622 	if (status != NT_STATUS_SUCCESS) {
1735521Sas200622 		smb_fssd_term(&fs_sd);
1745521Sas200622 		return (status);
1755521Sas200622 	}
1765331Samw 
1775521Sas200622 	error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
1785521Sas200622 	smb_fssd_term(&fs_sd);
1795331Samw 
1805521Sas200622 	if (error) {
1817619SJose.Borrego@Sun.COM 		if (error == EBADE)
1827619SJose.Borrego@Sun.COM 			return (NT_STATUS_INVALID_OWNER);
1835772Sas200622 		smbsr_map_errno(error, &smb_err);
1845521Sas200622 		return (smb_err.status);
1855521Sas200622 	}
1865331Samw 
1875521Sas200622 	return (NT_STATUS_SUCCESS);
1885521Sas200622 }
1895521Sas200622 
1905331Samw 
1915521Sas200622 /*
1925521Sas200622  * smb_sd_tofs
1935521Sas200622  *
1945521Sas200622  * Creates a filesystem security structure based on the given
1955521Sas200622  * Windows security descriptor.
1965521Sas200622  */
1975521Sas200622 uint32_t
smb_sd_tofs(smb_sd_t * sd,smb_fssd_t * fs_sd)1985521Sas200622 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
1995521Sas200622 {
2006432Sas200622 	smb_sid_t *sid;
2015521Sas200622 	uint32_t status = NT_STATUS_SUCCESS;
2025521Sas200622 	uint16_t sd_control;
2035521Sas200622 	idmap_stat idm_stat;
2045521Sas200622 	int idtype;
2055521Sas200622 	int flags = 0;
2065331Samw 
2075521Sas200622 	sd_control = sd->sd_control;
2085331Samw 
2095521Sas200622 	/*
2105521Sas200622 	 * ZFS only has one set of flags so for now only
2115521Sas200622 	 * Windows DACL flags are taken into account.
2125521Sas200622 	 */
2135521Sas200622 	if (sd_control & SE_DACL_DEFAULTED)
2145521Sas200622 		flags |= ACL_DEFAULTED;
2155521Sas200622 	if (sd_control & SE_DACL_AUTO_INHERITED)
2165521Sas200622 		flags |= ACL_AUTO_INHERIT;
2175521Sas200622 	if (sd_control & SE_DACL_PROTECTED)
2185521Sas200622 		flags |= ACL_PROTECTED;
2195331Samw 
2205521Sas200622 	if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
2215521Sas200622 		flags |= ACL_IS_DIR;
2225521Sas200622 
2235521Sas200622 	/* Owner */
2245521Sas200622 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
2255521Sas200622 		sid = sd->sd_owner;
2266432Sas200622 		if (!smb_sid_isvalid(sid))
2275521Sas200622 			return (NT_STATUS_INVALID_SID);
2285521Sas200622 
2297619SJose.Borrego@Sun.COM 		idtype = SMB_IDMAP_USER;
2305521Sas200622 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
2315521Sas200622 		if (idm_stat != IDMAP_SUCCESS) {
2325521Sas200622 			return (NT_STATUS_NONE_MAPPED);
2335331Samw 		}
2345331Samw 	}
2355331Samw 
2365521Sas200622 	/* Group */
2375521Sas200622 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
2385521Sas200622 		sid = sd->sd_group;
2396432Sas200622 		if (!smb_sid_isvalid(sid))
2405521Sas200622 			return (NT_STATUS_INVALID_SID);
2415331Samw 
2427619SJose.Borrego@Sun.COM 		idtype = SMB_IDMAP_GROUP;
2435521Sas200622 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
2445521Sas200622 		if (idm_stat != IDMAP_SUCCESS) {
2455521Sas200622 			return (NT_STATUS_NONE_MAPPED);
2465331Samw 		}
2475331Samw 	}
2485331Samw 
2495521Sas200622 	/* DACL */
2505521Sas200622 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
2515521Sas200622 		if (sd->sd_control & SE_DACL_PRESENT) {
2525521Sas200622 			status = smb_acl_to_zfs(sd->sd_dacl, flags,
2535521Sas200622 			    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
2545521Sas200622 			if (status != NT_STATUS_SUCCESS)
2555521Sas200622 				return (status);
2565521Sas200622 		}
2575521Sas200622 		else
2585521Sas200622 			return (NT_STATUS_INVALID_ACL);
2595521Sas200622 	}
2605331Samw 
2615521Sas200622 	/* SACL */
2625521Sas200622 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
2635521Sas200622 		if (sd->sd_control & SE_SACL_PRESENT) {
2645521Sas200622 			status = smb_acl_to_zfs(sd->sd_sacl, flags,
2655521Sas200622 			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
2665521Sas200622 			if (status != NT_STATUS_SUCCESS) {
2675521Sas200622 				return (status);
2685521Sas200622 			}
2695521Sas200622 		} else {
2705521Sas200622 			return (NT_STATUS_INVALID_ACL);
2715331Samw 		}
2725331Samw 	}
2735331Samw 
2745521Sas200622 	return (status);
2755331Samw }
2765331Samw 
2775331Samw /*
2785331Samw  * smb_sd_fromfs
2795331Samw  *
2805331Samw  * Makes an Windows style security descriptor in absolute form
2815331Samw  * based on the given filesystem security information.
2825331Samw  *
2835331Samw  * Should call smb_sd_term() for the returned sd to free allocated
2845331Samw  * members.
2855331Samw  */
2865331Samw static uint32_t
smb_sd_fromfs(smb_fssd_t * fs_sd,smb_sd_t * sd)2875331Samw smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
2885331Samw {
2895331Samw 	uint32_t status = NT_STATUS_SUCCESS;
2905331Samw 	smb_acl_t *acl = NULL;
2916432Sas200622 	smb_sid_t *sid;
2925331Samw 	idmap_stat idm_stat;
2935331Samw 
2945331Samw 	ASSERT(fs_sd);
2955331Samw 	ASSERT(sd);
2965331Samw 
2975331Samw 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
2985331Samw 
2995331Samw 	/* Owner */
3005331Samw 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
3015331Samw 		idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
3025331Samw 		    SMB_IDMAP_USER, &sid);
3035331Samw 
3045331Samw 		if (idm_stat != IDMAP_SUCCESS) {
3055521Sas200622 			smb_sd_term(sd);
3065331Samw 			return (NT_STATUS_NONE_MAPPED);
3075331Samw 		}
3085331Samw 
3095521Sas200622 		sd->sd_owner = sid;
3105331Samw 	}
3115331Samw 
3125331Samw 	/* Group */
3135331Samw 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
3145331Samw 		idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
3155331Samw 		    SMB_IDMAP_GROUP, &sid);
3165331Samw 
3175331Samw 		if (idm_stat != IDMAP_SUCCESS) {
3185331Samw 			smb_sd_term(sd);
3195331Samw 			return (NT_STATUS_NONE_MAPPED);
3205331Samw 		}
3215331Samw 
3225521Sas200622 		sd->sd_group = sid;
3235331Samw 	}
3245331Samw 
3255331Samw 	/* DACL */
3265331Samw 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
3275331Samw 		if (fs_sd->sd_zdacl != NULL) {
32811447Samw@Sun.COM 			acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
3295331Samw 			if (acl == NULL) {
3305331Samw 				smb_sd_term(sd);
3315331Samw 				return (NT_STATUS_INTERNAL_ERROR);
3325331Samw 			}
3335331Samw 
3345331Samw 			/*
3355331Samw 			 * Need to sort the ACL before send it to Windows
3365331Samw 			 * clients. Winodws GUI is sensitive about the order
3375331Samw 			 * of ACEs.
3385331Samw 			 */
3395521Sas200622 			smb_acl_sort(acl);
3405521Sas200622 			smb_sd_set_dacl(sd, acl, B_TRUE,
3415521Sas200622 			    fs_sd->sd_zdacl->acl_flags);
3425331Samw 		} else {
3435521Sas200622 			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
3445331Samw 		}
3455331Samw 	}
3465331Samw 
3475331Samw 	/* SACL */
3485331Samw 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
3495331Samw 		if (fs_sd->sd_zsacl != NULL) {
35011447Samw@Sun.COM 			acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
3515331Samw 			if (acl == NULL) {
3525331Samw 				smb_sd_term(sd);
3535331Samw 				return (NT_STATUS_INTERNAL_ERROR);
3545331Samw 			}
3555331Samw 
3565521Sas200622 			smb_sd_set_sacl(sd, acl, B_TRUE,
3575521Sas200622 			    fs_sd->sd_zsacl->acl_flags);
3585331Samw 		} else {
3595521Sas200622 			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
3605331Samw 		}
3615331Samw 	}
3625331Samw 
3635331Samw 	return (status);
3645331Samw }
3655331Samw 
3665521Sas200622 static void
smb_sd_set_dacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)3675521Sas200622 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
3685331Samw {
3695521Sas200622 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
3705331Samw 
3715521Sas200622 	sd->sd_dacl = acl;
3725331Samw 
3735521Sas200622 	if (flags & ACL_DEFAULTED)
3745521Sas200622 		sd->sd_control |= SE_DACL_DEFAULTED;
3755521Sas200622 	if (flags & ACL_AUTO_INHERIT)
3765521Sas200622 		sd->sd_control |= SE_DACL_AUTO_INHERITED;
3775521Sas200622 	if (flags & ACL_PROTECTED)
3785521Sas200622 		sd->sd_control |= SE_DACL_PROTECTED;
3795331Samw 
3805521Sas200622 	if (present)
3815521Sas200622 		sd->sd_control |= SE_DACL_PRESENT;
3825331Samw }
3835331Samw 
3845521Sas200622 static void
smb_sd_set_sacl(smb_sd_t * sd,smb_acl_t * acl,boolean_t present,int flags)3855521Sas200622 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
3865331Samw {
3875521Sas200622 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
3885521Sas200622 
3895521Sas200622 	sd->sd_sacl = acl;
3905331Samw 
3915521Sas200622 	if (flags & ACL_DEFAULTED)
3925521Sas200622 		sd->sd_control |= SE_SACL_DEFAULTED;
3935521Sas200622 	if (flags & ACL_AUTO_INHERIT)
3945521Sas200622 		sd->sd_control |= SE_SACL_AUTO_INHERITED;
3955521Sas200622 	if (flags & ACL_PROTECTED)
3965521Sas200622 		sd->sd_control |= SE_SACL_PROTECTED;
3975331Samw 
3985521Sas200622 	if (present)
3995521Sas200622 		sd->sd_control |= SE_SACL_PRESENT;
4005331Samw }
4015331Samw 
4025331Samw /*
4035521Sas200622  * smb_fssd_init
4045331Samw  *
4055521Sas200622  * Initializes the given FS SD structure.
4065331Samw  */
4075331Samw void
smb_fssd_init(smb_fssd_t * fs_sd,uint32_t secinfo,uint32_t flags)4085521Sas200622 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
4095331Samw {
4105521Sas200622 	bzero(fs_sd, sizeof (smb_fssd_t));
4115521Sas200622 	fs_sd->sd_secinfo = secinfo;
4125521Sas200622 	fs_sd->sd_flags = flags;
4135331Samw }
4145331Samw 
4155331Samw /*
4165521Sas200622  * smb_fssd_term
4175331Samw  *
4185521Sas200622  * Frees allocated memory for acl fields.
4195331Samw  */
4205331Samw void
smb_fssd_term(smb_fssd_t * fs_sd)4215521Sas200622 smb_fssd_term(smb_fssd_t *fs_sd)
4225331Samw {
4235521Sas200622 	ASSERT(fs_sd);
4245331Samw 
4255521Sas200622 	smb_fsacl_free(fs_sd->sd_zdacl);
4265521Sas200622 	smb_fsacl_free(fs_sd->sd_zsacl);
4275521Sas200622 	bzero(fs_sd, sizeof (smb_fssd_t));
4285331Samw }
429