Home | History | Annotate | Download | only in smbsrv
      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 /*
     27  * This module provides Security Descriptor handling functions.
     28  */
     29 
     30 #include <smbsrv/smb_kproto.h>
     31 #include <smbsrv/smb_fsops.h>
     32 #include <smbsrv/smb_idmap.h>
     33 
     34 static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
     35 static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
     36 static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
     37 
     38 void
     39 smb_sd_init(smb_sd_t *sd, uint8_t revision)
     40 {
     41 	bzero(sd, sizeof (smb_sd_t));
     42 	sd->sd_revision = revision;
     43 }
     44 
     45 /*
     46  * smb_sd_term
     47  *
     48  * Free non-NULL members of 'sd' which has to be in
     49  * absolute (pointer) form.
     50  */
     51 void
     52 smb_sd_term(smb_sd_t *sd)
     53 {
     54 	ASSERT(sd);
     55 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
     56 
     57 	smb_sid_free(sd->sd_owner);
     58 	smb_sid_free(sd->sd_group);
     59 	smb_acl_free(sd->sd_dacl);
     60 	smb_acl_free(sd->sd_sacl);
     61 
     62 	bzero(sd, sizeof (smb_sd_t));
     63 }
     64 
     65 uint32_t
     66 smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
     67 {
     68 	uint32_t length = SMB_SD_HDRSIZE;
     69 
     70 	if (secinfo & SMB_OWNER_SECINFO)
     71 		length += smb_sid_len(sd->sd_owner);
     72 
     73 	if (secinfo & SMB_GROUP_SECINFO)
     74 		length += smb_sid_len(sd->sd_group);
     75 
     76 	if (secinfo & SMB_DACL_SECINFO)
     77 		length += smb_acl_len(sd->sd_dacl);
     78 
     79 	if (secinfo & SMB_SACL_SECINFO)
     80 		length += smb_acl_len(sd->sd_sacl);
     81 
     82 	return (length);
     83 }
     84 
     85 /*
     86  * smb_sd_get_secinfo
     87  *
     88  * Return the security information mask for the specified security
     89  * descriptor.
     90  */
     91 uint32_t
     92 smb_sd_get_secinfo(smb_sd_t *sd)
     93 {
     94 	uint32_t sec_info = 0;
     95 
     96 	if (sd == NULL)
     97 		return (0);
     98 
     99 	if (sd->sd_owner)
    100 		sec_info |= SMB_OWNER_SECINFO;
    101 
    102 	if (sd->sd_group)
    103 		sec_info |= SMB_GROUP_SECINFO;
    104 
    105 	if (sd->sd_dacl)
    106 		sec_info |= SMB_DACL_SECINFO;
    107 
    108 	if (sd->sd_sacl)
    109 		sec_info |= SMB_SACL_SECINFO;
    110 
    111 	return (sec_info);
    112 }
    113 
    114 /*
    115  * smb_sd_read
    116  *
    117  * Read uid, gid and ACL from filesystem. The returned ACL from read
    118  * routine is always in ZFS format. Convert the ZFS acl to a Win acl
    119  * and return the Win SD in absolute form.
    120  *
    121  * NOTE: upon successful return caller MUST free the memory allocated
    122  * for the returned SD by calling smb_sd_term().
    123  */
    124 uint32_t
    125 smb_sd_read(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
    126 {
    127 	smb_fssd_t fs_sd;
    128 	smb_error_t smb_err;
    129 	smb_node_t *node;
    130 	uint32_t status = NT_STATUS_SUCCESS;
    131 	uint32_t sd_flags;
    132 	int error;
    133 
    134 	node = sr->fid_ofile->f_node;
    135 	sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
    136 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
    137 
    138 	error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
    139 	if (error) {
    140 		smbsr_map_errno(error, &smb_err);
    141 		return (smb_err.status);
    142 	}
    143 
    144 	status = smb_sd_fromfs(&fs_sd, sd);
    145 	smb_fssd_term(&fs_sd);
    146 
    147 	return (status);
    148 }
    149 
    150 /*
    151  * smb_sd_write
    152  *
    153  * Takes a Win SD in absolute form, converts it to
    154  * ZFS format and write it to filesystem. The write routine
    155  * converts ZFS acl to Posix acl if required.
    156  */
    157 uint32_t
    158 smb_sd_write(smb_request_t *sr, smb_sd_t *sd, uint32_t secinfo)
    159 {
    160 	smb_node_t *node;
    161 	smb_fssd_t fs_sd;
    162 	smb_error_t smb_err;
    163 	uint32_t status;
    164 	uint32_t sd_flags;
    165 	int error;
    166 
    167 	node = sr->fid_ofile->f_node;
    168 	sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
    169 	smb_fssd_init(&fs_sd, secinfo, sd_flags);
    170 
    171 	status = smb_sd_tofs(sd, &fs_sd);
    172 	if (status != NT_STATUS_SUCCESS) {
    173 		smb_fssd_term(&fs_sd);
    174 		return (status);
    175 	}
    176 
    177 	error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
    178 	smb_fssd_term(&fs_sd);
    179 
    180 	if (error) {
    181 		if (error == EBADE)
    182 			return (NT_STATUS_INVALID_OWNER);
    183 		smbsr_map_errno(error, &smb_err);
    184 		return (smb_err.status);
    185 	}
    186 
    187 	return (NT_STATUS_SUCCESS);
    188 }
    189 
    190 
    191 /*
    192  * smb_sd_tofs
    193  *
    194  * Creates a filesystem security structure based on the given
    195  * Windows security descriptor.
    196  */
    197 uint32_t
    198 smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
    199 {
    200 	smb_sid_t *sid;
    201 	uint32_t status = NT_STATUS_SUCCESS;
    202 	uint16_t sd_control;
    203 	idmap_stat idm_stat;
    204 	int idtype;
    205 	int flags = 0;
    206 
    207 	sd_control = sd->sd_control;
    208 
    209 	/*
    210 	 * ZFS only has one set of flags so for now only
    211 	 * Windows DACL flags are taken into account.
    212 	 */
    213 	if (sd_control & SE_DACL_DEFAULTED)
    214 		flags |= ACL_DEFAULTED;
    215 	if (sd_control & SE_DACL_AUTO_INHERITED)
    216 		flags |= ACL_AUTO_INHERIT;
    217 	if (sd_control & SE_DACL_PROTECTED)
    218 		flags |= ACL_PROTECTED;
    219 
    220 	if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
    221 		flags |= ACL_IS_DIR;
    222 
    223 	/* Owner */
    224 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
    225 		sid = sd->sd_owner;
    226 		if (!smb_sid_isvalid(sid))
    227 			return (NT_STATUS_INVALID_SID);
    228 
    229 		idtype = SMB_IDMAP_USER;
    230 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
    231 		if (idm_stat != IDMAP_SUCCESS) {
    232 			return (NT_STATUS_NONE_MAPPED);
    233 		}
    234 	}
    235 
    236 	/* Group */
    237 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
    238 		sid = sd->sd_group;
    239 		if (!smb_sid_isvalid(sid))
    240 			return (NT_STATUS_INVALID_SID);
    241 
    242 		idtype = SMB_IDMAP_GROUP;
    243 		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
    244 		if (idm_stat != IDMAP_SUCCESS) {
    245 			return (NT_STATUS_NONE_MAPPED);
    246 		}
    247 	}
    248 
    249 	/* DACL */
    250 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
    251 		if (sd->sd_control & SE_DACL_PRESENT) {
    252 			status = smb_acl_to_zfs(sd->sd_dacl, flags,
    253 			    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
    254 			if (status != NT_STATUS_SUCCESS)
    255 				return (status);
    256 		}
    257 		else
    258 			return (NT_STATUS_INVALID_ACL);
    259 	}
    260 
    261 	/* SACL */
    262 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
    263 		if (sd->sd_control & SE_SACL_PRESENT) {
    264 			status = smb_acl_to_zfs(sd->sd_sacl, flags,
    265 			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
    266 			if (status != NT_STATUS_SUCCESS) {
    267 				return (status);
    268 			}
    269 		} else {
    270 			return (NT_STATUS_INVALID_ACL);
    271 		}
    272 	}
    273 
    274 	return (status);
    275 }
    276 
    277 /*
    278  * smb_sd_fromfs
    279  *
    280  * Makes an Windows style security descriptor in absolute form
    281  * based on the given filesystem security information.
    282  *
    283  * Should call smb_sd_term() for the returned sd to free allocated
    284  * members.
    285  */
    286 static uint32_t
    287 smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
    288 {
    289 	uint32_t status = NT_STATUS_SUCCESS;
    290 	smb_acl_t *acl = NULL;
    291 	smb_sid_t *sid;
    292 	idmap_stat idm_stat;
    293 
    294 	ASSERT(fs_sd);
    295 	ASSERT(sd);
    296 
    297 	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
    298 
    299 	/* Owner */
    300 	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
    301 		idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
    302 		    SMB_IDMAP_USER, &sid);
    303 
    304 		if (idm_stat != IDMAP_SUCCESS) {
    305 			smb_sd_term(sd);
    306 			return (NT_STATUS_NONE_MAPPED);
    307 		}
    308 
    309 		sd->sd_owner = sid;
    310 	}
    311 
    312 	/* Group */
    313 	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
    314 		idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
    315 		    SMB_IDMAP_GROUP, &sid);
    316 
    317 		if (idm_stat != IDMAP_SUCCESS) {
    318 			smb_sd_term(sd);
    319 			return (NT_STATUS_NONE_MAPPED);
    320 		}
    321 
    322 		sd->sd_group = sid;
    323 	}
    324 
    325 	/* DACL */
    326 	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
    327 		if (fs_sd->sd_zdacl != NULL) {
    328 			acl = smb_acl_from_zfs(fs_sd->sd_zdacl);
    329 			if (acl == NULL) {
    330 				smb_sd_term(sd);
    331 				return (NT_STATUS_INTERNAL_ERROR);
    332 			}
    333 
    334 			/*
    335 			 * Need to sort the ACL before send it to Windows
    336 			 * clients. Winodws GUI is sensitive about the order
    337 			 * of ACEs.
    338 			 */
    339 			smb_acl_sort(acl);
    340 			smb_sd_set_dacl(sd, acl, B_TRUE,
    341 			    fs_sd->sd_zdacl->acl_flags);
    342 		} else {
    343 			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
    344 		}
    345 	}
    346 
    347 	/* SACL */
    348 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
    349 		if (fs_sd->sd_zsacl != NULL) {
    350 			acl = smb_acl_from_zfs(fs_sd->sd_zsacl);
    351 			if (acl == NULL) {
    352 				smb_sd_term(sd);
    353 				return (NT_STATUS_INTERNAL_ERROR);
    354 			}
    355 
    356 			smb_sd_set_sacl(sd, acl, B_TRUE,
    357 			    fs_sd->sd_zsacl->acl_flags);
    358 		} else {
    359 			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
    360 		}
    361 	}
    362 
    363 	return (status);
    364 }
    365 
    366 static void
    367 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
    368 {
    369 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
    370 
    371 	sd->sd_dacl = acl;
    372 
    373 	if (flags & ACL_DEFAULTED)
    374 		sd->sd_control |= SE_DACL_DEFAULTED;
    375 	if (flags & ACL_AUTO_INHERIT)
    376 		sd->sd_control |= SE_DACL_AUTO_INHERITED;
    377 	if (flags & ACL_PROTECTED)
    378 		sd->sd_control |= SE_DACL_PROTECTED;
    379 
    380 	if (present)
    381 		sd->sd_control |= SE_DACL_PRESENT;
    382 }
    383 
    384 static void
    385 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
    386 {
    387 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
    388 
    389 	sd->sd_sacl = acl;
    390 
    391 	if (flags & ACL_DEFAULTED)
    392 		sd->sd_control |= SE_SACL_DEFAULTED;
    393 	if (flags & ACL_AUTO_INHERIT)
    394 		sd->sd_control |= SE_SACL_AUTO_INHERITED;
    395 	if (flags & ACL_PROTECTED)
    396 		sd->sd_control |= SE_SACL_PROTECTED;
    397 
    398 	if (present)
    399 		sd->sd_control |= SE_SACL_PRESENT;
    400 }
    401 
    402 /*
    403  * smb_fssd_init
    404  *
    405  * Initializes the given FS SD structure.
    406  */
    407 void
    408 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
    409 {
    410 	bzero(fs_sd, sizeof (smb_fssd_t));
    411 	fs_sd->sd_secinfo = secinfo;
    412 	fs_sd->sd_flags = flags;
    413 }
    414 
    415 /*
    416  * smb_fssd_term
    417  *
    418  * Frees allocated memory for acl fields.
    419  */
    420 void
    421 smb_fssd_term(smb_fssd_t *fs_sd)
    422 {
    423 	ASSERT(fs_sd);
    424 
    425 	smb_fsacl_free(fs_sd->sd_zdacl);
    426 	smb_fsacl_free(fs_sd->sd_zsacl);
    427 	bzero(fs_sd, sizeof (smb_fssd_t));
    428 }
    429