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
  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
 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
 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
 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
 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
 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
 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
 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
 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
 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 }