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 2009 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/smb_osdep.h> 43 #include <netsmb/smb.h> 44 #include <netsmb/smb_conn.h> 45 #include <netsmb/smb_subr.h> 46 #include <netsmb/mchain.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 55 /* Sanity check SD sizes */ 56 #define MAX_RAW_SD_SIZE 32768 57 #define SMALL_SD_SIZE 1024 58 59 #undef ACL_SUPPORT /* not yet */ 60 61 62 /* 63 * smbfs_getsd(), smbfs_setsd() are common functions used by 64 * both ioctl get/set ACL and VOP_GETSECATTR, VOP_SETSECATTR. 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 int 71 smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) 72 { 73 struct smb_cred scred; 74 int error, cerror; 75 smbmntinfo_t *smi; 76 smbnode_t *np; 77 u_int16_t fid = SMB_FID_UNUSED; 78 uint32_t sdlen = SMALL_SD_SIZE; 79 uint32_t rights = STD_RIGHT_READ_CONTROL_ACCESS; 80 81 if (selector & SACL_SECURITY_INFORMATION) 82 rights |= SEC_RIGHT_SYSTEM_SECURITY; 83 84 np = VTOSMB(vp); 85 smi = VTOSMI(vp); 86 87 /* Shared lock for (possible) n_fid use. */ 88 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 89 return (EINTR); 90 smb_credinit(&scred, cr); 91 92 error = smbfs_smb_tmpopen(np, rights, &scred, &fid); 93 if (error) 94 goto out; 95 96 again: 97 /* 98 * This does the OTW Get 99 */ 100 error = smbfs_smb_getsec_m(smi->smi_share, fid, 101 &scred, selector, mp, &sdlen); 102 /* 103 * Server may give us an error indicating that we 104 * need a larger data buffer to receive the SD, 105 * and the size we'll need. Use the given size, 106 * but only after a sanity check. 107 * 108 * Let's check for specific error values here. 109 * The NT error is: STATUS_BUFFER_TOO_SMALL, 110 * or with old error codes, one of these: 111 * ERRSRV/ERRnoroom, ERRDOS/122, ERRDOS/111 112 * Those are mapped to: EMOREDATA, which is 113 * later converted to E2BIG. 114 */ 115 if (error == E2BIG && 116 sdlen > SMALL_SD_SIZE && 117 sdlen <= MAX_RAW_SD_SIZE) 118 goto again; 119 120 cerror = smbfs_smb_tmpclose(np, fid, &scred); 121 if (cerror) 122 SMBERROR("error %d closing file %s\n", 123 cerror, np->n_rpath); 124 125 out: 126 smb_credrele(&scred); 127 smbfs_rw_exit(&np->r_lkserlock); 128 129 return (error); 130 } 131 132 int 133 smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) 134 { 135 struct smb_cred scred; 136 int error, cerror; 137 smbmntinfo_t *smi; 138 smbnode_t *np; 139 uint32_t rights; 140 u_int16_t fid = SMB_FID_UNUSED; 141 142 np = VTOSMB(vp); 143 smi = VTOSMI(vp); 144 145 /* 146 * Which parts of the SD are we setting? 147 * What rights do we need for that? 148 */ 149 if (selector == 0) 150 return (0); 151 rights = 0; 152 if (selector & (OWNER_SECURITY_INFORMATION | 153 GROUP_SECURITY_INFORMATION)) 154 rights |= STD_RIGHT_WRITE_OWNER_ACCESS; 155 if (selector & DACL_SECURITY_INFORMATION) 156 rights |= STD_RIGHT_WRITE_DAC_ACCESS; 157 if (selector & SACL_SECURITY_INFORMATION) 158 rights |= SEC_RIGHT_SYSTEM_SECURITY; 159 160 /* Shared lock for (possible) n_fid use. */ 161 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 162 return (EINTR); 163 smb_credinit(&scred, cr); 164 165 error = smbfs_smb_tmpopen(np, rights, &scred, &fid); 166 if (error) 167 goto out; 168 169 /* 170 * This does the OTW Set 171 */ 172 error = smbfs_smb_setsec_m(smi->smi_share, fid, 173 &scred, selector, mp); 174 175 cerror = smbfs_smb_tmpclose(np, fid, &scred); 176 if (cerror) 177 SMBERROR("error %d closing file %s\n", 178 cerror, np->n_rpath); 179 180 out: 181 smb_credrele(&scred); 182 smbfs_rw_exit(&np->r_lkserlock); 183 184 return (error); 185 } 186 187 /* 188 * Entry points from VOP_IOCTL 189 */ 190 int 191 smbfs_ioc_getsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) 192 { 193 ioc_sdbuf_t iocb; 194 mdchain_t *mdp, md_store; 195 mblk_t *m; 196 void *ubuf; 197 int error; 198 199 /* 200 * Get the buffer information 201 */ 202 if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag)) 203 return (EFAULT); 204 205 /* 206 * This does the OTW Get (and maybe open, close) 207 * Allocates and returns an mblk in &m. 208 */ 209 error = smbfs_getsd(vp, iocb.selector, &m, cr); 210 if (error) 211 return (error); 212 213 /* 214 * Have m. Must free it before return. 215 */ 216 mdp = &md_store; 217 md_initm(mdp, m); 218 iocb.used = m_fixhdr(m); 219 220 /* 221 * Always copyout the buffer information, 222 * so the user can realloc and try again 223 * after an EOVERFLOW return. 224 */ 225 if (ddi_copyout(&iocb, (void *)arg, sizeof (iocb), flag)) { 226 error = EFAULT; 227 goto out; 228 } 229 230 if (iocb.used > iocb.alloc) { 231 error = EOVERFLOW; 232 goto out; 233 } 234 235 /* 236 * Copyout the buffer contents (SD) 237 */ 238 ubuf = (void *)(uintptr_t)iocb.addr; 239 error = md_get_mem(mdp, ubuf, iocb.used, MB_MUSER); 240 241 out: 242 /* Note: m_freem(m) is done by... */ 243 md_done(mdp); 244 245 return (error); 246 } 247 248 int 249 smbfs_ioc_setsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) 250 { 251 ioc_sdbuf_t iocb; 252 mbchain_t *mbp, mb_store; 253 void *ubuf; 254 int error; 255 256 /* 257 * Get the buffer information 258 */ 259 if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag)) 260 return (EFAULT); 261 262 if (iocb.used < sizeof (ntsecdesc_t) || 263 iocb.used >= MAX_RAW_SD_SIZE) 264 return (EINVAL); 265 266 /* 267 * Get the buffer contents (security descriptor data) 268 */ 269 mbp = &mb_store; 270 mb_init(mbp); 271 ubuf = (void *)(uintptr_t)iocb.addr; 272 error = mb_put_mem(mbp, ubuf, iocb.used, MB_MUSER); 273 if (error) 274 goto out; 275 276 /* 277 * This does the OTW Set (and maybe open, close) 278 * It clears mb_top when consuming the message. 279 */ 280 error = smbfs_setsd(vp, iocb.selector, &mbp->mb_top, cr); 281 282 out: 283 mb_done(mbp); 284 return (error); 285 286 } 287 288 #ifdef ACL_SUPPORT 289 /* 290 * Conversion functions for VOP_GETSECATTR, VOP_SETSECATTR 291 * 292 * XXX: We may or may not add conversion code here, or we 293 * may add that to usr/src/common (TBD). For now all the 294 * ACL conversion code is in libsmbfs. 295 */ 296 297 /* 298 * Convert a Windows SD (in the mdchain mdp) into a 299 * ZFS-style vsecattr_t and possibly uid, gid. 300 */ 301 /* ARGSUSED */ 302 static int 303 smb_ntsd2vsec(mdchain_t *mdp, vsecattr_t *vsa, 304 int *uidp, int *gidp, cred_t *cr) 305 { 306 /* XXX NOT_YET */ 307 return (ENOSYS); 308 } 309 310 /* 311 * Convert a ZFS-style vsecattr_t (and possibly uid, gid) 312 * into a Windows SD (built in the mbchain mbp). 313 */ 314 /* ARGSUSED */ 315 static int 316 smb_vsec2ntsd(vsecattr_t *vsa, int uid, int gid, 317 mbchain_t *mbp, cred_t *cr) 318 { 319 /* XXX NOT_YET */ 320 return (ENOSYS); 321 } 322 #endif /* ACL_SUPPORT */ 323 324 /* 325 * Entry points from VOP_GETSECATTR, VOP_SETSECATTR 326 * 327 * Disabled the real _getacl functionality for now, 328 * because we have no way to return the owner and 329 * primary group until we replace our fake uid/gid 330 * in getattr with something derived from _getsd. 331 */ 332 333 /* ARGSUSED */ 334 int 335 smbfs_getacl(vnode_t *vp, vsecattr_t *vsa, 336 int *uidp, int *gidp, int flag, cred_t *cr) 337 { 338 #ifdef ACL_SUPPORT 339 mdchain_t *mdp, md_store; 340 mblk_t *m; 341 uint32_t selector; 342 int error; 343 344 /* 345 * Which parts of the SD we request. 346 * XXX: We need a way to let the caller specify 347 * what parts she wants - i.e. the SACL? 348 * XXX: selector |= SACL_SECURITY_INFORMATION; 349 * Or maybe: if we get access denied, try the 350 * open/fetch again without the SACL bit. 351 */ 352 selector = 0; 353 if (vsa) 354 selector |= DACL_SECURITY_INFORMATION; 355 if (uidp) 356 selector |= OWNER_SECURITY_INFORMATION; 357 if (gidp) 358 selector |= GROUP_SECURITY_INFORMATION; 359 if (selector == 0) 360 return (0); 361 362 /* 363 * This does the OTW Get (and maybe open, close) 364 * Allocates and returns an mblk in &m. 365 */ 366 error = smbfs_getsd(vp, selector, &m, cr); 367 if (error) 368 return (error); 369 370 /* 371 * Have m. Must free it before return. 372 */ 373 mdp = &md_store; 374 md_initm(mdp, m); 375 376 /* 377 * Convert the Windows security descriptor to a 378 * ZFS ACL (and owner ID, primary group ID). 379 * This is the difficult part. (todo) 380 */ 381 error = smb_ntsd2vsec(mdp, vsa, uidp, gidp, cr); 382 383 /* Note: m_freem(m) is done by... */ 384 md_done(mdp); 385 386 return (error); 387 #else /* ACL_SUPPORT */ 388 return (ENOSYS); 389 #endif /* ACL_SUPPORT */ 390 } 391 392 393 /* ARGSUSED */ 394 int 395 smbfs_setacl(vnode_t *vp, vsecattr_t *vsa, 396 int uid, int gid, int flag, cred_t *cr) 397 { 398 #ifdef ACL_SUPPORT 399 mbchain_t *mbp, mb_store; 400 uint32_t selector; 401 int error; 402 403 /* 404 * Which parts of the SD we'll modify. 405 * Ditto comments above re. SACL 406 */ 407 selector = 0; 408 if (vsa) 409 selector |= DACL_SECURITY_INFORMATION; 410 if (uid != -1) 411 selector |= OWNER_SECURITY_INFORMATION; 412 if (gid != -1) 413 selector |= GROUP_SECURITY_INFORMATION; 414 if (selector == 0) 415 return (0); 416 417 /* 418 * Setup buffer for SD data. 419 */ 420 mbp = &mb_store; 421 mb_init(mbp); 422 423 /* 424 * Convert a ZFS ACL (and owner ID, group ID) 425 * to a Windows security descriptor. 426 * This is the difficult part. (todo) 427 */ 428 error = smb_vsec2ntsd(vsa, uid, gid, mbp, cr); 429 if (error) 430 goto out; 431 432 /* 433 * This does the OTW Set (and maybe open, close) 434 * It clears mb_top when consuming the message. 435 */ 436 error = smbfs_setsd(vp, selector, &mbp->mb_top, cr); 437 438 out: 439 mb_done(mbp); 440 return (error); 441 #else /* ACL_SUPPORT */ 442 return (ENOSYS); 443 #endif /* ACL_SUPPORT */ 444 } 445