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 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 <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, fs_sd->sd_uid,
    329 			    fs_sd->sd_gid);
    330 			if (acl == NULL) {
    331 				smb_sd_term(sd);
    332 				return (NT_STATUS_INTERNAL_ERROR);
    333 			}
    334 
    335 			/*
    336 			 * Need to sort the ACL before send it to Windows
    337 			 * clients. Winodws GUI is sensitive about the order
    338 			 * of ACEs.
    339 			 */
    340 			smb_acl_sort(acl);
    341 			smb_sd_set_dacl(sd, acl, B_TRUE,
    342 			    fs_sd->sd_zdacl->acl_flags);
    343 		} else {
    344 			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
    345 		}
    346 	}
    347 
    348 	/* SACL */
    349 	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
    350 		if (fs_sd->sd_zsacl != NULL) {
    351 			acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
    352 			    fs_sd->sd_gid);
    353 			if (acl == NULL) {
    354 				smb_sd_term(sd);
    355 				return (NT_STATUS_INTERNAL_ERROR);
    356 			}
    357 
    358 			smb_sd_set_sacl(sd, acl, B_TRUE,
    359 			    fs_sd->sd_zsacl->acl_flags);
    360 		} else {
    361 			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
    362 		}
    363 	}
    364 
    365 	return (status);
    366 }
    367 
    368 static void
    369 smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
    370 {
    371 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
    372 
    373 	sd->sd_dacl = acl;
    374 
    375 	if (flags & ACL_DEFAULTED)
    376 		sd->sd_control |= SE_DACL_DEFAULTED;
    377 	if (flags & ACL_AUTO_INHERIT)
    378 		sd->sd_control |= SE_DACL_AUTO_INHERITED;
    379 	if (flags & ACL_PROTECTED)
    380 		sd->sd_control |= SE_DACL_PROTECTED;
    381 
    382 	if (present)
    383 		sd->sd_control |= SE_DACL_PRESENT;
    384 }
    385 
    386 static void
    387 smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
    388 {
    389 	ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0);
    390 
    391 	sd->sd_sacl = acl;
    392 
    393 	if (flags & ACL_DEFAULTED)
    394 		sd->sd_control |= SE_SACL_DEFAULTED;
    395 	if (flags & ACL_AUTO_INHERIT)
    396 		sd->sd_control |= SE_SACL_AUTO_INHERITED;
    397 	if (flags & ACL_PROTECTED)
    398 		sd->sd_control |= SE_SACL_PROTECTED;
    399 
    400 	if (present)
    401 		sd->sd_control |= SE_SACL_PRESENT;
    402 }
    403 
    404 /*
    405  * smb_fssd_init
    406  *
    407  * Initializes the given FS SD structure.
    408  */
    409 void
    410 smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
    411 {
    412 	bzero(fs_sd, sizeof (smb_fssd_t));
    413 	fs_sd->sd_secinfo = secinfo;
    414 	fs_sd->sd_flags = flags;
    415 }
    416 
    417 /*
    418  * smb_fssd_term
    419  *
    420  * Frees allocated memory for acl fields.
    421  */
    422 void
    423 smb_fssd_term(smb_fssd_t *fs_sd)
    424 {
    425 	ASSERT(fs_sd);
    426 
    427 	smb_fsacl_free(fs_sd->sd_zdacl);
    428 	smb_fsacl_free(fs_sd->sd_zsacl);
    429 	bzero(fs_sd, sizeof (smb_fssd_t));
    430 }
    431