xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c (revision b31b5de1357c915fe7dab4d9646d9d84f9fe69bc)
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