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
smbfs_acl_iocget(int fd,uint32_t selector,mbdata_t * mbp)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
smbfs_acl_iocset(int fd,uint32_t selector,mbdata_t * mbp)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
smbfs_acl_getsd(int fd,uint32_t selector,i_ntsd_t ** sdp)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
smbfs_acl_setsd(int fd,uint32_t selector,i_ntsd_t * sd)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
smbfs_acl_get(int fd,acl_t ** aclp,uid_t * uidp,gid_t * gidp)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
smbfs_acl_set(int fd,acl_t * acl,uid_t uid,gid_t gid)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