Home | History | Annotate | Download | only in smbfs
      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 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * ACL support for smbfs
     31  */
     32 
     33 #include <sys/systm.h>	/* bcopy, ... */
     34 #include <sys/errno.h>
     35 #include <sys/cred.h>
     36 #include <sys/cmn_err.h>
     37 #include <sys/kmem.h>
     38 #include <sys/sunddi.h>
     39 #include <sys/acl.h>
     40 #include <sys/vnode.h>
     41 #include <sys/vfs.h>
     42 #include <sys/byteorder.h>
     43 
     44 #include <netsmb/smb_osdep.h>
     45 #include <netsmb/smb.h>
     46 #include <netsmb/smb_conn.h>
     47 #include <netsmb/smb_subr.h>
     48 #include <netsmb/mchain.h>
     49 
     50 #include <smbfs/smbfs.h>
     51 #include <smbfs/smbfs_node.h>
     52 #include <smbfs/smbfs_subr.h>
     53 
     54 #include <sys/fs/smbfs_ioctl.h>
     55 #include <fs/fs_subr.h>
     56 
     57 /* Sanity check SD sizes */
     58 #define	MAX_RAW_SD_SIZE	32768
     59 #define	SMALL_SD_SIZE	1024
     60 
     61 #undef	ACL_SUPPORT	/* not yet */
     62 
     63 
     64 /*
     65  * smbfs_getsd(), smbfs_setsd() are common functions used by
     66  * both ioctl get/set ACL and VOP_GETSECATTR, VOP_SETSECATTR.
     67  * Handles required rights, tmpopen/tmpclose.
     68  *
     69  * Note: smbfs_getsd allocates and returns an mblk chain,
     70  * which the caller must free.
     71  */
     72 int
     73 smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
     74 {
     75 	struct smb_cred scred;
     76 	int error, cerror;
     77 	smbmntinfo_t *smi;
     78 	smbnode_t	*np;
     79 	u_int16_t	fid = SMB_FID_UNUSED;
     80 	uint32_t	sdlen = SMALL_SD_SIZE;
     81 	uint32_t	rights = STD_RIGHT_READ_CONTROL_ACCESS;
     82 
     83 	if (selector & SACL_SECURITY_INFORMATION)
     84 		rights |= SEC_RIGHT_SYSTEM_SECURITY;
     85 
     86 	np = VTOSMB(vp);
     87 	smi = VTOSMI(vp);
     88 
     89 	/* Shared lock for (possible) n_fid use. */
     90 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
     91 		return (EINTR);
     92 	smb_credinit(&scred, curproc, cr);
     93 
     94 	error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
     95 	if (error)
     96 		goto out;
     97 
     98 again:
     99 	/*
    100 	 * This does the OTW Get
    101 	 */
    102 	error = smbfs_smb_getsec_m(smi->smi_share, fid,
    103 	    &scred, selector, mp, &sdlen);
    104 	/*
    105 	 * Server may give us an error indicating that we
    106 	 * need a larger data buffer to receive the SD,
    107 	 * and the size we'll need.  Use the given size,
    108 	 * but only after a sanity check.
    109 	 *
    110 	 * Let's check for specific error values here.
    111 	 * The NT error is: STATUS_BUFFER_TOO_SMALL,
    112 	 * or with old error codes, one of these:
    113 	 * ERRSRV/ERRnoroom, ERRDOS/122, ERRDOS/111
    114 	 * Those are mapped to: EMOREDATA, which is
    115 	 * later converted to E2BIG.
    116 	 */
    117 	if (error == E2BIG &&
    118 	    sdlen > SMALL_SD_SIZE &&
    119 	    sdlen <= MAX_RAW_SD_SIZE)
    120 		goto again;
    121 
    122 	cerror = smbfs_smb_tmpclose(np, fid, &scred);
    123 	if (cerror)
    124 		SMBERROR("error %d closing file %s\n",
    125 		    cerror, np->n_rpath);
    126 
    127 out:
    128 	smb_credrele(&scred);
    129 	smbfs_rw_exit(&np->r_lkserlock);
    130 
    131 	return (error);
    132 }
    133 
    134 int
    135 smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
    136 {
    137 	struct smb_cred scred;
    138 	int error, cerror;
    139 	smbmntinfo_t *smi;
    140 	smbnode_t	*np;
    141 	uint32_t	rights;
    142 	u_int16_t	fid = SMB_FID_UNUSED;
    143 
    144 	np = VTOSMB(vp);
    145 	smi = VTOSMI(vp);
    146 
    147 	/*
    148 	 * Which parts of the SD are we setting?
    149 	 * What rights do we need for that?
    150 	 */
    151 	if (selector == 0)
    152 		return (0);
    153 	rights = 0;
    154 	if (selector & (OWNER_SECURITY_INFORMATION |
    155 	    GROUP_SECURITY_INFORMATION))
    156 		rights |= STD_RIGHT_WRITE_OWNER_ACCESS;
    157 	if (selector & DACL_SECURITY_INFORMATION)
    158 		rights |= STD_RIGHT_WRITE_DAC_ACCESS;
    159 	if (selector & SACL_SECURITY_INFORMATION)
    160 		rights |= SEC_RIGHT_SYSTEM_SECURITY;
    161 
    162 	/* Shared lock for (possible) n_fid use. */
    163 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
    164 		return (EINTR);
    165 	smb_credinit(&scred, curproc, cr);
    166 
    167 	error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
    168 	if (error)
    169 		goto out;
    170 
    171 	/*
    172 	 * This does the OTW Set
    173 	 */
    174 	error = smbfs_smb_setsec_m(smi->smi_share, fid,
    175 	    &scred, selector, mp);
    176 
    177 	cerror = smbfs_smb_tmpclose(np, fid, &scred);
    178 	if (cerror)
    179 		SMBERROR("error %d closing file %s\n",
    180 		    cerror, np->n_rpath);
    181 
    182 out:
    183 	smb_credrele(&scred);
    184 	smbfs_rw_exit(&np->r_lkserlock);
    185 
    186 	return (error);
    187 }
    188 
    189 /*
    190  * Entry points from VOP_IOCTL
    191  */
    192 int
    193 smbfs_ioc_getsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
    194 {
    195 	ioc_sdbuf_t iocb;
    196 	mdchain_t *mdp, md_store;
    197 	mblk_t *m;
    198 	void *ubuf;
    199 	int error;
    200 
    201 	/*
    202 	 * Get the buffer information
    203 	 */
    204 	if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
    205 		return (EFAULT);
    206 
    207 	/*
    208 	 * This does the OTW Get (and maybe open, close)
    209 	 * Allocates and returns an mblk in &m.
    210 	 */
    211 	error = smbfs_getsd(vp, iocb.selector, &m, cr);
    212 	if (error)
    213 		return (error);
    214 
    215 	/*
    216 	 * Have m.  Must free it before return.
    217 	 */
    218 	mdp = &md_store;
    219 	md_initm(mdp, m);
    220 	iocb.used = m_fixhdr(m);
    221 
    222 	/*
    223 	 * Always copyout the buffer information,
    224 	 * so the user can realloc and try again
    225 	 * after an EOVERFLOW return.
    226 	 */
    227 	if (ddi_copyout(&iocb, (void *)arg, sizeof (iocb), flag)) {
    228 		error = EFAULT;
    229 		goto out;
    230 	}
    231 
    232 	if (iocb.used > iocb.alloc) {
    233 		error = EOVERFLOW;
    234 		goto out;
    235 	}
    236 
    237 	/*
    238 	 * Copyout the buffer contents (SD)
    239 	 */
    240 	ubuf = (void *)(uintptr_t)iocb.addr;
    241 	error = md_get_mem(mdp, ubuf, iocb.used, MB_MUSER);
    242 
    243 out:
    244 	/* Note: m_freem(m) is done by... */
    245 	md_done(mdp);
    246 
    247 	return (error);
    248 }
    249 
    250 int
    251 smbfs_ioc_setsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
    252 {
    253 	ioc_sdbuf_t iocb;
    254 	mbchain_t *mbp, mb_store;
    255 	void *ubuf;
    256 	int error;
    257 
    258 	/*
    259 	 * Get the buffer information
    260 	 */
    261 	if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
    262 		return (EFAULT);
    263 
    264 	if (iocb.used < sizeof (ntsecdesc_t) ||
    265 	    iocb.used >= MAX_RAW_SD_SIZE)
    266 		return (EINVAL);
    267 
    268 	/*
    269 	 * Get the buffer contents (security descriptor data)
    270 	 */
    271 	mbp = &mb_store;
    272 	mb_init(mbp);
    273 	ubuf = (void *)(uintptr_t)iocb.addr;
    274 	error = mb_put_mem(mbp, ubuf, iocb.used, MB_MUSER);
    275 	if (error)
    276 		goto out;
    277 
    278 	/*
    279 	 * This does the OTW Set (and maybe open, close)
    280 	 * It clears mb_top when consuming the message.
    281 	 */
    282 	error = smbfs_setsd(vp, iocb.selector, &mbp->mb_top, cr);
    283 
    284 out:
    285 	mb_done(mbp);
    286 	return (error);
    287 
    288 }
    289 
    290 #ifdef	ACL_SUPPORT
    291 /*
    292  * Conversion functions for VOP_GETSECATTR, VOP_SETSECATTR
    293  *
    294  * XXX: We may or may not add conversion code here, or we
    295  * may add that to usr/src/common (TBD).  For now all the
    296  * ACL conversion code is in libsmbfs.
    297  */
    298 
    299 /*
    300  * Convert a Windows SD (in the mdchain mdp) into a
    301  * ZFS-style vsecattr_t and possibly uid, gid.
    302  */
    303 /* ARGSUSED */
    304 static int
    305 smb_ntsd2vsec(mdchain_t *mdp, vsecattr_t *vsa,
    306 	int *uidp, int *gidp, cred_t *cr)
    307 {
    308 	/* XXX NOT_YET */
    309 	return (ENOSYS);
    310 }
    311 
    312 /*
    313  * Convert a ZFS-style vsecattr_t (and possibly uid, gid)
    314  * into a Windows SD (built in the mbchain mbp).
    315  */
    316 /* ARGSUSED */
    317 static int
    318 smb_vsec2ntsd(vsecattr_t *vsa, int uid, int gid,
    319 	mbchain_t *mbp, cred_t *cr)
    320 {
    321 	/* XXX NOT_YET */
    322 	return (ENOSYS);
    323 }
    324 #endif	/* ACL_SUPPORT */
    325 
    326 /*
    327  * Entry points from VOP_GETSECATTR, VOP_SETSECATTR
    328  *
    329  * Disabled the real _getacl functionality for now,
    330  * because we have no way to return the owner and
    331  * primary group until we replace our fake uid/gid
    332  * in getattr with something derived from _getsd.
    333  */
    334 
    335 /* ARGSUSED */
    336 int
    337 smbfs_getacl(vnode_t *vp, vsecattr_t *vsa,
    338 	int *uidp, int *gidp, int flag, cred_t *cr)
    339 {
    340 #ifdef	ACL_SUPPORT
    341 	mdchain_t *mdp, md_store;
    342 	mblk_t *m;
    343 	uint32_t	selector;
    344 	int		error;
    345 
    346 	/*
    347 	 * Which parts of the SD we request.
    348 	 * XXX: We need a way to let the caller specify
    349 	 * what parts she wants - i.e. the SACL?
    350 	 * XXX: selector |= SACL_SECURITY_INFORMATION;
    351 	 * Or maybe: if we get access denied, try the
    352 	 * open/fetch again without the SACL bit.
    353 	 */
    354 	selector = 0;
    355 	if (vsa)
    356 		selector |= DACL_SECURITY_INFORMATION;
    357 	if (uidp)
    358 		selector |= OWNER_SECURITY_INFORMATION;
    359 	if (gidp)
    360 		selector |= GROUP_SECURITY_INFORMATION;
    361 	if (selector == 0)
    362 		return (0);
    363 
    364 	/*
    365 	 * This does the OTW Get (and maybe open, close)
    366 	 * Allocates and returns an mblk in &m.
    367 	 */
    368 	error = smbfs_getsd(vp, selector, &m, cr);
    369 	if (error)
    370 		return (error);
    371 
    372 	/*
    373 	 * Have m.  Must free it before return.
    374 	 */
    375 	mdp = &md_store;
    376 	md_initm(mdp, m);
    377 
    378 	/*
    379 	 * Convert the Windows security descriptor to a
    380 	 * ZFS ACL (and owner ID, primary group ID).
    381 	 * This is the difficult part. (todo)
    382 	 */
    383 	error = smb_ntsd2vsec(mdp, vsa, uidp, gidp, cr);
    384 
    385 	/* Note: m_freem(m) is done by... */
    386 	md_done(mdp);
    387 
    388 	return (error);
    389 #else	/* ACL_SUPPORT */
    390 	return (ENOSYS);
    391 #endif	/* ACL_SUPPORT */
    392 }
    393 
    394 
    395 /* ARGSUSED */
    396 int
    397 smbfs_setacl(vnode_t *vp, vsecattr_t *vsa,
    398 	int uid, int gid, int flag, cred_t *cr)
    399 {
    400 #ifdef	ACL_SUPPORT
    401 	mbchain_t *mbp, mb_store;
    402 	uint32_t	selector;
    403 	int		error;
    404 
    405 	/*
    406 	 * Which parts of the SD we'll modify.
    407 	 * Ditto comments above re. SACL
    408 	 */
    409 	selector = 0;
    410 	if (vsa)
    411 		selector |= DACL_SECURITY_INFORMATION;
    412 	if (uid != -1)
    413 		selector |= OWNER_SECURITY_INFORMATION;
    414 	if (gid != -1)
    415 		selector |= GROUP_SECURITY_INFORMATION;
    416 	if (selector == 0)
    417 		return (0);
    418 
    419 	/*
    420 	 * Setup buffer for SD data.
    421 	 */
    422 	mbp = &mb_store;
    423 	mb_init(mbp);
    424 
    425 	/*
    426 	 * Convert a ZFS ACL (and owner ID, group ID)
    427 	 * to a Windows security descriptor.
    428 	 * This is the difficult part. (todo)
    429 	 */
    430 	error = smb_vsec2ntsd(vsa, uid, gid, mbp, cr);
    431 	if (error)
    432 		goto out;
    433 
    434 	/*
    435 	 * This does the OTW Set (and maybe open, close)
    436 	 * It clears mb_top when consuming the message.
    437 	 */
    438 	error = smbfs_setsd(vp, selector, &mbp->mb_top, cr);
    439 
    440 out:
    441 	mb_done(mbp);
    442 	return (error);
    443 #else	/* ACL_SUPPORT */
    444 	return (ENOSYS);
    445 #endif	/* ACL_SUPPORT */
    446 }
    447