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