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