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 */
70 static int
smbfs_getsd(vnode_t * vp,uint32_t selector,mblk_t ** mp,cred_t * cr)71 smbfs_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
93 again:
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
119 out:
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 */
133 static int
smbfs_setsd(vnode_t * vp,uint32_t selector,mblk_t ** mp,cred_t * cr)134 smbfs_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
185 out:
186 smb_credrele(&scred);
187
188 return (error);
189 }
190
191 /*
192 * Helper for VOP_IOCTL: SMBFSIO_GETSD
193 */
194 int
smbfs_acl_iocget(vnode_t * vp,intptr_t arg,int flag,cred_t * cr)195 smbfs_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
245 out:
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 */
255 int
smbfs_acl_iocset(vnode_t * vp,intptr_t arg,int flag,cred_t * cr)256 smbfs_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
289 out:
290 mb_done(mbp);
291 return (error);
292
293 }
294
295 /*
296 * Refresh our cached copy of the security attributes
297 */
298 static int
smbfs_acl_refresh(vnode_t * vp,cred_t * cr)299 smbfs_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
376 out:
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 */
391 int
smbfs_acl_getids(vnode_t * vp,cred_t * cr)392 smbfs_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 */
426 int
smbfs_acl_getvsa(vnode_t * vp,vsecattr_t * vsa,int flag,cred_t * cr)427 smbfs_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 */
479 static int
smbfs_acl_store(vnode_t * vp,vsecattr_t * vsa,uid_t uid,gid_t gid,uint32_t selector,cred_t * cr)480 smbfs_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
516 out:
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 */
528 int
smbfs_acl_setids(vnode_t * vp,vattr_t * vap,cred_t * cr)529 smbfs_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 */
558 int
smbfs_acl_setvsa(vnode_t * vp,vsecattr_t * vsa,int flag,cred_t * cr)559 smbfs_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