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