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 */
70static int
71smbfs_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
93again:
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
119out:
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 */
133static int
134smbfs_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
185out:
186	smb_credrele(&scred);
187
188	return (error);
189}
190
191/*
192 * Helper for VOP_IOCTL: SMBFSIO_GETSD
193 */
194int
195smbfs_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
245out:
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 */
255int
256smbfs_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
289out:
290	mb_done(mbp);
291	return (error);
292
293}
294
295/*
296 * Refresh our cached copy of the security attributes
297 */
298static int
299smbfs_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
376out:
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 */
391int
392smbfs_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 */
426int
427smbfs_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 */
479static int
480smbfs_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
516out:
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 */
528int
529smbfs_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 */
558int
559smbfs_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