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