xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
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 2010 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 static 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 /*
131  * smbfs_setsd() is a common function used by both
132  * smbfs_ioctl SMBFSIO_SETSD and VOP_SETSECATTR.
133  * Handles required rights, tmpopen/tmpclose.
134  *
135  * Note: smbfs_setsd _consumes_ the passed *mp and
136  * clears the pointer (so the caller won't free it)
137  */
138 static int
139 smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
140 {
141 	struct smb_cred scred;
142 	int error, cerror;
143 	smbmntinfo_t *smi;
144 	smbnode_t	*np;
145 	uint32_t	rights;
146 	u_int16_t	fid = SMB_FID_UNUSED;
147 
148 	np = VTOSMB(vp);
149 	smi = VTOSMI(vp);
150 
151 	/*
152 	 * Which parts of the SD are we setting?
153 	 * What rights do we need for that?
154 	 */
155 	if (selector == 0)
156 		return (0);
157 
158 	rights = 0;
159 	if (selector & (OWNER_SECURITY_INFORMATION |
160 	    GROUP_SECURITY_INFORMATION))
161 		rights |= STD_RIGHT_WRITE_OWNER_ACCESS;
162 	if (selector & DACL_SECURITY_INFORMATION)
163 		rights |= STD_RIGHT_WRITE_DAC_ACCESS;
164 	if (selector & SACL_SECURITY_INFORMATION)
165 		rights |= SEC_RIGHT_SYSTEM_SECURITY;
166 
167 	/* Shared lock for (possible) n_fid use. */
168 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
169 		return (EINTR);
170 	smb_credinit(&scred, cr);
171 
172 	error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
173 	if (error)
174 		goto out;
175 
176 	/*
177 	 * We're setting the remote ACL now, so
178 	 * invalidate our cached ACL just in case
179 	 * the server doesn't do exactly as we ask.
180 	 */
181 	mutex_enter(&np->r_statelock);
182 	np->r_sectime = gethrtime();
183 	mutex_exit(&np->r_statelock);
184 
185 	/*
186 	 * This does the OTW Set
187 	 */
188 	error = smbfs_smb_setsec_m(smi->smi_share, fid,
189 	    &scred, selector, mp);
190 
191 	cerror = smbfs_smb_tmpclose(np, fid, &scred);
192 	if (cerror)
193 		SMBVDEBUG("error %d closing file %s\n",
194 		    cerror, np->n_rpath);
195 
196 out:
197 	smb_credrele(&scred);
198 	smbfs_rw_exit(&np->r_lkserlock);
199 
200 	return (error);
201 }
202 
203 /*
204  * Helper for VOP_IOCTL: SMBFSIO_GETSD
205  */
206 int
207 smbfs_acl_iocget(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
208 {
209 	ioc_sdbuf_t iocb;
210 	mdchain_t *mdp, md_store;
211 	mblk_t *m;
212 	void *ubuf;
213 	int error;
214 
215 	/*
216 	 * Get the buffer information
217 	 */
218 	if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
219 		return (EFAULT);
220 
221 	/*
222 	 * This does the OTW Get (and maybe open, close)
223 	 * Allocates and returns an mblk in &m.
224 	 */
225 	error = smbfs_getsd(vp, iocb.selector, &m, cr);
226 	if (error)
227 		return (error);
228 
229 	/*
230 	 * Have m.  Must free it before return.
231 	 */
232 	mdp = &md_store;
233 	md_initm(mdp, m);
234 	iocb.used = m_fixhdr(m);
235 
236 	/*
237 	 * Always copyout the buffer information,
238 	 * so the user can realloc and try again
239 	 * after an EOVERFLOW return.
240 	 */
241 	if (ddi_copyout(&iocb, (void *)arg, sizeof (iocb), flag)) {
242 		error = EFAULT;
243 		goto out;
244 	}
245 
246 	if (iocb.used > iocb.alloc) {
247 		error = EOVERFLOW;
248 		goto out;
249 	}
250 
251 	/*
252 	 * Copyout the buffer contents (SD)
253 	 */
254 	ubuf = (void *)(uintptr_t)iocb.addr;
255 	error = md_get_mem(mdp, ubuf, iocb.used, MB_MUSER);
256 
257 out:
258 	/* Note: m_freem(m) is done by... */
259 	md_done(mdp);
260 
261 	return (error);
262 }
263 
264 /*
265  * Helper for VOP_IOCTL: SMBFSIO_SETSD
266  */
267 int
268 smbfs_acl_iocset(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
269 {
270 	ioc_sdbuf_t iocb;
271 	mbchain_t *mbp, mb_store;
272 	void *ubuf;
273 	int error;
274 
275 	/*
276 	 * Get the buffer information
277 	 */
278 	if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
279 		return (EFAULT);
280 
281 	if (iocb.used < sizeof (ntsecdesc_t) ||
282 	    iocb.used >= MAX_RAW_SD_SIZE)
283 		return (EINVAL);
284 
285 	/*
286 	 * Get the buffer contents (security descriptor data)
287 	 */
288 	mbp = &mb_store;
289 	(void) mb_init(mbp);
290 	ubuf = (void *)(uintptr_t)iocb.addr;
291 	error = mb_put_mem(mbp, ubuf, iocb.used, MB_MUSER);
292 	if (error)
293 		goto out;
294 
295 	/*
296 	 * This does the OTW Set (and maybe open, close)
297 	 * It clears mb_top when consuming the message.
298 	 */
299 	error = smbfs_setsd(vp, iocb.selector, &mbp->mb_top, cr);
300 
301 out:
302 	mb_done(mbp);
303 	return (error);
304 
305 }
306 
307 /*
308  * Refresh our cached copy of the security attributes
309  */
310 static int
311 smbfs_acl_refresh(vnode_t *vp, cred_t *cr)
312 {
313 	smbnode_t *np;
314 	smbmntinfo_t *smi;
315 	mdchain_t *mdp, md_store;
316 	mblk_t *m = NULL;
317 	i_ntsd_t *sd = NULL;
318 	vsecattr_t vsa, ovsa;
319 	uint32_t selector;
320 	uid_t uid;
321 	gid_t gid;
322 	int error;
323 
324 	np = VTOSMB(vp);
325 	smi = VTOSMI(vp);
326 
327 	bzero(&md_store, sizeof (md_store));
328 	mdp = &md_store;
329 
330 	/*
331 	 * Which parts of the SD we request.
332 	 * Not getting the SACL for now.
333 	 */
334 	selector = DACL_SECURITY_INFORMATION |
335 	    OWNER_SECURITY_INFORMATION |
336 	    GROUP_SECURITY_INFORMATION;
337 
338 	/*
339 	 * This does the OTW Get (and maybe open, close)
340 	 * Allocates and returns an mblk in &m.
341 	 */
342 	error = smbfs_getsd(vp, selector, &m, cr);
343 	if (error)
344 		goto out;
345 	/* Note: allocated *m */
346 	md_initm(mdp, m);
347 
348 	/*
349 	 * Parse the OtW security descriptor,
350 	 * storing in our internal form.
351 	 */
352 	error = md_get_ntsd(mdp, &sd);
353 	if (error)
354 		goto out;
355 
356 	/*
357 	 * Convert the Windows security descriptor to a
358 	 * ZFS ACL (and owner ID, primary group ID).
359 	 */
360 	bzero(&vsa, sizeof (vsa));
361 	vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
362 	error = smbfs_acl_sd2zfs(sd, &vsa, &uid, &gid);
363 	if (error)
364 		goto out;
365 
366 	ASSERT(vsa.vsa_aclentp != NULL);
367 	SMBVDEBUG("uid=%u, gid=%u", uid, gid);
368 
369 	/*
370 	 * Store the results in r_secattr, n_uid, n_gid
371 	 */
372 	mutex_enter(&np->r_statelock);
373 	ovsa = np->r_secattr;
374 	np->r_secattr = vsa;
375 	np->n_uid = uid;
376 	np->n_gid = gid;
377 	/*
378 	 * ACLs don't change frequently, so cache these
379 	 * for a relatively long time (ac dir max).
380 	 */
381 	np->r_sectime = gethrtime() + smi->smi_acdirmax;
382 	mutex_exit(&np->r_statelock);
383 
384 	/* Allocated in: smbfs_acl_sd2zfs */
385 	if (ovsa.vsa_aclentp != NULL)
386 		kmem_free(ovsa.vsa_aclentp, ovsa.vsa_aclentsz);
387 
388 out:
389 	if (sd != NULL)
390 		smbfs_acl_free_sd(sd);
391 	/* Note: m_freem(m) is done by... */
392 	md_done(mdp);
393 
394 	return (error);
395 }
396 
397 /*
398  * Helper for smbfsgetattr()
399  *
400  * Just refresh the ACL cache if needed,
401  * which updates n_uid/n_gid
402  */
403 int
404 smbfs_acl_getids(vnode_t *vp, cred_t *cr)
405 {
406 	smbnode_t *np;
407 	int error;
408 
409 	np = VTOSMB(vp);
410 
411 	/*
412 	 * NB: extended attribute files and directories
413 	 * do not have ACLs separate from the parent.
414 	 * Let the caller do ACL fabrication.
415 	 */
416 	if (np->n_flag & N_XATTR)
417 		return (ENOSYS);
418 
419 	mutex_enter(&np->r_statelock);
420 	if (gethrtime() >= np->r_sectime) {
421 		/* Need to update r_secattr */
422 		mutex_exit(&np->r_statelock);
423 		error = smbfs_acl_refresh(vp, cr);
424 		return (error);
425 	}
426 	mutex_exit(&np->r_statelock);
427 
428 	return (0);
429 }
430 
431 /*
432  * Helper for VOP_GETSECATTR
433  *
434  * Refresh the ACL cache if needed, then
435  * duplicate the requested parts of the vsecattr.
436  */
437 /* ARGSUSED */
438 int
439 smbfs_acl_getvsa(vnode_t *vp, vsecattr_t *vsa,
440 	int flag, cred_t *cr)
441 {
442 	smbnode_t *np;
443 	int error;
444 
445 	np = VTOSMB(vp);
446 
447 	/*
448 	 * NB: extended attribute files and directories
449 	 * do not have ACLs separate from the parent.
450 	 * Let the caller do ACL fabrication.
451 	 */
452 	if (np->n_flag & N_XATTR)
453 		return (ENOSYS);
454 
455 	mutex_enter(&np->r_statelock);
456 
457 	if (np->r_secattr.vsa_aclentp == NULL ||
458 	    gethrtime() >= np->r_sectime) {
459 		/* Need to update r_secattr */
460 		mutex_exit(&np->r_statelock);
461 
462 		error = smbfs_acl_refresh(vp, cr);
463 		if (error)
464 			return (error);
465 
466 		mutex_enter(&np->r_statelock);
467 	}
468 	ASSERT(np->r_secattr.vsa_aclentp != NULL);
469 
470 	/*
471 	 * Duplicate requested parts of r_secattr
472 	 */
473 
474 	if (vsa->vsa_mask & VSA_ACECNT)
475 		vsa->vsa_aclcnt = np->r_secattr.vsa_aclcnt;
476 
477 	if (vsa->vsa_mask & VSA_ACE) {
478 		vsa->vsa_aclentsz = np->r_secattr.vsa_aclentsz;
479 		vsa->vsa_aclentp = kmem_alloc(vsa->vsa_aclentsz, KM_SLEEP);
480 		bcopy(np->r_secattr.vsa_aclentp, vsa->vsa_aclentp,
481 		    vsa->vsa_aclentsz);
482 	}
483 
484 	mutex_exit(&np->r_statelock);
485 	return (0);
486 }
487 
488 /*
489  * Helper for smbfs_acl_setids, smbfs_acl_setvsa
490  */
491 static int
492 smbfs_acl_store(vnode_t *vp, vsecattr_t *vsa, uid_t uid, gid_t gid,
493 	uint32_t selector, cred_t *cr)
494 {
495 	mbchain_t *mbp, mb_store;
496 	i_ntsd_t *sd;
497 	int error;
498 
499 	ASSERT(selector != 0);
500 
501 	sd = NULL;
502 	bzero(&mb_store, sizeof (mb_store));
503 	mbp = &mb_store;
504 
505 	/*
506 	 * Convert a ZFS ACL (and owner ID, group ID)
507 	 * into an NT SD, internal form.
508 	 */
509 	error = smbfs_acl_zfs2sd(vsa, uid, gid, selector, &sd);
510 	if (error)
511 		goto out;
512 
513 	/*
514 	 * Marshall the internal form SD into an
515 	 * OtW security descriptor.
516 	 */
517 	(void) mb_init(mbp);
518 	error = mb_put_ntsd(mbp, sd);
519 	if (error)
520 		goto out;
521 
522 	/*
523 	 * This does the OTW Set (and maybe open, close)
524 	 * It clears mb_top when consuming the message.
525 	 */
526 	error = smbfs_setsd(vp, selector, &mbp->mb_top, cr);
527 
528 out:
529 	if (sd != NULL)
530 		smbfs_acl_free_sd(sd);
531 	mb_done(mbp);
532 	return (error);
533 }
534 
535 /*
536  * Helper for smbfs_setattr()
537  *
538  * Set the passed UID/GID as indicated by va_mask.
539  */
540 int
541 smbfs_acl_setids(vnode_t *vp, vattr_t *vap, cred_t *cr)
542 {
543 	uid_t uid = (uid_t)-1;
544 	gid_t gid = (uid_t)-1;
545 	uint32_t selector = 0;
546 	int error;
547 
548 	if (vap->va_mask & AT_UID) {
549 		selector |= OWNER_SECURITY_INFORMATION;
550 		uid = vap->va_uid;
551 	}
552 
553 	if (vap->va_mask & AT_GID) {
554 		selector |= GROUP_SECURITY_INFORMATION;
555 		gid = vap->va_gid;
556 	}
557 
558 	if (selector == 0)
559 		return (0);
560 
561 	error = smbfs_acl_store(vp, NULL, uid, gid, selector, cr);
562 	return (error);
563 }
564 
565 /*
566  * Helper for VOP_SETSECATTR
567  * Convert ZFS to NT form, call smbfs_setsd.
568  */
569 /* ARGSUSED */
570 int
571 smbfs_acl_setvsa(vnode_t *vp, vsecattr_t *vsa,
572 	int flag, cred_t *cr)
573 {
574 	uint32_t selector = DACL_SECURITY_INFORMATION;
575 	smbnode_t *np = VTOSMB(vp);
576 	int error;
577 
578 	/*
579 	 * NB: extended attribute files and directories
580 	 * do not have ACLs separate from the parent.
581 	 */
582 	if (np->n_flag & N_XATTR)
583 		return (ENOSYS);
584 
585 	/*
586 	 * When handling ACE_OWNER or ACE_GROUP entries,
587 	 * we need the current owner and group.
588 	 */
589 	error = smbfs_acl_getids(vp, cr);
590 	if (error)
591 		return (error);
592 
593 	error = smbfs_acl_store(vp, vsa, np->n_uid, np->n_gid, selector, cr);
594 	return (error);
595 }
596