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