xref: /illumos-gate/usr/src/lib/libsmbfs/smb/acl_api.c (revision 8459c777fc1aaabb2f7dad05de1313aa169417cd)
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 2017 Nexenta Systems, Inc.  All rights reserved.
27  */
28 
29 /*
30  * ACL API for smbfs
31  */
32 
33 #include <sys/types.h>
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 <errno.h>
45 #include <stdio.h>
46 #include <strings.h>
47 #include <unistd.h>
48 
49 #include <umem.h>
50 #include <idmap.h>
51 
52 #include <sys/fs/smbfs_ioctl.h>
53 
54 #include <netsmb/smb.h>
55 #include <netsmb/smb_lib.h>
56 #include <netsmb/smbfs_acl.h>
57 
58 #include "smbfs_ntacl.h"
59 #include "private.h"
60 
61 /* Sanity check SD sizes */
62 #define	MAX_RAW_SD_SIZE	32768
63 
64 /* XXX: acl_common.h */
65 acl_t *acl_alloc(enum acl_type);
66 void acl_free(acl_t *);
67 
68 
69 /*
70  * Get/set a Windows security descriptor (SD)
71  * using the (private) smbfs ioctl mechanism.
72  * Note: Get allocates mbp->mb_top
73  */
74 
75 /* ARGSUSED */
76 int
77 smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
78 {
79 	ioc_sdbuf_t	iocb;
80 	struct mbuf	*m;
81 	int		error;
82 
83 	error = mb_init_sz(mbp, MAX_RAW_SD_SIZE);
84 	if (error)
85 		return (error);
86 
87 	m = mbp->mb_top;
88 	bzero(&iocb, sizeof (iocb));
89 	iocb.addr = mtod(m, uintptr_t);
90 	iocb.alloc = m->m_maxlen;
91 	iocb.used = 0;
92 	iocb.selector = selector;
93 
94 	/*
95 	 * This does the OTW Get.
96 	 */
97 	if (nsmb_ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
98 		error = errno;
99 		goto errout;
100 	}
101 
102 	m->m_len = iocb.used;
103 	return (0);
104 
105 errout:
106 	mb_done(mbp);
107 	return (error);
108 }
109 
110 /* ARGSUSED */
111 int
112 smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
113 {
114 	ioc_sdbuf_t	iocb;
115 	struct mbuf	*m;
116 	int		error;
117 
118 	/* Make the data contiguous. */
119 	error = m_lineup(mbp->mb_top, &m);
120 	if (error)
121 		return (error);
122 
123 	if (mbp->mb_top != m)
124 		mb_initm(mbp, m);
125 
126 	bzero(&iocb, sizeof (iocb));
127 	iocb.addr = mtod(m, uintptr_t);
128 	iocb.alloc = m->m_maxlen;
129 	iocb.used  = m->m_len;
130 	iocb.selector = selector;
131 
132 	/*
133 	 * This does the OTW Set.
134 	 */
135 	if (nsmb_ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
136 		error = errno;
137 
138 	return (error);
139 }
140 
141 /*
142  * Get an NT SD from the open file via ioctl.
143  */
144 int
145 smbfs_acl_getsd(int fd, uint32_t selector, i_ntsd_t **sdp)
146 {
147 	mbdata_t *mbp, mb_store;
148 	int error;
149 
150 	mbp = &mb_store;
151 	bzero(mbp, sizeof (*mbp));
152 
153 	/*
154 	 * Get the raw Windows SD via ioctl.
155 	 * Returns allocated mbchain in mbp.
156 	 */
157 	error = smbfs_acl_iocget(fd, selector, mbp);
158 	if (error == 0) {
159 		/*
160 		 * Import the raw SD into "internal" form.
161 		 * (like "absolute" form per. NT docs)
162 		 * Returns allocated data in sdp
163 		 */
164 		error = md_get_ntsd(mbp, sdp);
165 	}
166 
167 	mb_done(mbp);
168 	return (error);
169 }
170 
171 /*
172  * Set an NT SD onto the open file via ioctl.
173  */
174 int
175 smbfs_acl_setsd(int fd, uint32_t selector, i_ntsd_t *sd)
176 {
177 	mbdata_t *mbp, mb_store;
178 	int error;
179 
180 	mbp = &mb_store;
181 	error = mb_init_sz(mbp, MAX_RAW_SD_SIZE);
182 	if (error)
183 		return (error);
184 
185 	/*
186 	 * Export the "internal" SD into an mb chain.
187 	 * (a.k.a "self-relative" form per. NT docs)
188 	 * Returns allocated mbchain in mbp.
189 	 */
190 	error = mb_put_ntsd(mbp, sd);
191 	if (error == 0) {
192 		/*
193 		 * Set the raw Windows SD via ioctl.
194 		 */
195 		error = smbfs_acl_iocset(fd, selector, mbp);
196 	}
197 
198 	mb_done(mbp);
199 
200 	return (error);
201 }
202 
203 
204 
205 /*
206  * Convenience function to Get security using a
207  * ZFS-style ACL (libsec acl, type=ACE_T)
208  * Intentionally similar to: facl_get(3SEC)
209  */
210 int
211 smbfs_acl_get(int fd, acl_t **aclp, uid_t *uidp, gid_t *gidp)
212 {
213 	i_ntsd_t *sd = NULL;
214 	acl_t *acl = NULL;
215 	uint32_t selector;
216 	int error;
217 
218 	/*
219 	 * Which parts of the SD are being requested?
220 	 * XXX: Should we request the SACL too?  If so,
221 	 * might that cause this access to be denied?
222 	 * Or maybe: if we get access denied, try the
223 	 * open/fetch again without the SACL bit.
224 	 */
225 	selector = 0;
226 	if (aclp)
227 		selector |= DACL_SECURITY_INFORMATION;
228 	if (uidp)
229 		selector |= OWNER_SECURITY_INFORMATION;
230 	if (gidp)
231 		selector |= GROUP_SECURITY_INFORMATION;
232 
233 	if (selector == 0)
234 		return (0);
235 
236 	/*
237 	 * Get the Windows SD via ioctl, in
238 	 * "internal" (absolute) form.
239 	 */
240 	error = smbfs_acl_getsd(fd, selector, &sd);
241 	if (error)
242 		return (error);
243 	/* Note: sd now holds allocated data. */
244 
245 	/*
246 	 * Convert the internal SD to a ZFS ACL.
247 	 * Get uid/gid too if pointers != NULL.
248 	 */
249 	if (aclp) {
250 		acl = acl_alloc(ACE_T);
251 		if (acl == NULL) {
252 			error = ENOMEM;
253 			goto out;
254 		}
255 	}
256 	error = smbfs_acl_sd2zfs(sd, acl, uidp, gidp);
257 	if (error)
258 		goto out;
259 
260 	/* Success! */
261 	if (aclp) {
262 		*aclp = acl;
263 		acl = NULL;
264 	}
265 
266 out:
267 	if (acl)
268 		acl_free(acl);
269 	smbfs_acl_free_sd(sd);
270 	return (error);
271 }
272 
273 /*
274  * Convenience function to Set security using a
275  * ZFS-style ACL (libsec acl, type=ACE_T)
276  * Intentionally similar to: facl_set(3SEC)
277  */
278 int
279 smbfs_acl_set(int fd, acl_t *acl, uid_t uid, gid_t gid)
280 {
281 	struct stat st;
282 	i_ntsd_t *sd = NULL;
283 	uint32_t selector;
284 	int error;
285 
286 	if (acl && acl->acl_type != ACE_T)
287 		return (EINVAL);
288 
289 	/*
290 	 * Which parts of the SD are being modified?
291 	 * XXX: Ditto comments above re. SACL.
292 	 */
293 	selector = 0;
294 	if (acl)
295 		selector |= DACL_SECURITY_INFORMATION;
296 	if (uid != (uid_t)-1)
297 		selector |= OWNER_SECURITY_INFORMATION;
298 	if (gid != (gid_t)-1)
299 		selector |= GROUP_SECURITY_INFORMATION;
300 	if (selector == 0)
301 		return (0);
302 
303 	if (uid == (uid_t)-1 || gid == (gid_t)-1) {
304 		/*
305 		 * If not setting owner or group, we need the
306 		 * current owner and group for translating
307 		 * references via owner@ or group@ ACEs.
308 		 */
309 		if (fstat(fd, &st) != 0)
310 			return (errno);
311 		if (uid == (uid_t)-1)
312 			uid = st.st_uid;
313 		if (gid == (gid_t)-1)
314 			gid = st.st_gid;
315 	}
316 
317 	/*
318 	 * Convert the ZFS ACL to an internal SD.
319 	 * Returns allocated data in sd
320 	 */
321 	error = smbfs_acl_zfs2sd(acl, uid, gid, selector, &sd);
322 	if (error == 0)
323 		error = smbfs_acl_setsd(fd, selector, sd);
324 
325 	smbfs_acl_free_sd(sd);
326 
327 	return (error);
328 }
329