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 support for smbfs
29 */
30
31 #include <sys/systm.h> /* bcopy, ... */
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 <netsmb/mchain.h>
43 #include <netsmb/smb.h>
44 #include <netsmb/smb_conn.h>
45 #include <netsmb/smb_osdep.h>
46 #include <netsmb/smb_subr.h>
47
48 #include <smbfs/smbfs.h>
49 #include <smbfs/smbfs_node.h>
50 #include <smbfs/smbfs_subr.h>
51
52 #include <sys/fs/smbfs_ioctl.h>
53 #include <fs/fs_subr.h>
54 #include "smbfs_ntacl.h"
55
56 /* Sanity check SD sizes */
57 #define MAX_RAW_SD_SIZE 32768
58 #define SMALL_SD_SIZE 1024
59
60 /*
61 * smbfs_getsd() is a common function used by both
62 * smbfs_ioctl SMBFSIO_GETSD and VOP_GETSECATTR.
63 * Handles required rights, tmpopen/tmpclose.
64 *
65 * Note: smbfs_getsd allocates and returns an mblk chain,
66 * which the caller must free.
67 */
68 static int
smbfs_getsd(vnode_t * vp,uint32_t selector,mblk_t ** mp,cred_t * cr)69 smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
70 {
71 struct smb_cred scred;
72 int error, cerror;
73 smbmntinfo_t *smi;
74 smbnode_t *np;
75 u_int16_t fid = SMB_FID_UNUSED;
76 uint32_t sdlen = SMALL_SD_SIZE;
77 uint32_t rights = STD_RIGHT_READ_CONTROL_ACCESS;
78
79 if (selector & SACL_SECURITY_INFORMATION)
80 rights |= SEC_RIGHT_SYSTEM_SECURITY;
81
82 np = VTOSMB(vp);
83 smi = VTOSMI(vp);
84
85 /* Shared lock for (possible) n_fid use. */
86 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
87 return (EINTR);
88 smb_credinit(&scred, cr);
89
90 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
91 if (error)
92 goto out;
93
94 again:
95 /*
96 * This does the OTW Get
97 */
98 error = smbfs_smb_getsec_m(smi->smi_share, fid,
99 &scred, selector, mp, &sdlen);
100 /*
101 * Server may give us an error indicating that we
102 * need a larger data buffer to receive the SD,
103 * and the size we'll need. Use the given size,
104 * but only after a sanity check.
105 *
106 * Let's check for specific error values here.
107 * The NT error is: STATUS_BUFFER_TOO_SMALL,
108 * or with old error codes, one of these:
109 * ERRSRV/ERRnoroom, ERRDOS/122, ERRDOS/111
110 * Those are mapped to: EMOREDATA, which is
111 * later converted to E2BIG.
112 */
113 if (error == E2BIG &&
114 sdlen > SMALL_SD_SIZE &&
115 sdlen <= MAX_RAW_SD_SIZE)
116 goto again;
117
118 cerror = smbfs_smb_tmpclose(np, fid, &scred);
119 if (cerror)
120 SMBVDEBUG("error %d closing file %s\n",
121 cerror, np->n_rpath);
122
123 out:
124 smb_credrele(&scred);
125 smbfs_rw_exit(&np->r_lkserlock);
126
127 return (error);
128 }
129
130 /*
131 * smbfs_setsd() is a common function used by both
132 * smbfs_ioctl SMBFSIO_SETSD and VOP_SETSECATTR.
133 * Handles required rights, tmpopen/tmpclose.
134 *
135 * Note: smbfs_setsd _consumes_ the passed *mp and
136 * clears the pointer (so the caller won't free it)
137 */
138 static int
smbfs_setsd(vnode_t * vp,uint32_t selector,mblk_t ** mp,cred_t * cr)139 smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
140 {
141 struct smb_cred scred;
142 int error, cerror;
143 smbmntinfo_t *smi;
144 smbnode_t *np;
145 uint32_t rights;
146 u_int16_t fid = SMB_FID_UNUSED;
147
148 np = VTOSMB(vp);
149 smi = VTOSMI(vp);
150
151 /*
152 * Which parts of the SD are we setting?
153 * What rights do we need for that?
154 */
155 if (selector == 0)
156 return (0);
157
158 rights = 0;
159 if (selector & (OWNER_SECURITY_INFORMATION |
160 GROUP_SECURITY_INFORMATION))
161 rights |= STD_RIGHT_WRITE_OWNER_ACCESS;
162 if (selector & DACL_SECURITY_INFORMATION)
163 rights |= STD_RIGHT_WRITE_DAC_ACCESS;
164 if (selector & SACL_SECURITY_INFORMATION)
165 rights |= SEC_RIGHT_SYSTEM_SECURITY;
166
167 /* Shared lock for (possible) n_fid use. */
168 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
169 return (EINTR);
170 smb_credinit(&scred, cr);
171
172 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
173 if (error)
174 goto out;
175
176 /*
177 * We're setting the remote ACL now, so
178 * invalidate our cached ACL just in case
179 * the server doesn't do exactly as we ask.
180 */
181 mutex_enter(&np->r_statelock);
182 np->r_sectime = gethrtime();
183 mutex_exit(&np->r_statelock);
184
185 /*
186 * This does the OTW Set
187 */
188 error = smbfs_smb_setsec_m(smi->smi_share, fid,
189 &scred, selector, mp);
190
191 cerror = smbfs_smb_tmpclose(np, fid, &scred);
192 if (cerror)
193 SMBVDEBUG("error %d closing file %s\n",
194 cerror, np->n_rpath);
195
196 out:
197 smb_credrele(&scred);
198 smbfs_rw_exit(&np->r_lkserlock);
199
200 return (error);
201 }
202
203 /*
204 * Helper for VOP_IOCTL: SMBFSIO_GETSD
205 */
206 int
smbfs_acl_iocget(vnode_t * vp,intptr_t arg,int flag,cred_t * cr)207 smbfs_acl_iocget(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
208 {
209 ioc_sdbuf_t iocb;
210 mdchain_t *mdp, md_store;
211 mblk_t *m;
212 void *ubuf;
213 int error;
214
215 /*
216 * Get the buffer information
217 */
218 if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
219 return (EFAULT);
220
221 /*
222 * This does the OTW Get (and maybe open, close)
223 * Allocates and returns an mblk in &m.
224 */
225 error = smbfs_getsd(vp, iocb.selector, &m, cr);
226 if (error)
227 return (error);
228
229 /*
230 * Have m. Must free it before return.
231 */
232 mdp = &md_store;
233 md_initm(mdp, m);
234 iocb.used = m_fixhdr(m);
235
236 /*
237 * Always copyout the buffer information,
238 * so the user can realloc and try again
239 * after an EOVERFLOW return.
240 */
241 if (ddi_copyout(&iocb, (void *)arg, sizeof (iocb), flag)) {
242 error = EFAULT;
243 goto out;
244 }
245
246 if (iocb.used > iocb.alloc) {
247 error = EOVERFLOW;
248 goto out;
249 }
250
251 /*
252 * Copyout the buffer contents (SD)
253 */
254 ubuf = (void *)(uintptr_t)iocb.addr;
255 error = md_get_mem(mdp, ubuf, iocb.used, MB_MUSER);
256
257 out:
258 /* Note: m_freem(m) is done by... */
259 md_done(mdp);
260
261 return (error);
262 }
263
264 /*
265 * Helper for VOP_IOCTL: SMBFSIO_SETSD
266 */
267 int
smbfs_acl_iocset(vnode_t * vp,intptr_t arg,int flag,cred_t * cr)268 smbfs_acl_iocset(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
269 {
270 ioc_sdbuf_t iocb;
271 mbchain_t *mbp, mb_store;
272 void *ubuf;
273 int error;
274
275 /*
276 * Get the buffer information
277 */
278 if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
279 return (EFAULT);
280
281 if (iocb.used < sizeof (ntsecdesc_t) ||
282 iocb.used >= MAX_RAW_SD_SIZE)
283 return (EINVAL);
284
285 /*
286 * Get the buffer contents (security descriptor data)
287 */
288 mbp = &mb_store;
289 (void) mb_init(mbp);
290 ubuf = (void *)(uintptr_t)iocb.addr;
291 error = mb_put_mem(mbp, ubuf, iocb.used, MB_MUSER);
292 if (error)
293 goto out;
294
295 /*
296 * This does the OTW Set (and maybe open, close)
297 * It clears mb_top when consuming the message.
298 */
299 error = smbfs_setsd(vp, iocb.selector, &mbp->mb_top, cr);
300
301 out:
302 mb_done(mbp);
303 return (error);
304
305 }
306
307 /*
308 * Refresh our cached copy of the security attributes
309 */
310 static int
smbfs_acl_refresh(vnode_t * vp,cred_t * cr)311 smbfs_acl_refresh(vnode_t *vp, cred_t *cr)
312 {
313 smbnode_t *np;
314 smbmntinfo_t *smi;
315 mdchain_t *mdp, md_store;
316 mblk_t *m = NULL;
317 i_ntsd_t *sd = NULL;
318 vsecattr_t vsa, ovsa;
319 uint32_t selector;
320 uid_t uid;
321 gid_t gid;
322 int error;
323
324 np = VTOSMB(vp);
325 smi = VTOSMI(vp);
326
327 bzero(&md_store, sizeof (md_store));
328 mdp = &md_store;
329
330 /*
331 * Which parts of the SD we request.
332 * Not getting the SACL for now.
333 */
334 selector = DACL_SECURITY_INFORMATION |
335 OWNER_SECURITY_INFORMATION |
336 GROUP_SECURITY_INFORMATION;
337
338 /*
339 * This does the OTW Get (and maybe open, close)
340 * Allocates and returns an mblk in &m.
341 */
342 error = smbfs_getsd(vp, selector, &m, cr);
343 if (error)
344 goto out;
345 /* Note: allocated *m */
346 md_initm(mdp, m);
347
348 /*
349 * Parse the OtW security descriptor,
350 * storing in our internal form.
351 */
352 error = md_get_ntsd(mdp, &sd);
353 if (error)
354 goto out;
355
356 /*
357 * Convert the Windows security descriptor to a
358 * ZFS ACL (and owner ID, primary group ID).
359 */
360 bzero(&vsa, sizeof (vsa));
361 vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
362 error = smbfs_acl_sd2zfs(sd, &vsa, &uid, &gid);
363 if (error)
364 goto out;
365
366 ASSERT(vsa.vsa_aclentp != NULL);
367 SMBVDEBUG("uid=%u, gid=%u", uid, gid);
368
369 /*
370 * Store the results in r_secattr, n_uid, n_gid
371 */
372 mutex_enter(&np->r_statelock);
373 ovsa = np->r_secattr;
374 np->r_secattr = vsa;
375 np->n_uid = uid;
376 np->n_gid = gid;
377 /*
378 * ACLs don't change frequently, so cache these
379 * for a relatively long time (ac dir max).
380 */
381 np->r_sectime = gethrtime() + smi->smi_acdirmax;
382 mutex_exit(&np->r_statelock);
383
384 /* Allocated in: smbfs_acl_sd2zfs */
385 if (ovsa.vsa_aclentp != NULL)
386 kmem_free(ovsa.vsa_aclentp, ovsa.vsa_aclentsz);
387
388 out:
389 if (sd != NULL)
390 smbfs_acl_free_sd(sd);
391 /* Note: m_freem(m) is done by... */
392 md_done(mdp);
393
394 return (error);
395 }
396
397 /*
398 * Helper for smbfsgetattr()
399 *
400 * Just refresh the ACL cache if needed,
401 * which updates n_uid/n_gid
402 */
403 int
smbfs_acl_getids(vnode_t * vp,cred_t * cr)404 smbfs_acl_getids(vnode_t *vp, cred_t *cr)
405 {
406 smbnode_t *np;
407 int error;
408
409 np = VTOSMB(vp);
410
411 /*
412 * NB: extended attribute files and directories
413 * do not have ACLs separate from the parent.
414 * Let the caller do ACL fabrication.
415 */
416 if (np->n_flag & N_XATTR)
417 return (ENOSYS);
418
419 mutex_enter(&np->r_statelock);
420 if (gethrtime() >= np->r_sectime) {
421 /* Need to update r_secattr */
422 mutex_exit(&np->r_statelock);
423 error = smbfs_acl_refresh(vp, cr);
424 return (error);
425 }
426 mutex_exit(&np->r_statelock);
427
428 return (0);
429 }
430
431 /*
432 * Helper for VOP_GETSECATTR
433 *
434 * Refresh the ACL cache if needed, then
435 * duplicate the requested parts of the vsecattr.
436 */
437 /* ARGSUSED */
438 int
smbfs_acl_getvsa(vnode_t * vp,vsecattr_t * vsa,int flag,cred_t * cr)439 smbfs_acl_getvsa(vnode_t *vp, vsecattr_t *vsa,
440 int flag, cred_t *cr)
441 {
442 smbnode_t *np;
443 int error;
444
445 np = VTOSMB(vp);
446
447 /*
448 * NB: extended attribute files and directories
449 * do not have ACLs separate from the parent.
450 * Let the caller do ACL fabrication.
451 */
452 if (np->n_flag & N_XATTR)
453 return (ENOSYS);
454
455 mutex_enter(&np->r_statelock);
456
457 if (np->r_secattr.vsa_aclentp == NULL ||
458 gethrtime() >= np->r_sectime) {
459 /* Need to update r_secattr */
460 mutex_exit(&np->r_statelock);
461
462 error = smbfs_acl_refresh(vp, cr);
463 if (error)
464 return (error);
465
466 mutex_enter(&np->r_statelock);
467 }
468 ASSERT(np->r_secattr.vsa_aclentp != NULL);
469
470 /*
471 * Duplicate requested parts of r_secattr
472 */
473
474 if (vsa->vsa_mask & VSA_ACECNT)
475 vsa->vsa_aclcnt = np->r_secattr.vsa_aclcnt;
476
477 if (vsa->vsa_mask & VSA_ACE) {
478 vsa->vsa_aclentsz = np->r_secattr.vsa_aclentsz;
479 vsa->vsa_aclentp = kmem_alloc(vsa->vsa_aclentsz, KM_SLEEP);
480 bcopy(np->r_secattr.vsa_aclentp, vsa->vsa_aclentp,
481 vsa->vsa_aclentsz);
482 }
483
484 mutex_exit(&np->r_statelock);
485 return (0);
486 }
487
488 /*
489 * Helper for smbfs_acl_setids, smbfs_acl_setvsa
490 */
491 static int
smbfs_acl_store(vnode_t * vp,vsecattr_t * vsa,uid_t uid,gid_t gid,uint32_t selector,cred_t * cr)492 smbfs_acl_store(vnode_t *vp, vsecattr_t *vsa, uid_t uid, gid_t gid,
493 uint32_t selector, cred_t *cr)
494 {
495 mbchain_t *mbp, mb_store;
496 i_ntsd_t *sd;
497 int error;
498
499 ASSERT(selector != 0);
500
501 sd = NULL;
502 bzero(&mb_store, sizeof (mb_store));
503 mbp = &mb_store;
504
505 /*
506 * Convert a ZFS ACL (and owner ID, group ID)
507 * into an NT SD, internal form.
508 */
509 error = smbfs_acl_zfs2sd(vsa, uid, gid, selector, &sd);
510 if (error)
511 goto out;
512
513 /*
514 * Marshall the internal form SD into an
515 * OtW security descriptor.
516 */
517 (void) mb_init(mbp);
518 error = mb_put_ntsd(mbp, sd);
519 if (error)
520 goto out;
521
522 /*
523 * This does the OTW Set (and maybe open, close)
524 * It clears mb_top when consuming the message.
525 */
526 error = smbfs_setsd(vp, selector, &mbp->mb_top, cr);
527
528 out:
529 if (sd != NULL)
530 smbfs_acl_free_sd(sd);
531 mb_done(mbp);
532 return (error);
533 }
534
535 /*
536 * Helper for smbfs_setattr()
537 *
538 * Set the passed UID/GID as indicated by va_mask.
539 */
540 int
smbfs_acl_setids(vnode_t * vp,vattr_t * vap,cred_t * cr)541 smbfs_acl_setids(vnode_t *vp, vattr_t *vap, cred_t *cr)
542 {
543 uid_t uid = (uid_t)-1;
544 gid_t gid = (uid_t)-1;
545 uint32_t selector = 0;
546 int error;
547
548 if (vap->va_mask & AT_UID) {
549 selector |= OWNER_SECURITY_INFORMATION;
550 uid = vap->va_uid;
551 }
552
553 if (vap->va_mask & AT_GID) {
554 selector |= GROUP_SECURITY_INFORMATION;
555 gid = vap->va_gid;
556 }
557
558 if (selector == 0)
559 return (0);
560
561 error = smbfs_acl_store(vp, NULL, uid, gid, selector, cr);
562 return (error);
563 }
564
565 /*
566 * Helper for VOP_SETSECATTR
567 * Convert ZFS to NT form, call smbfs_setsd.
568 */
569 /* ARGSUSED */
570 int
smbfs_acl_setvsa(vnode_t * vp,vsecattr_t * vsa,int flag,cred_t * cr)571 smbfs_acl_setvsa(vnode_t *vp, vsecattr_t *vsa,
572 int flag, cred_t *cr)
573 {
574 uint32_t selector = DACL_SECURITY_INFORMATION;
575 smbnode_t *np = VTOSMB(vp);
576 int error;
577
578 /*
579 * NB: extended attribute files and directories
580 * do not have ACLs separate from the parent.
581 */
582 if (np->n_flag & N_XATTR)
583 return (ENOSYS);
584
585 /*
586 * When handling ACE_OWNER or ACE_GROUP entries,
587 * we need the current owner and group.
588 */
589 error = smbfs_acl_getids(vp, cr);
590 if (error)
591 return (error);
592
593 error = smbfs_acl_store(vp, vsa, np->n_uid, np->n_gid, selector, cr);
594 return (error);
595 }
596