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