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