15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 228670SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <sys/sid.h> 275772Sas200622 #include <sys/nbmlock.h> 285331Samw #include <smbsrv/smb_fsops.h> 295521Sas200622 #include <smbsrv/smb_kproto.h> 305521Sas200622 #include <smbsrv/ntstatus.h> 315521Sas200622 #include <smbsrv/ntaccess.h> 325772Sas200622 #include <smbsrv/smb_incl.h> 335331Samw #include <acl/acl_common.h> 345772Sas200622 #include <sys/fcntl.h> 355772Sas200622 #include <sys/flock.h> 365772Sas200622 #include <fs/fs_subr.h> 375331Samw 386139Sjb150015 extern caller_context_t smb_ct; 396139Sjb150015 406600Sas200622 extern int smb_fem_oplock_install(smb_node_t *); 416600Sas200622 extern void smb_fem_oplock_uninstall(smb_node_t *); 426600Sas200622 436600Sas200622 extern int smb_vop_other_opens(vnode_t *, int); 446600Sas200622 455331Samw static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, 465331Samw smb_fssd_t *fs_sd); 475331Samw 485331Samw /* 495331Samw * The smb_fsop_* functions have knowledge of CIFS semantics. 505331Samw * 515331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 525331Samw * serve as an interface to the VFS layer. 535331Samw * 545331Samw * Hence, smb_request_t and smb_node_t structures should not be passed 555331Samw * from the smb_fsop_* layer to the smb_vop_* layer. 565331Samw * 575331Samw * In general, CIFS service code should only ever call smb_fsop_* 585331Samw * functions directly, and never smb_vop_* functions directly. 595331Samw * 605331Samw * smb_fsop_* functions should call smb_vop_* functions where possible, instead 615331Samw * of their smb_fsop_* counterparts. However, there are times when 625331Samw * this cannot be avoided. 635331Samw */ 645331Samw 655331Samw /* 665331Samw * Note: Stream names cannot be mangled. 675331Samw */ 685331Samw 696600Sas200622 /* 706600Sas200622 * smb_fsop_amask_to_omode 716600Sas200622 * 726600Sas200622 * Convert the access mask to the open mode (for use 736600Sas200622 * with the VOP_OPEN call). 746600Sas200622 * 756600Sas200622 * Note that opening a file for attribute only access 766600Sas200622 * will also translate into an FREAD or FWRITE open mode 776600Sas200622 * (i.e., it's not just for data). 786600Sas200622 * 796600Sas200622 * This is needed so that opens are tracked appropriately 806600Sas200622 * for oplock processing. 816600Sas200622 */ 826600Sas200622 835331Samw int 846600Sas200622 smb_fsop_amask_to_omode(uint32_t access) 855331Samw { 866600Sas200622 int mode = 0; 876600Sas200622 886600Sas200622 if (access & (FILE_READ_DATA | FILE_EXECUTE | 896600Sas200622 FILE_READ_ATTRIBUTES | FILE_READ_EA)) 906600Sas200622 mode |= FREAD; 916600Sas200622 926600Sas200622 if (access & (FILE_WRITE_DATA | FILE_APPEND_DATA | 936600Sas200622 FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)) 946600Sas200622 mode |= FWRITE; 956600Sas200622 966600Sas200622 if (access & FILE_APPEND_DATA) 976600Sas200622 mode |= FAPPEND; 986600Sas200622 996600Sas200622 return (mode); 1005331Samw } 1015331Samw 1025331Samw int 1036600Sas200622 smb_fsop_open(smb_node_t *node, int mode, cred_t *cred) 1045331Samw { 1056600Sas200622 /* 1066600Sas200622 * Assuming that the same vnode is returned as we had before. 1076600Sas200622 * (I.e., with certain types of files or file systems, a 1086600Sas200622 * different vnode might be returned by VOP_OPEN) 1096600Sas200622 */ 1106600Sas200622 return (smb_vop_open(&node->vp, mode, cred)); 1115331Samw } 1125331Samw 1137348SJose.Borrego@Sun.COM void 1146600Sas200622 smb_fsop_close(smb_node_t *node, int mode, cred_t *cred) 1156600Sas200622 { 1167348SJose.Borrego@Sun.COM smb_vop_close(node->vp, mode, cred); 1176600Sas200622 } 1186600Sas200622 1196600Sas200622 int 1206600Sas200622 smb_fsop_oplock_install(smb_node_t *node, int mode) 1215331Samw { 1226600Sas200622 int rc; 1236600Sas200622 1246600Sas200622 if (smb_vop_other_opens(node->vp, mode)) 1256600Sas200622 return (EMFILE); 1266600Sas200622 1276600Sas200622 if ((rc = smb_fem_oplock_install(node))) 1286600Sas200622 return (rc); 1296600Sas200622 1306600Sas200622 if (smb_vop_other_opens(node->vp, mode)) { 1316600Sas200622 (void) smb_fem_oplock_uninstall(node); 1326600Sas200622 return (EMFILE); 1336600Sas200622 } 1346600Sas200622 1356600Sas200622 return (0); 1366600Sas200622 } 1376600Sas200622 1386600Sas200622 void 1396600Sas200622 smb_fsop_oplock_uninstall(smb_node_t *node) 1406600Sas200622 { 1416600Sas200622 smb_fem_oplock_uninstall(node); 1425331Samw } 1435331Samw 1445331Samw static int 1455331Samw smb_fsop_create_with_sd( 1466139Sjb150015 smb_request_t *sr, 1475331Samw cred_t *cr, 1487619SJose.Borrego@Sun.COM smb_node_t *dir_snode, 1495331Samw char *name, 1505331Samw smb_attr_t *attr, 1515331Samw smb_node_t **ret_snode, 1525331Samw smb_attr_t *ret_attr, 1535331Samw smb_fssd_t *fs_sd) 1545331Samw { 1555331Samw vsecattr_t *vsap; 1565331Samw vsecattr_t vsecattr; 1575331Samw acl_t *acl, *dacl, *sacl; 1585331Samw smb_attr_t set_attr; 1595331Samw vnode_t *vp; 1605331Samw int aclbsize = 0; /* size of acl list in bytes */ 1615331Samw int flags = 0; 1625331Samw int rc; 1637619SJose.Borrego@Sun.COM boolean_t is_dir; 1645331Samw 1655331Samw ASSERT(fs_sd); 1665331Samw 1677348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 1685331Samw flags = SMB_IGNORE_CASE; 169*9231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 170*9231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 1715331Samw 1725331Samw ASSERT(cr); 1735331Samw 1745331Samw is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0); 1755331Samw 1767348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACLONCREATE)) { 1775331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 1785331Samw dacl = fs_sd->sd_zdacl; 1795331Samw sacl = fs_sd->sd_zsacl; 1805331Samw ASSERT(dacl || sacl); 1815331Samw if (dacl && sacl) { 1825521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 1835331Samw } else if (dacl) { 1845331Samw acl = dacl; 1855331Samw } else { 1865331Samw acl = sacl; 1875331Samw } 1885331Samw 1895521Sas200622 rc = smb_fsacl_to_vsa(acl, &vsecattr, &aclbsize); 1905331Samw 1915331Samw if (dacl && sacl) 1925331Samw acl_free(acl); 1935331Samw 1947619SJose.Borrego@Sun.COM if (rc != 0) 1955331Samw return (rc); 1965331Samw 1975331Samw vsap = &vsecattr; 1987619SJose.Borrego@Sun.COM } else { 1997619SJose.Borrego@Sun.COM vsap = NULL; 2005331Samw } 2015331Samw 2028845Samw@Sun.COM /* The tree ACEs may prevent a create */ 2038845Samw@Sun.COM rc = EACCES; 2045331Samw if (is_dir) { 2058845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_SUBDIRECTORY) != 0) 2068845Samw@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, 2078845Samw@Sun.COM &vp, flags, cr, vsap); 2085331Samw } else { 2098845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_ADD_FILE) != 0) 2108845Samw@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, 2118845Samw@Sun.COM &vp, flags, cr, vsap); 2125331Samw } 2135331Samw 2145331Samw if (vsap != NULL) 2155331Samw kmem_free(vsap->vsa_aclentp, aclbsize); 2165331Samw 2175331Samw if (rc != 0) 2185331Samw return (rc); 2195331Samw 2205331Samw set_attr.sa_mask = 0; 2215331Samw 2225331Samw /* 2235331Samw * Ideally we should be able to specify the owner and owning 2245331Samw * group at create time along with the ACL. Since we cannot 2255331Samw * do that right now, kcred is passed to smb_vop_setattr so it 2265331Samw * doesn't fail due to lack of permission. 2275331Samw */ 2285331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 2295331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 2305331Samw set_attr.sa_mask |= SMB_AT_UID; 2315331Samw } 2325331Samw 2335331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 2345331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 2355331Samw set_attr.sa_mask |= SMB_AT_GID; 2365331Samw } 2375331Samw 2387757SJanice.Chang@Sun.COM if (set_attr.sa_mask) 2397757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, &set_attr, 0, kcred); 2405331Samw 2417619SJose.Borrego@Sun.COM if (rc == 0) { 2427619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2437619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2447619SJose.Borrego@Sun.COM 2458670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 2467619SJose.Borrego@Sun.COM rc = ENOMEM; 2478670SJose.Borrego@Sun.COM 2488670SJose.Borrego@Sun.COM VN_RELE(vp); 2497619SJose.Borrego@Sun.COM } 2505331Samw } else { 2515331Samw /* 2525331Samw * For filesystems that don't support ACL-on-create, try 2535331Samw * to set the specified SD after create, which could actually 2545331Samw * fail because of conflicts between inherited security 2555331Samw * attributes upon creation and the specified SD. 2565331Samw * 2575331Samw * Passing kcred to smb_fsop_sdwrite() to overcome this issue. 2585331Samw */ 2595331Samw 2605331Samw if (is_dir) { 2617619SJose.Borrego@Sun.COM rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, 2627619SJose.Borrego@Sun.COM flags, cr, NULL); 2635331Samw } else { 2647619SJose.Borrego@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 2657619SJose.Borrego@Sun.COM flags, cr, NULL); 2665331Samw } 2675331Samw 2685521Sas200622 if (rc != 0) 2695521Sas200622 return (rc); 2705521Sas200622 2717619SJose.Borrego@Sun.COM *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, 2727619SJose.Borrego@Sun.COM name, dir_snode, NULL, ret_attr); 2737619SJose.Borrego@Sun.COM 2747619SJose.Borrego@Sun.COM if (*ret_snode != NULL) { 2757619SJose.Borrego@Sun.COM if (!smb_tree_has_feature(sr->tid_tree, 2767619SJose.Borrego@Sun.COM SMB_TREE_NFS_MOUNTED)) 2777619SJose.Borrego@Sun.COM rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, 2787619SJose.Borrego@Sun.COM fs_sd, 1); 2797619SJose.Borrego@Sun.COM } else { 2805331Samw rc = ENOMEM; 2815331Samw } 2828670SJose.Borrego@Sun.COM 2838670SJose.Borrego@Sun.COM VN_RELE(vp); 2845331Samw } 2855331Samw 2865521Sas200622 if (rc != 0) { 2877619SJose.Borrego@Sun.COM if (is_dir) 2887619SJose.Borrego@Sun.COM (void) smb_vop_rmdir(dir_snode->vp, name, flags, cr); 2897619SJose.Borrego@Sun.COM else 2907619SJose.Borrego@Sun.COM (void) smb_vop_remove(dir_snode->vp, name, flags, cr); 2915521Sas200622 } 2925521Sas200622 2935331Samw return (rc); 2945331Samw } 2955331Samw 2965331Samw /* 2975331Samw * smb_fsop_create 2985331Samw * 2995331Samw * All SMB functions should use this wrapper to ensure that 3005331Samw * all the smb_vop_creates are performed with the appropriate credentials. 3015331Samw * Please document any direct calls to explain the reason 3025331Samw * for avoiding this wrapper. 3035331Samw * 3045331Samw * It is assumed that a reference exists on snode coming into this routine. 3055331Samw * 3065331Samw * *ret_snode is returned with a reference upon success. No reference is 3075331Samw * taken if an error is returned. 3085331Samw */ 3095331Samw int 3105331Samw smb_fsop_create( 3116139Sjb150015 smb_request_t *sr, 3126139Sjb150015 cred_t *cr, 3136139Sjb150015 smb_node_t *dir_snode, 3146139Sjb150015 char *name, 3156139Sjb150015 smb_attr_t *attr, 3166139Sjb150015 smb_node_t **ret_snode, 3176139Sjb150015 smb_attr_t *ret_attr) 3185331Samw { 3195331Samw struct open_param *op = &sr->arg.open; 3206139Sjb150015 smb_node_t *fnode; 3216139Sjb150015 smb_attr_t file_attr; 3226139Sjb150015 vnode_t *xattrdirvp; 3236139Sjb150015 vnode_t *vp; 3246139Sjb150015 char *longname = NULL; 3256139Sjb150015 char *fname; 3266139Sjb150015 char *sname; 3276139Sjb150015 int flags = 0; 3286139Sjb150015 int rc = 0; 3296139Sjb150015 smb_fssd_t fs_sd; 3306139Sjb150015 uint32_t secinfo; 3316139Sjb150015 uint32_t status; 3325331Samw 3335331Samw ASSERT(cr); 3345331Samw ASSERT(dir_snode); 3355331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 3365331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 3375331Samw 3385331Samw ASSERT(ret_snode); 3395331Samw *ret_snode = 0; 3405331Samw 3415331Samw ASSERT(name); 3425331Samw if (*name == 0) 3435331Samw return (EINVAL); 3445331Samw 3455331Samw ASSERT(sr); 3465331Samw ASSERT(sr->tid_tree); 3477348SJose.Borrego@Sun.COM 3487348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 3497348SJose.Borrego@Sun.COM return (EACCES); 3507348SJose.Borrego@Sun.COM 3517348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 3525331Samw return (EROFS); 3535331Samw 3547348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 3555331Samw flags = SMB_IGNORE_CASE; 356*9231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 357*9231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 3585331Samw 359*9231SAfshin.Ardakani@Sun.COM if (smb_is_stream_name(name)) { 360*9231SAfshin.Ardakani@Sun.COM fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 361*9231SAfshin.Ardakani@Sun.COM sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 3625331Samw 363*9231SAfshin.Ardakani@Sun.COM if (smb_stream_parse_name(name, fname, sname) == -1) { 3645331Samw kmem_free(fname, MAXNAMELEN); 3655331Samw kmem_free(sname, MAXNAMELEN); 366*9231SAfshin.Ardakani@Sun.COM return (EINVAL); 3675331Samw } 3685331Samw 369*9231SAfshin.Ardakani@Sun.COM /* Look up the unnamed stream. */ 3705331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 371*9231SAfshin.Ardakani@Sun.COM sr->tid_tree->t_snode, dir_snode, fname, 372*9231SAfshin.Ardakani@Sun.COM &fnode, &file_attr); 3735331Samw 3745331Samw if (rc != 0) { 3755331Samw kmem_free(fname, MAXNAMELEN); 3765331Samw kmem_free(sname, MAXNAMELEN); 3775331Samw return (rc); 3785331Samw } 3795331Samw 3805331Samw rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp, 3815772Sas200622 &xattrdirvp, flags, cr); 3825331Samw 3835331Samw if (rc != 0) { 3845331Samw smb_node_release(fnode); 3855331Samw kmem_free(fname, MAXNAMELEN); 3865331Samw kmem_free(sname, MAXNAMELEN); 3875331Samw return (rc); 3885331Samw } 3895331Samw 3906030Sjb150015 attr->sa_vattr.va_uid = file_attr.sa_vattr.va_uid; 3916030Sjb150015 attr->sa_vattr.va_gid = file_attr.sa_vattr.va_gid; 3926030Sjb150015 attr->sa_mask = SMB_AT_UID | SMB_AT_GID; 3936030Sjb150015 3946030Sjb150015 /* 3956030Sjb150015 * The second parameter of smb_vop_setattr() is set to 3966030Sjb150015 * NULL, even though an unnamed stream exists. This is 3976030Sjb150015 * because we want to set the UID and GID on the named 3986030Sjb150015 * stream in this case for consistency with the (unnamed 3996030Sjb150015 * stream) file (see comments for smb_vop_setattr()). 4006030Sjb150015 */ 4016030Sjb150015 4027757SJanice.Chang@Sun.COM rc = smb_vop_setattr(vp, NULL, attr, 0, kcred); 4036030Sjb150015 4046030Sjb150015 if (rc != 0) { 4056030Sjb150015 smb_node_release(fnode); 4066030Sjb150015 kmem_free(fname, MAXNAMELEN); 4076030Sjb150015 kmem_free(sname, MAXNAMELEN); 4086030Sjb150015 return (rc); 4096030Sjb150015 } 4106030Sjb150015 4115331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 4125331Samw vp, sname, ret_attr); 4135331Samw 4145331Samw smb_node_release(fnode); 4158670SJose.Borrego@Sun.COM VN_RELE(xattrdirvp); 4168670SJose.Borrego@Sun.COM VN_RELE(vp); 4175331Samw 418*9231SAfshin.Ardakani@Sun.COM if (*ret_snode == NULL) 419*9231SAfshin.Ardakani@Sun.COM rc = ENOMEM; 420*9231SAfshin.Ardakani@Sun.COM 421*9231SAfshin.Ardakani@Sun.COM kmem_free(fname, MAXNAMELEN); 422*9231SAfshin.Ardakani@Sun.COM kmem_free(sname, MAXNAMELEN); 423*9231SAfshin.Ardakani@Sun.COM return (rc); 424*9231SAfshin.Ardakani@Sun.COM } 4255521Sas200622 426*9231SAfshin.Ardakani@Sun.COM /* Not a named stream */ 427*9231SAfshin.Ardakani@Sun.COM if (smb_maybe_mangled_name(name)) { 428*9231SAfshin.Ardakani@Sun.COM longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 429*9231SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dir_snode, name, longname, MAXNAMELEN); 430*9231SAfshin.Ardakani@Sun.COM kmem_free(longname, MAXNAMELEN); 4315331Samw 432*9231SAfshin.Ardakani@Sun.COM if (rc == 0) 433*9231SAfshin.Ardakani@Sun.COM rc = EEXIST; 434*9231SAfshin.Ardakani@Sun.COM if (rc != ENOENT) 435*9231SAfshin.Ardakani@Sun.COM return (rc); 4365331Samw } 4375331Samw 438*9231SAfshin.Ardakani@Sun.COM if (op->sd) { 439*9231SAfshin.Ardakani@Sun.COM /* 440*9231SAfshin.Ardakani@Sun.COM * SD sent by client in Windows format. Needs to be 441*9231SAfshin.Ardakani@Sun.COM * converted to FS format. No inheritance. 442*9231SAfshin.Ardakani@Sun.COM */ 443*9231SAfshin.Ardakani@Sun.COM secinfo = smb_sd_get_secinfo(op->sd); 444*9231SAfshin.Ardakani@Sun.COM smb_fssd_init(&fs_sd, secinfo, 0); 445*9231SAfshin.Ardakani@Sun.COM 446*9231SAfshin.Ardakani@Sun.COM status = smb_sd_tofs(op->sd, &fs_sd); 447*9231SAfshin.Ardakani@Sun.COM if (status == NT_STATUS_SUCCESS) { 448*9231SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 449*9231SAfshin.Ardakani@Sun.COM name, attr, ret_snode, ret_attr, &fs_sd); 450*9231SAfshin.Ardakani@Sun.COM } else { 451*9231SAfshin.Ardakani@Sun.COM rc = EINVAL; 452*9231SAfshin.Ardakani@Sun.COM } 453*9231SAfshin.Ardakani@Sun.COM smb_fssd_term(&fs_sd); 454*9231SAfshin.Ardakani@Sun.COM } else if (sr->tid_tree->t_acltype == ACE_T) { 455*9231SAfshin.Ardakani@Sun.COM /* 456*9231SAfshin.Ardakani@Sun.COM * No incoming SD and filesystem is ZFS 457*9231SAfshin.Ardakani@Sun.COM * Server applies Windows inheritance rules, 458*9231SAfshin.Ardakani@Sun.COM * see smb_fsop_sdinherit() comments as to why. 459*9231SAfshin.Ardakani@Sun.COM */ 460*9231SAfshin.Ardakani@Sun.COM smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, 0); 461*9231SAfshin.Ardakani@Sun.COM rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 462*9231SAfshin.Ardakani@Sun.COM if (rc == 0) { 463*9231SAfshin.Ardakani@Sun.COM rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 464*9231SAfshin.Ardakani@Sun.COM name, attr, ret_snode, ret_attr, &fs_sd); 465*9231SAfshin.Ardakani@Sun.COM } 466*9231SAfshin.Ardakani@Sun.COM 467*9231SAfshin.Ardakani@Sun.COM smb_fssd_term(&fs_sd); 468*9231SAfshin.Ardakani@Sun.COM } else { 469*9231SAfshin.Ardakani@Sun.COM /* 470*9231SAfshin.Ardakani@Sun.COM * No incoming SD and filesystem is not ZFS 471*9231SAfshin.Ardakani@Sun.COM * let the filesystem handles the inheritance. 472*9231SAfshin.Ardakani@Sun.COM */ 473*9231SAfshin.Ardakani@Sun.COM rc = smb_vop_create(dir_snode->vp, name, attr, &vp, 474*9231SAfshin.Ardakani@Sun.COM flags, cr, NULL); 475*9231SAfshin.Ardakani@Sun.COM 476*9231SAfshin.Ardakani@Sun.COM if (rc == 0) { 477*9231SAfshin.Ardakani@Sun.COM *ret_snode = smb_node_lookup(sr, op, cr, vp, 478*9231SAfshin.Ardakani@Sun.COM name, dir_snode, NULL, ret_attr); 479*9231SAfshin.Ardakani@Sun.COM 480*9231SAfshin.Ardakani@Sun.COM if (*ret_snode == NULL) 481*9231SAfshin.Ardakani@Sun.COM rc = ENOMEM; 482*9231SAfshin.Ardakani@Sun.COM 483*9231SAfshin.Ardakani@Sun.COM VN_RELE(vp); 484*9231SAfshin.Ardakani@Sun.COM } 485*9231SAfshin.Ardakani@Sun.COM 486*9231SAfshin.Ardakani@Sun.COM } 487*9231SAfshin.Ardakani@Sun.COM 4885331Samw return (rc); 4895331Samw } 4905331Samw 4915331Samw /* 4925331Samw * smb_fsop_mkdir 4935331Samw * 4945331Samw * All SMB functions should use this wrapper to ensure that 4955331Samw * the the calls are performed with the appropriate credentials. 4965331Samw * Please document any direct call to explain the reason 4975331Samw * for avoiding this wrapper. 4985331Samw * 4995331Samw * It is assumed that a reference exists on snode coming into this routine. 5005331Samw * 5015331Samw * *ret_snode is returned with a reference upon success. No reference is 5025331Samw * taken if an error is returned. 5035331Samw */ 5045331Samw int 5055331Samw smb_fsop_mkdir( 5066139Sjb150015 smb_request_t *sr, 5075331Samw cred_t *cr, 5085331Samw smb_node_t *dir_snode, 5095331Samw char *name, 5105331Samw smb_attr_t *attr, 5115331Samw smb_node_t **ret_snode, 5125331Samw smb_attr_t *ret_attr) 5135331Samw { 5145331Samw struct open_param *op = &sr->arg.open; 5155331Samw char *longname; 5165331Samw vnode_t *vp; 5175331Samw int flags = 0; 5185331Samw smb_fssd_t fs_sd; 5195331Samw uint32_t secinfo; 5205331Samw uint32_t status; 5215331Samw int rc; 5225331Samw ASSERT(cr); 5235331Samw ASSERT(dir_snode); 5245331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 5255331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 5265331Samw 5275331Samw ASSERT(ret_snode); 5285331Samw *ret_snode = 0; 5295331Samw 5305331Samw ASSERT(name); 5315331Samw if (*name == 0) 5325331Samw return (EINVAL); 5335331Samw 5345331Samw ASSERT(sr); 5355331Samw ASSERT(sr->tid_tree); 5367348SJose.Borrego@Sun.COM 5377348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 5387348SJose.Borrego@Sun.COM return (EACCES); 5397348SJose.Borrego@Sun.COM 5407348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 5415331Samw return (EROFS); 542*9231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 543*9231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 5445331Samw 5455331Samw if (smb_maybe_mangled_name(name)) { 5465331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 547*9231SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dir_snode, name, longname, MAXNAMELEN); 5485331Samw kmem_free(longname, MAXNAMELEN); 5495331Samw 5505331Samw /* 5515331Samw * If the name passed in by the client has an unmangled 5525331Samw * equivalent that is found in the specified directory, 5535331Samw * then the mkdir cannot succeed. Return EEXIST. 5545331Samw * 5555331Samw * Only if ENOENT is returned will a mkdir be attempted. 5565331Samw */ 5575331Samw 5585331Samw if (rc == 0) 5595331Samw rc = EEXIST; 5605331Samw 5615331Samw if (rc != ENOENT) 5625331Samw return (rc); 5635331Samw } 5645331Samw 5657348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 5665331Samw flags = SMB_IGNORE_CASE; 5675331Samw 5685521Sas200622 if (op->sd) { 5695331Samw /* 5705331Samw * SD sent by client in Windows format. Needs to be 5715331Samw * converted to FS format. No inheritance. 5725331Samw */ 5735521Sas200622 secinfo = smb_sd_get_secinfo(op->sd); 5745521Sas200622 smb_fssd_init(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR); 5755521Sas200622 5765521Sas200622 status = smb_sd_tofs(op->sd, &fs_sd); 5775331Samw if (status == NT_STATUS_SUCCESS) { 5785331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 5795331Samw name, attr, ret_snode, ret_attr, &fs_sd); 5805331Samw } 5815331Samw else 5825331Samw rc = EINVAL; 5835521Sas200622 smb_fssd_term(&fs_sd); 5845331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 5855331Samw /* 5865331Samw * No incoming SD and filesystem is ZFS 5875331Samw * Server applies Windows inheritance rules, 5885331Samw * see smb_fsop_sdinherit() comments as to why. 5895331Samw */ 5905521Sas200622 smb_fssd_init(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR); 5915331Samw rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd); 5925331Samw if (rc == 0) { 5935331Samw rc = smb_fsop_create_with_sd(sr, cr, dir_snode, 5945331Samw name, attr, ret_snode, ret_attr, &fs_sd); 5955331Samw } 5965331Samw 5975521Sas200622 smb_fssd_term(&fs_sd); 5985331Samw 5995331Samw } else { 6005331Samw rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr, 6015772Sas200622 NULL); 6025331Samw 6035331Samw if (rc == 0) { 6045331Samw *ret_snode = smb_node_lookup(sr, op, cr, vp, name, 6055331Samw dir_snode, NULL, ret_attr); 6065331Samw 6078670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 6085331Samw rc = ENOMEM; 6098670SJose.Borrego@Sun.COM 6108670SJose.Borrego@Sun.COM VN_RELE(vp); 6115331Samw } 6125331Samw } 6135331Samw 6145331Samw return (rc); 6155331Samw } 6165331Samw 6175331Samw /* 6185331Samw * smb_fsop_remove 6195331Samw * 6205331Samw * All SMB functions should use this wrapper to ensure that 6215331Samw * the the calls are performed with the appropriate credentials. 6225331Samw * Please document any direct call to explain the reason 6235331Samw * for avoiding this wrapper. 6245331Samw * 6255331Samw * It is assumed that a reference exists on snode coming into this routine. 6265331Samw * 6275331Samw * A null smb_request might be passed to this function. 6285331Samw */ 6295331Samw int 6305331Samw smb_fsop_remove( 6316139Sjb150015 smb_request_t *sr, 6326139Sjb150015 cred_t *cr, 6336139Sjb150015 smb_node_t *dir_snode, 6346139Sjb150015 char *name, 635*9231SAfshin.Ardakani@Sun.COM uint32_t flags) 6365331Samw { 6376139Sjb150015 smb_node_t *fnode; 6386139Sjb150015 smb_attr_t file_attr; 6396139Sjb150015 char *longname; 6406139Sjb150015 char *fname; 6416139Sjb150015 char *sname; 6426139Sjb150015 int rc; 6435331Samw 6445331Samw ASSERT(cr); 6455331Samw /* 6465331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 6475331Samw * function is called during the deletion of the node (because of 6485331Samw * DELETE_ON_CLOSE). 6495331Samw */ 6505331Samw ASSERT(dir_snode); 6515331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 6525331Samw 6538845Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0 || 6548845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_DELETE) == 0) 6555331Samw return (EACCES); 6565331Samw 6577348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 6585331Samw return (EROFS); 6595331Samw 6605331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6615331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6625331Samw 6635967Scp160787 if (dir_snode->flags & NODE_XATTR_DIR) { 6645967Scp160787 rc = smb_vop_stream_remove(dir_snode->dir_snode->vp, 6655967Scp160787 name, flags, cr); 6668334SJose.Borrego@Sun.COM } else if ((rc = smb_stream_parse_name(name, fname, sname)) != 0) { 6678334SJose.Borrego@Sun.COM if (rc == -1) { 6688334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 6698334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 6708334SJose.Borrego@Sun.COM return (EINVAL); 6718334SJose.Borrego@Sun.COM } 6728334SJose.Borrego@Sun.COM 6735967Scp160787 /* 6745331Samw * Look up the unnamed stream (i.e. fname). 6755331Samw * Unmangle processing will be done on fname 6765331Samw * as well as any link target. 6775331Samw */ 6785331Samw 6795331Samw rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS, 680*9231SAfshin.Ardakani@Sun.COM sr->tid_tree->t_snode, dir_snode, fname, 681*9231SAfshin.Ardakani@Sun.COM &fnode, &file_attr); 6825331Samw 6835331Samw if (rc != 0) { 6845331Samw kmem_free(fname, MAXNAMELEN); 6855331Samw kmem_free(sname, MAXNAMELEN); 6865331Samw return (rc); 6875331Samw } 6885331Samw 6895331Samw /* 6905331Samw * XXX 6915331Samw * Need to find out what permission is required by NTFS 6925331Samw * to remove a stream. 6935331Samw */ 6945772Sas200622 rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr); 6955331Samw 6965331Samw smb_node_release(fnode); 6975331Samw } else { 6985772Sas200622 rc = smb_vop_remove(dir_snode->vp, name, flags, cr); 6995331Samw 7005331Samw if (rc == ENOENT) { 7015331Samw if (smb_maybe_mangled_name(name) == 0) { 7025331Samw kmem_free(fname, MAXNAMELEN); 7035331Samw kmem_free(sname, MAXNAMELEN); 7045331Samw return (rc); 7055331Samw } 7065331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 7075331Samw 708*9231SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dir_snode, name, 709*9231SAfshin.Ardakani@Sun.COM longname, MAXNAMELEN); 7105331Samw 7115331Samw if (rc == 0) { 7125331Samw /* 713*9231SAfshin.Ardakani@Sun.COM * longname is the real (case-sensitive) 714*9231SAfshin.Ardakani@Sun.COM * on-disk name. 7155331Samw * We make sure we do a remove on this exact 7165331Samw * name, as the name was mangled and denotes 7175331Samw * a unique file. 7185331Samw */ 7195331Samw flags &= ~SMB_IGNORE_CASE; 7205331Samw rc = smb_vop_remove(dir_snode->vp, longname, 7215772Sas200622 flags, cr); 7225331Samw } 7235331Samw 7245331Samw kmem_free(longname, MAXNAMELEN); 7255331Samw } 7265331Samw } 7275331Samw 7285331Samw kmem_free(fname, MAXNAMELEN); 7295331Samw kmem_free(sname, MAXNAMELEN); 7305331Samw return (rc); 7315331Samw } 7325331Samw 7335331Samw /* 7345331Samw * smb_fsop_remove_streams 7355331Samw * 7365331Samw * This function removes a file's streams without removing the 7375331Samw * file itself. 7385331Samw * 7398670SJose.Borrego@Sun.COM * It is assumed that fnode is not a link. 7405331Samw */ 7415331Samw int 7426139Sjb150015 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) 7435331Samw { 7448670SJose.Borrego@Sun.COM int rc, flags = 0; 7458670SJose.Borrego@Sun.COM uint16_t odid; 7468670SJose.Borrego@Sun.COM smb_odir_t *od; 7478670SJose.Borrego@Sun.COM smb_odirent_t *odirent; 7488670SJose.Borrego@Sun.COM boolean_t eos; 7495331Samw 7507348SJose.Borrego@Sun.COM ASSERT(sr); 7515331Samw ASSERT(cr); 7525331Samw ASSERT(fnode); 7535331Samw ASSERT(fnode->n_magic == SMB_NODE_MAGIC); 7545331Samw ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); 7555331Samw 7567348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, fnode) == 0) 7575331Samw return (EACCES); 7585331Samw 7597348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 7605331Samw return (EROFS); 7615331Samw 7627348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 7635331Samw flags = SMB_IGNORE_CASE; 764*9231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 765*9231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 7665331Samw 7678670SJose.Borrego@Sun.COM if ((odid = smb_odir_openat(sr, fnode)) == 0) 7688670SJose.Borrego@Sun.COM return (ENOENT); 7698670SJose.Borrego@Sun.COM if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) 7708670SJose.Borrego@Sun.COM return (ENOENT); 7715331Samw 7728670SJose.Borrego@Sun.COM odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 7738670SJose.Borrego@Sun.COM for (;;) { 7748670SJose.Borrego@Sun.COM rc = smb_odir_read(sr, od, odirent, &eos); 7758670SJose.Borrego@Sun.COM if ((rc != 0) || (eos)) 7765331Samw break; 7778670SJose.Borrego@Sun.COM (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name, 7788670SJose.Borrego@Sun.COM flags, cr); 7798670SJose.Borrego@Sun.COM } 7808670SJose.Borrego@Sun.COM kmem_free(odirent, sizeof (smb_odirent_t)); 7815331Samw 7828670SJose.Borrego@Sun.COM smb_odir_release(od); 7838670SJose.Borrego@Sun.COM smb_odir_close(od); 7845331Samw return (rc); 7855331Samw } 7865331Samw 7875331Samw /* 7885331Samw * smb_fsop_rmdir 7895331Samw * 7905331Samw * All SMB functions should use this wrapper to ensure that 7915331Samw * the the calls are performed with the appropriate credentials. 7925331Samw * Please document any direct call to explain the reason 7935331Samw * for avoiding this wrapper. 7945331Samw * 7955331Samw * It is assumed that a reference exists on snode coming into this routine. 7965331Samw */ 7975331Samw int 7985331Samw smb_fsop_rmdir( 7996139Sjb150015 smb_request_t *sr, 8006139Sjb150015 cred_t *cr, 8016139Sjb150015 smb_node_t *dir_snode, 8026139Sjb150015 char *name, 803*9231SAfshin.Ardakani@Sun.COM uint32_t flags) 8045331Samw { 8056139Sjb150015 int rc; 8066139Sjb150015 char *longname; 8075331Samw 8085331Samw ASSERT(cr); 8095331Samw /* 8105331Samw * The state of the node could be SMB_NODE_STATE_DESTROYING if this 8115331Samw * function is called during the deletion of the node (because of 8125331Samw * DELETE_ON_CLOSE). 8135331Samw */ 8145331Samw ASSERT(dir_snode); 8155331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 8165331Samw 8178845Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0 || 8188845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_DELETE_CHILD) == 0) 8195331Samw return (EACCES); 8205331Samw 8217348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 8225331Samw return (EROFS); 8235331Samw 8245772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr); 8255331Samw 8265331Samw if (rc == ENOENT) { 8275331Samw if (smb_maybe_mangled_name(name) == 0) 8285331Samw return (rc); 8295331Samw 8305331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 831*9231SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dir_snode, name, longname, MAXNAMELEN); 8325331Samw 8335331Samw if (rc == 0) { 8345331Samw /* 835*9231SAfshin.Ardakani@Sun.COM * longname is the real (case-sensitive) 836*9231SAfshin.Ardakani@Sun.COM * on-disk name. 8375331Samw * We make sure we do a rmdir on this exact 8385331Samw * name, as the name was mangled and denotes 8395331Samw * a unique directory. 8405331Samw */ 8415331Samw flags &= ~SMB_IGNORE_CASE; 8425772Sas200622 rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr); 8435331Samw } 8445331Samw 8455331Samw kmem_free(longname, MAXNAMELEN); 8465331Samw } 8475331Samw 8485331Samw return (rc); 8495331Samw } 8505331Samw 8515331Samw /* 8525331Samw * smb_fsop_getattr 8535331Samw * 8545331Samw * All SMB functions should use this wrapper to ensure that 8555331Samw * the the calls are performed with the appropriate credentials. 8565331Samw * Please document any direct call to explain the reason 8575331Samw * for avoiding this wrapper. 8585331Samw * 8595331Samw * It is assumed that a reference exists on snode coming into this routine. 8605331Samw */ 8615331Samw int 8626139Sjb150015 smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 8635331Samw smb_attr_t *attr) 8645331Samw { 8655331Samw smb_node_t *unnamed_node; 8665331Samw vnode_t *unnamed_vp = NULL; 8675331Samw uint32_t status; 8685331Samw uint32_t access = 0; 8695331Samw int flags = 0; 8705772Sas200622 int rc; 8715331Samw 8725331Samw ASSERT(cr); 8735331Samw ASSERT(snode); 8745331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 8755331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 8765331Samw 8778845Samw@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0 || 8788845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0) 8795331Samw return (EACCES); 8805331Samw 8815331Samw if (sr->fid_ofile) { 8825331Samw /* if uid and/or gid is requested */ 8835331Samw if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID)) 8845331Samw access |= READ_CONTROL; 8855331Samw 8865331Samw /* if anything else is also requested */ 8875331Samw if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID)) 8885331Samw access |= FILE_READ_ATTRIBUTES; 8895331Samw 8905331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 8915331Samw if (status != NT_STATUS_SUCCESS) 8925331Samw return (EACCES); 8935331Samw 8947348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 8957348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 8965331Samw flags = ATTR_NOACLCHECK; 8975331Samw } 8985331Samw 8995331Samw unnamed_node = SMB_IS_STREAM(snode); 9005331Samw 9015331Samw if (unnamed_node) { 9025331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 9035331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 9045331Samw unnamed_vp = unnamed_node->vp; 9055331Samw } 9065331Samw 9075772Sas200622 rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr); 9085772Sas200622 if (rc == 0) 9095772Sas200622 snode->attr = *attr; 9105772Sas200622 9115772Sas200622 return (rc); 9125331Samw } 9135331Samw 9145331Samw /* 9155331Samw * smb_fsop_rename 9165331Samw * 9175331Samw * All SMB functions should use this smb_vop_rename wrapper to ensure that 9185331Samw * the smb_vop_rename is performed with the appropriate credentials. 9195331Samw * Please document any direct call to smb_vop_rename to explain the reason 9205331Samw * for avoiding this wrapper. 9215331Samw * 9225331Samw * It is assumed that references exist on from_dir_snode and to_dir_snode coming 9235331Samw * into this routine. 9245331Samw */ 9255331Samw int 9265331Samw smb_fsop_rename( 9276139Sjb150015 smb_request_t *sr, 9285331Samw cred_t *cr, 9295331Samw smb_node_t *from_dir_snode, 9305331Samw char *from_name, 9315331Samw smb_node_t *to_dir_snode, 9325331Samw char *to_name) 9335331Samw { 9345331Samw smb_node_t *from_snode; 9355331Samw smb_attr_t tmp_attr; 9365331Samw vnode_t *from_vp; 937*9231SAfshin.Ardakani@Sun.COM int flags = 0, ret_flags; 9385331Samw int rc; 9398845Samw@Sun.COM boolean_t isdir; 9405331Samw 9415331Samw ASSERT(cr); 9425331Samw ASSERT(from_dir_snode); 9435331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 9445331Samw ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 9455331Samw 9465331Samw ASSERT(to_dir_snode); 9475331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 9485331Samw ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 9495331Samw 9507348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, from_dir_snode) == 0) 9515331Samw return (EACCES); 9525331Samw 9537348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, to_dir_snode) == 0) 9545331Samw return (EACCES); 9555331Samw 9565331Samw ASSERT(sr); 9575331Samw ASSERT(sr->tid_tree); 9587348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 9595331Samw return (EROFS); 9605331Samw 9615331Samw /* 9627348SJose.Borrego@Sun.COM * Note: There is no need to check SMB_TREE_IS_CASEINSENSITIVE 9635331Samw * here. 9645331Samw * 9655331Samw * A case-sensitive rename is always done in this routine 9665331Samw * because we are using the on-disk name from an earlier lookup. 9675331Samw * If a mangled name was passed in by the caller (denoting a 9685331Samw * deterministic lookup), then the exact file must be renamed 9695331Samw * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or 9705331Samw * else the underlying file system might return a "first-match" 9715331Samw * on this on-disk name, possibly resulting in the wrong file). 9725331Samw */ 9735331Samw 974*9231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 975*9231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 976*9231SAfshin.Ardakani@Sun.COM 9775331Samw /* 9785331Samw * XXX: Lock required through smb_node_release() below? 9795331Samw */ 9805331Samw 981*9231SAfshin.Ardakani@Sun.COM rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 982*9231SAfshin.Ardakani@Sun.COM flags, &ret_flags, NULL, cr); 9835331Samw 9845331Samw if (rc != 0) 9855331Samw return (rc); 9865331Samw 9878845Samw@Sun.COM isdir = from_vp->v_type == VDIR; 9888845Samw@Sun.COM 9898845Samw@Sun.COM if ((isdir && SMB_TREE_HAS_ACCESS(sr, 9908845Samw@Sun.COM ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY) != 9918845Samw@Sun.COM (ACE_DELETE_CHILD | ACE_ADD_SUBDIRECTORY)) || 9928845Samw@Sun.COM (!isdir && SMB_TREE_HAS_ACCESS(sr, ACE_DELETE | ACE_ADD_FILE) != 9938845Samw@Sun.COM (ACE_DELETE | ACE_ADD_FILE))) 9948845Samw@Sun.COM return (EACCES); 9958845Samw@Sun.COM 9965331Samw rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp, 9975772Sas200622 to_name, flags, cr); 9985331Samw 9995331Samw if (rc == 0) { 10005331Samw from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name, 10015331Samw from_dir_snode, NULL, &tmp_attr); 10025331Samw 10035331Samw if (from_snode == NULL) { 10048670SJose.Borrego@Sun.COM rc = ENOMEM; 10058670SJose.Borrego@Sun.COM } else { 10068934SJose.Borrego@Sun.COM smb_node_rename(from_dir_snode, from_snode, 10078670SJose.Borrego@Sun.COM to_dir_snode, to_name); 10088670SJose.Borrego@Sun.COM smb_node_release(from_snode); 10095331Samw } 10105331Samw } 10118670SJose.Borrego@Sun.COM VN_RELE(from_vp); 10125331Samw 10135331Samw /* XXX: unlock */ 10145331Samw 10155331Samw return (rc); 10165331Samw } 10175331Samw 10185331Samw /* 10195331Samw * smb_fsop_setattr 10205331Samw * 10215331Samw * All SMB functions should use this wrapper to ensure that 10225331Samw * the the calls are performed with the appropriate credentials. 10235331Samw * Please document any direct call to explain the reason 10245331Samw * for avoiding this wrapper. 10255331Samw * 10265331Samw * It is assumed that a reference exists on snode coming into this routine. 10275331Samw * A null smb_request might be passed to this function. 10285331Samw */ 10295331Samw int 10305331Samw smb_fsop_setattr( 10316139Sjb150015 smb_request_t *sr, 10326139Sjb150015 cred_t *cr, 10336139Sjb150015 smb_node_t *snode, 10346139Sjb150015 smb_attr_t *set_attr, 10356139Sjb150015 smb_attr_t *ret_attr) 10365331Samw { 10375331Samw smb_node_t *unnamed_node; 10385331Samw vnode_t *unnamed_vp = NULL; 10395331Samw uint32_t status; 10407619SJose.Borrego@Sun.COM uint32_t access; 10415331Samw int rc = 0; 10425331Samw int flags = 0; 10437619SJose.Borrego@Sun.COM uint_t sa_mask; 10445331Samw 10455331Samw ASSERT(cr); 10465331Samw ASSERT(snode); 10475331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 10485331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 10495331Samw 10507348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, snode) == 0) 10515331Samw return (EACCES); 10525331Samw 10537348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 10545331Samw return (EROFS); 10555331Samw 10568845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, 10578845Samw@Sun.COM ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0) 10588845Samw@Sun.COM return (EACCES); 10598845Samw@Sun.COM 10607348SJose.Borrego@Sun.COM if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) { 10617348SJose.Borrego@Sun.COM if (sr->fid_ofile) { 10627348SJose.Borrego@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile)) 10637348SJose.Borrego@Sun.COM return (EACCES); 10647348SJose.Borrego@Sun.COM } else { 10657348SJose.Borrego@Sun.COM if (SMB_PATHFILE_IS_READONLY(sr, snode)) 10667348SJose.Borrego@Sun.COM return (EACCES); 10677348SJose.Borrego@Sun.COM } 10687348SJose.Borrego@Sun.COM } 10697348SJose.Borrego@Sun.COM 10705331Samw /* sr could be NULL in some cases */ 10715331Samw if (sr && sr->fid_ofile) { 10727619SJose.Borrego@Sun.COM sa_mask = set_attr->sa_mask; 10737619SJose.Borrego@Sun.COM access = 0; 10747619SJose.Borrego@Sun.COM 10757619SJose.Borrego@Sun.COM if (sa_mask & SMB_AT_SIZE) { 10767619SJose.Borrego@Sun.COM access |= FILE_WRITE_DATA; 10777619SJose.Borrego@Sun.COM sa_mask &= ~SMB_AT_SIZE; 10787619SJose.Borrego@Sun.COM } 10797619SJose.Borrego@Sun.COM 10807619SJose.Borrego@Sun.COM if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) { 10815331Samw access |= WRITE_OWNER; 10827619SJose.Borrego@Sun.COM sa_mask &= ~(SMB_AT_UID|SMB_AT_GID); 10837619SJose.Borrego@Sun.COM } 10847619SJose.Borrego@Sun.COM 10857619SJose.Borrego@Sun.COM if (sa_mask) 10865331Samw access |= FILE_WRITE_ATTRIBUTES; 10875331Samw 10885331Samw status = smb_ofile_access(sr->fid_ofile, cr, access); 10895331Samw if (status != NT_STATUS_SUCCESS) 10905331Samw return (EACCES); 10915331Samw 10927348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 10937348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 10945331Samw flags = ATTR_NOACLCHECK; 10955331Samw } 10965331Samw 10975331Samw unnamed_node = SMB_IS_STREAM(snode); 10985331Samw 10995331Samw if (unnamed_node) { 11005331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 11015331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 11025331Samw unnamed_vp = unnamed_node->vp; 11035331Samw } 11047757SJanice.Chang@Sun.COM 11057757SJanice.Chang@Sun.COM rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr); 11065331Samw 11075331Samw if ((rc == 0) && ret_attr) { 11085331Samw /* 11095772Sas200622 * Use kcred to update the node attr because this 11105772Sas200622 * call is not being made on behalf of the user. 11115331Samw */ 11125331Samw ret_attr->sa_mask = SMB_AT_ALL; 11137348SJose.Borrego@Sun.COM rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags, 11147348SJose.Borrego@Sun.COM kcred); 11155772Sas200622 if (rc == 0) 11165772Sas200622 snode->attr = *ret_attr; 11175331Samw } 11185331Samw 11195331Samw return (rc); 11205331Samw } 11215331Samw 11225331Samw /* 11235331Samw * smb_fsop_read 11245331Samw * 11255331Samw * All SMB functions should use this wrapper to ensure that 11265331Samw * the the calls are performed with the appropriate credentials. 11275331Samw * Please document any direct call to explain the reason 11285331Samw * for avoiding this wrapper. 11295331Samw * 11305331Samw * It is assumed that a reference exists on snode coming into this routine. 11315331Samw */ 11325331Samw int 11335331Samw smb_fsop_read( 11345331Samw struct smb_request *sr, 11355331Samw cred_t *cr, 11365331Samw smb_node_t *snode, 11375331Samw uio_t *uio, 11385331Samw smb_attr_t *ret_attr) 11395331Samw { 11405331Samw smb_node_t *unnamed_node; 11415331Samw vnode_t *unnamed_vp = NULL; 11427348SJose.Borrego@Sun.COM caller_context_t ct; 11435772Sas200622 int svmand; 11445331Samw int rc; 11455331Samw 11465331Samw ASSERT(cr); 11475331Samw ASSERT(snode); 11485331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 11495331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 11505331Samw 11515331Samw ASSERT(sr); 11525331Samw ASSERT(sr->fid_ofile); 11535331Samw 11548845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_DATA) == 0) 11558845Samw@Sun.COM return (EACCES); 11568845Samw@Sun.COM 11575331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA); 11585331Samw if (rc != NT_STATUS_SUCCESS) { 11595331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE); 11605331Samw if (rc != NT_STATUS_SUCCESS) 11615331Samw return (EACCES); 11625331Samw } 11635331Samw 11645331Samw unnamed_node = SMB_IS_STREAM(snode); 11655331Samw if (unnamed_node) { 11665331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 11675331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 11685331Samw unnamed_vp = unnamed_node->vp; 11695331Samw /* 11705331Samw * Streams permission are checked against the unnamed stream, 11715331Samw * but in FS level they have their own permissions. To avoid 11725331Samw * rejection by FS due to lack of permission on the actual 11735331Samw * extended attr kcred is passed for streams. 11745331Samw */ 11755331Samw cr = kcred; 11765331Samw } 11775331Samw 11785772Sas200622 smb_node_start_crit(snode, RW_READER); 11797348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 11805772Sas200622 if (rc) { 11815772Sas200622 smb_node_end_crit(snode); 11825772Sas200622 return (rc); 11835772Sas200622 } 11845772Sas200622 11857348SJose.Borrego@Sun.COM ct = smb_ct; 11867348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 11875772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_READ, uio->uio_loffset, 11887348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 11895772Sas200622 11905772Sas200622 if (rc) { 11915772Sas200622 smb_node_end_crit(snode); 11926432Sas200622 return (ERANGE); 11935772Sas200622 } 11945772Sas200622 rc = smb_vop_read(snode->vp, uio, cr); 11955772Sas200622 11965772Sas200622 if (rc == 0 && ret_attr) { 11975331Samw /* 11985772Sas200622 * Use kcred to update the node attr because this 11995772Sas200622 * call is not being made on behalf of the user. 12005331Samw */ 12015331Samw ret_attr->sa_mask = SMB_AT_ALL; 12025772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 12035772Sas200622 kcred) == 0) { 12045772Sas200622 snode->attr = *ret_attr; 12055772Sas200622 } 12065331Samw } 12075331Samw 12085772Sas200622 smb_node_end_crit(snode); 12095772Sas200622 12105331Samw return (rc); 12115331Samw } 12125331Samw 12135331Samw /* 12145331Samw * smb_fsop_write 12155331Samw * 12165331Samw * This is a wrapper function used for smb_write and smb_write_raw operations. 12175331Samw * 12185331Samw * It is assumed that a reference exists on snode coming into this routine. 12195331Samw */ 12205331Samw int 12215331Samw smb_fsop_write( 12226139Sjb150015 smb_request_t *sr, 12235331Samw cred_t *cr, 12245331Samw smb_node_t *snode, 12255331Samw uio_t *uio, 12265331Samw uint32_t *lcount, 12275331Samw smb_attr_t *ret_attr, 12287052Samw int ioflag) 12295331Samw { 12305331Samw smb_node_t *unnamed_node; 12315331Samw vnode_t *unnamed_vp = NULL; 12327348SJose.Borrego@Sun.COM caller_context_t ct; 12335772Sas200622 int svmand; 12345331Samw int rc; 12355331Samw 12365331Samw ASSERT(cr); 12375331Samw ASSERT(snode); 12385331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 12395331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 12405331Samw 12415331Samw ASSERT(sr); 12425331Samw ASSERT(sr->tid_tree); 12435331Samw ASSERT(sr->fid_ofile); 12445331Samw 12457348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 12465331Samw return (EROFS); 12475772Sas200622 12488845Samw@Sun.COM if (SMB_OFILE_IS_READONLY(sr->fid_ofile) || 12498845Samw@Sun.COM SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_DATA | ACE_APPEND_DATA) == 0) 12507348SJose.Borrego@Sun.COM return (EACCES); 12517348SJose.Borrego@Sun.COM 12525331Samw rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA); 12535772Sas200622 if (rc != NT_STATUS_SUCCESS) { 12545772Sas200622 rc = smb_ofile_access(sr->fid_ofile, cr, FILE_APPEND_DATA); 12555772Sas200622 if (rc != NT_STATUS_SUCCESS) 12565772Sas200622 return (EACCES); 12575772Sas200622 } 12585331Samw 12595331Samw unnamed_node = SMB_IS_STREAM(snode); 12605331Samw 12615331Samw if (unnamed_node) { 12625331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 12635331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 12645331Samw unnamed_vp = unnamed_node->vp; 12655331Samw /* 12665331Samw * Streams permission are checked against the unnamed stream, 12675331Samw * but in FS level they have their own permissions. To avoid 12685331Samw * rejection by FS due to lack of permission on the actual 12695331Samw * extended attr kcred is passed for streams. 12705331Samw */ 12715331Samw cr = kcred; 12725331Samw } 12735331Samw 12745772Sas200622 smb_node_start_crit(snode, RW_READER); 12757348SJose.Borrego@Sun.COM rc = nbl_svmand(snode->vp, kcred, &svmand); 12765772Sas200622 if (rc) { 12775772Sas200622 smb_node_end_crit(snode); 12785772Sas200622 return (rc); 12795772Sas200622 } 12807348SJose.Borrego@Sun.COM 12817348SJose.Borrego@Sun.COM ct = smb_ct; 12827348SJose.Borrego@Sun.COM ct.cc_pid = sr->fid_ofile->f_uniqid; 12835772Sas200622 rc = nbl_lock_conflict(snode->vp, NBL_WRITE, uio->uio_loffset, 12847348SJose.Borrego@Sun.COM uio->uio_iov->iov_len, svmand, &ct); 12855772Sas200622 12865772Sas200622 if (rc) { 12875772Sas200622 smb_node_end_crit(snode); 12886432Sas200622 return (ERANGE); 12895772Sas200622 } 12907052Samw rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr); 12915772Sas200622 12925772Sas200622 if (rc == 0 && ret_attr) { 12935331Samw /* 12945772Sas200622 * Use kcred to update the node attr because this 12955772Sas200622 * call is not being made on behalf of the user. 12965331Samw */ 12975331Samw ret_attr->sa_mask = SMB_AT_ALL; 12985772Sas200622 if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0, 12995772Sas200622 kcred) == 0) { 13005772Sas200622 snode->attr = *ret_attr; 13015772Sas200622 } 13025331Samw } 13035331Samw 13045772Sas200622 smb_node_end_crit(snode); 13055772Sas200622 13065331Samw return (rc); 13075331Samw } 13085331Samw 13095331Samw /* 13105331Samw * smb_fsop_statfs 13115331Samw * 13125331Samw * This is a wrapper function used for stat operations. 13135331Samw */ 13145331Samw int 13155331Samw smb_fsop_statfs( 13165331Samw cred_t *cr, 13175331Samw smb_node_t *snode, 13185331Samw struct statvfs64 *statp) 13195331Samw { 13205331Samw ASSERT(cr); 13215331Samw ASSERT(snode); 13225331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13235331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13245331Samw 13255331Samw return (smb_vop_statfs(snode->vp, statp, cr)); 13265331Samw } 13275331Samw 13285331Samw /* 13295331Samw * smb_fsop_access 13306700Sjm199354 * 13316700Sjm199354 * Named streams do not have separate permissions from the associated 13326700Sjm199354 * unnamed stream. Thus, if node is a named stream, the permissions 13336700Sjm199354 * check will be performed on the associated unnamed stream. 13346700Sjm199354 * 13356700Sjm199354 * However, our named streams do have their own quarantine attribute, 13366700Sjm199354 * separate from that on the unnamed stream. If READ or EXECUTE 13376700Sjm199354 * access has been requested on a named stream, an additional access 13386700Sjm199354 * check is performed on the named stream in case it has been 13396700Sjm199354 * quarantined. kcred is used to avoid issues with the permissions 13406700Sjm199354 * set on the extended attribute file representing the named stream. 13415331Samw */ 13425331Samw int 13435331Samw smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 13445331Samw uint32_t faccess) 13455331Samw { 13465331Samw int access = 0; 13475331Samw int error; 13485331Samw vnode_t *dir_vp; 13495331Samw boolean_t acl_check = B_TRUE; 13505331Samw smb_node_t *unnamed_node; 13515331Samw 13527348SJose.Borrego@Sun.COM ASSERT(sr); 13535331Samw ASSERT(cr); 13545331Samw ASSERT(snode); 13555331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 13565331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 13575331Samw 13585331Samw if (faccess == 0) 13595331Samw return (NT_STATUS_SUCCESS); 13605331Samw 13617348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) { 13625331Samw if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| 13635331Samw FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES| 13645331Samw DELETE|WRITE_DAC|WRITE_OWNER)) { 13655331Samw return (NT_STATUS_ACCESS_DENIED); 13665331Samw } 13675331Samw } 13685331Samw 13695331Samw unnamed_node = SMB_IS_STREAM(snode); 13705331Samw if (unnamed_node) { 13715331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 13725331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 13736700Sjm199354 13746700Sjm199354 /* 13756700Sjm199354 * Perform VREAD access check on the named stream in case it 13766700Sjm199354 * is quarantined. kcred is passed to smb_vop_access so it 13776700Sjm199354 * doesn't fail due to lack of permission. 13786700Sjm199354 */ 13796700Sjm199354 if (faccess & (FILE_READ_DATA | FILE_EXECUTE)) { 13806700Sjm199354 error = smb_vop_access(snode->vp, VREAD, 13816700Sjm199354 0, NULL, kcred); 13826700Sjm199354 if (error) 13836700Sjm199354 return (NT_STATUS_ACCESS_DENIED); 13846700Sjm199354 } 13856700Sjm199354 13865331Samw /* 13875331Samw * Streams authorization should be performed against the 13885331Samw * unnamed stream. 13895331Samw */ 13905331Samw snode = unnamed_node; 13915331Samw } 13925331Samw 13935331Samw if (faccess & ACCESS_SYSTEM_SECURITY) { 13945331Samw /* 13955331Samw * This permission is required for reading/writing SACL and 13965331Samw * it's not part of DACL. It's only granted via proper 13975331Samw * privileges. 13985331Samw */ 13995331Samw if ((sr->uid_user->u_privileges & 14005331Samw (SMB_USER_PRIV_BACKUP | 14015331Samw SMB_USER_PRIV_RESTORE | 14025331Samw SMB_USER_PRIV_SECURITY)) == 0) 14035331Samw return (NT_STATUS_PRIVILEGE_NOT_HELD); 14045331Samw 14055331Samw faccess &= ~ACCESS_SYSTEM_SECURITY; 14065331Samw } 14075331Samw 14085331Samw /* Links don't have ACL */ 14097348SJose.Borrego@Sun.COM if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) || 14105331Samw (snode->attr.sa_vattr.va_type == VLNK)) 14115331Samw acl_check = B_FALSE; 14125331Samw 14138845Samw@Sun.COM /* 14148845Samw@Sun.COM * Use the most restrictive parts of both faccess and the 14158845Samw@Sun.COM * share access. An AND of the two value masks gives us that 14168845Samw@Sun.COM * since we've already converted to a mask of what we "can" 14178845Samw@Sun.COM * do. 14188845Samw@Sun.COM */ 14198845Samw@Sun.COM faccess &= sr->tid_tree->t_access; 14208845Samw@Sun.COM 14215331Samw if (acl_check) { 14225331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 14235331Samw error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp, 14245331Samw cr); 14255331Samw } else { 14265331Samw /* 14275331Samw * FS doesn't understand 32-bit mask, need to map 14285331Samw */ 14295331Samw if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) 14305331Samw access |= VWRITE; 14315331Samw 14325331Samw if (faccess & FILE_READ_DATA) 14335331Samw access |= VREAD; 14345331Samw 14355331Samw if (faccess & FILE_EXECUTE) 14365331Samw access |= VEXEC; 14375331Samw 14385331Samw error = smb_vop_access(snode->vp, access, 0, NULL, cr); 14395331Samw } 14405331Samw 14415331Samw return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS); 14425331Samw } 14435331Samw 14445331Samw /* 14455331Samw * smb_fsop_lookup_name() 14465331Samw * 14477961SNatalie.Li@Sun.COM * If name indicates that the file is a stream file, perform 14487961SNatalie.Li@Sun.COM * stream specific lookup, otherwise call smb_fsop_lookup. 14495331Samw * 14507961SNatalie.Li@Sun.COM * Return an error if the looked-up file is in outside the tree. 14517961SNatalie.Li@Sun.COM * (Required when invoked from open path.) 14525331Samw */ 14535331Samw 14545331Samw int 14555331Samw smb_fsop_lookup_name( 14566139Sjb150015 smb_request_t *sr, 14575331Samw cred_t *cr, 14585331Samw int flags, 14595331Samw smb_node_t *root_node, 14605331Samw smb_node_t *dir_snode, 14615331Samw char *name, 14625331Samw smb_node_t **ret_snode, 14635331Samw smb_attr_t *ret_attr) 14645331Samw { 14656139Sjb150015 smb_node_t *fnode; 14666139Sjb150015 smb_attr_t file_attr; 14676139Sjb150015 vnode_t *xattrdirvp; 14686139Sjb150015 vnode_t *vp; 14696139Sjb150015 char *od_name; 14706139Sjb150015 char *fname; 14716139Sjb150015 char *sname; 14726139Sjb150015 int rc; 14735331Samw 14745331Samw ASSERT(cr); 14755331Samw ASSERT(dir_snode); 14765331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 14775331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 14785331Samw 14795331Samw /* 14805331Samw * The following check is required for streams processing, below 14815331Samw */ 14825331Samw 14837348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 14845331Samw flags |= SMB_IGNORE_CASE; 14855331Samw 14865331Samw fname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14875331Samw sname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14885331Samw 14898334SJose.Borrego@Sun.COM if ((rc = smb_stream_parse_name(name, fname, sname)) != 0) { 14908334SJose.Borrego@Sun.COM if (rc == -1) { 14918334SJose.Borrego@Sun.COM kmem_free(fname, MAXNAMELEN); 14928334SJose.Borrego@Sun.COM kmem_free(sname, MAXNAMELEN); 14938334SJose.Borrego@Sun.COM return (EINVAL); 14948334SJose.Borrego@Sun.COM } 14958334SJose.Borrego@Sun.COM 14965331Samw /* 14975331Samw * Look up the unnamed stream (i.e. fname). 14985331Samw * Unmangle processing will be done on fname 14995331Samw * as well as any link target. 15005331Samw */ 15015331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname, 1502*9231SAfshin.Ardakani@Sun.COM &fnode, &file_attr); 15035331Samw 15045331Samw if (rc != 0) { 15055331Samw kmem_free(fname, MAXNAMELEN); 15065331Samw kmem_free(sname, MAXNAMELEN); 15075331Samw return (rc); 15085331Samw } 15095331Samw 15105331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15115331Samw 15125331Samw /* 15135331Samw * od_name is the on-disk name of the stream, except 15145331Samw * without the prepended stream prefix (SMB_STREAM_PREFIX) 15155331Samw */ 15165331Samw 15175331Samw /* 15185331Samw * XXX 15195331Samw * What permissions NTFS requires for stream lookup if any? 15205331Samw */ 15215331Samw rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name, 15225772Sas200622 &xattrdirvp, flags, root_node->vp, cr); 15235331Samw 15245331Samw if (rc != 0) { 15255331Samw smb_node_release(fnode); 15265331Samw kmem_free(fname, MAXNAMELEN); 15275331Samw kmem_free(sname, MAXNAMELEN); 15285331Samw kmem_free(od_name, MAXNAMELEN); 15295331Samw return (rc); 15305331Samw } 15315331Samw 15325331Samw *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, 15335331Samw vp, od_name, ret_attr); 15345331Samw 15355331Samw kmem_free(od_name, MAXNAMELEN); 15365331Samw smb_node_release(fnode); 15378670SJose.Borrego@Sun.COM VN_RELE(xattrdirvp); 15388670SJose.Borrego@Sun.COM VN_RELE(vp); 15395331Samw 15405331Samw if (*ret_snode == NULL) { 15415331Samw kmem_free(fname, MAXNAMELEN); 15425331Samw kmem_free(sname, MAXNAMELEN); 15435331Samw return (ENOMEM); 15445331Samw } 15455331Samw } else { 15465331Samw rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name, 1547*9231SAfshin.Ardakani@Sun.COM ret_snode, ret_attr); 15485331Samw } 15495331Samw 15505331Samw if (rc == 0) { 15515331Samw ASSERT(ret_snode); 15527348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, *ret_snode) == 0) { 15535331Samw smb_node_release(*ret_snode); 15545331Samw *ret_snode = NULL; 15555331Samw rc = EACCES; 15565331Samw } 15575331Samw } 15585331Samw 15595331Samw kmem_free(fname, MAXNAMELEN); 15605331Samw kmem_free(sname, MAXNAMELEN); 15615331Samw 15625331Samw return (rc); 15635331Samw } 15645331Samw 15655331Samw /* 15665331Samw * smb_fsop_lookup 15675331Samw * 15685331Samw * All SMB functions should use this smb_vop_lookup wrapper to ensure that 15695331Samw * the smb_vop_lookup is performed with the appropriate credentials and using 15705331Samw * case insensitive compares. Please document any direct call to smb_vop_lookup 15715331Samw * to explain the reason for avoiding this wrapper. 15725331Samw * 15735331Samw * It is assumed that a reference exists on dir_snode coming into this routine 15745331Samw * (and that it is safe from deallocation). 15755331Samw * 15765331Samw * Same with the root_node. 15775331Samw * 15785331Samw * *ret_snode is returned with a reference upon success. No reference is 15795331Samw * taken if an error is returned. 15805331Samw * 15815331Samw * Note: The returned ret_snode may be in a child mount. This is ok for 15828670SJose.Borrego@Sun.COM * readdir. 15835331Samw * 15847348SJose.Borrego@Sun.COM * Other smb_fsop_* routines will call SMB_TREE_CONTAINS_NODE() to prevent 15855331Samw * operations on files not in the parent mount. 15865331Samw */ 15875331Samw int 15885331Samw smb_fsop_lookup( 15896139Sjb150015 smb_request_t *sr, 15905331Samw cred_t *cr, 15915331Samw int flags, 15925331Samw smb_node_t *root_node, 15935331Samw smb_node_t *dir_snode, 15945331Samw char *name, 15955331Samw smb_node_t **ret_snode, 1596*9231SAfshin.Ardakani@Sun.COM smb_attr_t *ret_attr) 15975331Samw { 15985331Samw smb_node_t *lnk_target_node; 15995331Samw smb_node_t *lnk_dnode; 16005331Samw char *longname; 16015331Samw char *od_name; 16025331Samw vnode_t *vp; 16035331Samw int rc; 1604*9231SAfshin.Ardakani@Sun.COM int ret_flags; 16055331Samw 16065331Samw ASSERT(cr); 16075331Samw ASSERT(dir_snode); 16085331Samw ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); 16095331Samw ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); 16105331Samw 16115331Samw if (name == NULL) 16125331Samw return (EINVAL); 16135331Samw 16147348SJose.Borrego@Sun.COM if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) 16155331Samw return (EACCES); 16165331Samw 16177348SJose.Borrego@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr)) 16185331Samw flags |= SMB_IGNORE_CASE; 1619*9231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr)) 1620*9231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA; 16215331Samw 16225331Samw od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 16235331Samw 16245331Samw rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags, 1625*9231SAfshin.Ardakani@Sun.COM &ret_flags, root_node ? root_node->vp : NULL, cr); 16265331Samw 16275331Samw if (rc != 0) { 16285331Samw if (smb_maybe_mangled_name(name) == 0) { 16295331Samw kmem_free(od_name, MAXNAMELEN); 16305331Samw return (rc); 16315331Samw } 16325331Samw 16335331Samw longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1634*9231SAfshin.Ardakani@Sun.COM rc = smb_unmangle_name(dir_snode, name, longname, MAXNAMELEN); 16355331Samw if (rc != 0) { 16365331Samw kmem_free(od_name, MAXNAMELEN); 16375331Samw kmem_free(longname, MAXNAMELEN); 16385331Samw return (rc); 16395331Samw } 16405331Samw 16415331Samw /* 1642*9231SAfshin.Ardakani@Sun.COM * longname is the real (case-sensitive) 1643*9231SAfshin.Ardakani@Sun.COM * on-disk name. 16445331Samw * We make sure we do a lookup on this exact 16455331Samw * name, as the name was mangled and denotes 16465331Samw * a unique file. 16475331Samw */ 16485331Samw 16495331Samw if (flags & SMB_IGNORE_CASE) 16505331Samw flags &= ~SMB_IGNORE_CASE; 16515331Samw 16525331Samw rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name, 1653*9231SAfshin.Ardakani@Sun.COM flags, &ret_flags, root_node ? root_node->vp : NULL, cr); 16545331Samw 16555331Samw kmem_free(longname, MAXNAMELEN); 16565331Samw 16575331Samw if (rc != 0) { 16585331Samw kmem_free(od_name, MAXNAMELEN); 16595331Samw return (rc); 16605331Samw } 16615331Samw } 16625331Samw 16635331Samw if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) { 16645331Samw 16655331Samw rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode, 16665331Samw &lnk_dnode, &lnk_target_node, cr); 16675331Samw 16685331Samw if (rc != 0) { 16695331Samw /* 16705331Samw * The link is assumed to be for the last component 16715331Samw * of a path. Hence any ENOTDIR error will be returned 16725331Samw * as ENOENT. 16735331Samw */ 16745331Samw if (rc == ENOTDIR) 16755331Samw rc = ENOENT; 16765331Samw 16775331Samw VN_RELE(vp); 16785331Samw kmem_free(od_name, MAXNAMELEN); 16795331Samw return (rc); 16805331Samw } 16815331Samw 16825331Samw /* 16835331Samw * Release the original VLNK vnode 16845331Samw */ 16855331Samw 16865331Samw VN_RELE(vp); 16875331Samw vp = lnk_target_node->vp; 16885331Samw 16895331Samw rc = smb_vop_traverse_check(&vp); 16905331Samw 16915331Samw if (rc != 0) { 16925331Samw smb_node_release(lnk_dnode); 16935331Samw smb_node_release(lnk_target_node); 16945331Samw kmem_free(od_name, MAXNAMELEN); 16955331Samw return (rc); 16965331Samw } 16975331Samw 16985331Samw /* 16995331Samw * smb_vop_traverse_check() may have returned a different vnode 17005331Samw */ 17015331Samw 17025331Samw if (lnk_target_node->vp == vp) { 17035331Samw *ret_snode = lnk_target_node; 17045331Samw *ret_attr = (*ret_snode)->attr; 17055331Samw } else { 17065331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, 17075331Samw lnk_target_node->od_name, lnk_dnode, NULL, 17085331Samw ret_attr); 17098670SJose.Borrego@Sun.COM VN_RELE(vp); 17105331Samw 17118670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 17125331Samw rc = ENOMEM; 17135331Samw smb_node_release(lnk_target_node); 17145331Samw } 17155331Samw 17165331Samw smb_node_release(lnk_dnode); 17175331Samw 17185331Samw } else { 17195331Samw 17205331Samw rc = smb_vop_traverse_check(&vp); 17215331Samw if (rc) { 17225331Samw VN_RELE(vp); 17235331Samw kmem_free(od_name, MAXNAMELEN); 17245331Samw return (rc); 17255331Samw } 17265331Samw 17275331Samw *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, 17285331Samw dir_snode, NULL, ret_attr); 17298670SJose.Borrego@Sun.COM VN_RELE(vp); 17305331Samw 17318670SJose.Borrego@Sun.COM if (*ret_snode == NULL) 17325331Samw rc = ENOMEM; 17335331Samw } 17345331Samw 17355331Samw kmem_free(od_name, MAXNAMELEN); 17365331Samw return (rc); 17375331Samw } 17385331Samw 17395331Samw int /*ARGSUSED*/ 17405331Samw smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) 17415331Samw { 17425331Samw ASSERT(cr); 17435331Samw ASSERT(snode); 17445331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 17455331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 17465331Samw 17475331Samw ASSERT(sr); 17485331Samw ASSERT(sr->tid_tree); 17497348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 17505331Samw return (EROFS); 17515331Samw 17525772Sas200622 return (smb_vop_commit(snode->vp, cr)); 17535331Samw } 17545331Samw 17555331Samw /* 17565331Samw * smb_fsop_aclread 17575331Samw * 17585331Samw * Retrieve filesystem ACL. Depends on requested ACLs in 17595331Samw * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in 17605331Samw * fs_sd. Note that requesting a DACL/SACL doesn't mean that 17615331Samw * the corresponding field in fs_sd should be non-NULL upon 17625331Samw * return, since the target ACL might not contain that type of 17635331Samw * entries. 17645331Samw * 17655331Samw * Returned ACL is always in ACE_T (aka ZFS) format. 17665331Samw * If successful the allocated memory for the ACL should be freed 17675521Sas200622 * using smb_fsacl_free() or smb_fssd_term() 17685331Samw */ 17695331Samw int 17705331Samw smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 17715331Samw smb_fssd_t *fs_sd) 17725331Samw { 17735331Samw int error = 0; 17745331Samw int flags = 0; 17755331Samw int access = 0; 17765331Samw acl_t *acl; 17775331Samw smb_node_t *unnamed_node; 17785331Samw 17795331Samw ASSERT(cr); 17805331Samw 17818845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_READ_ACL) == 0) 17828845Samw@Sun.COM return (EACCES); 17838845Samw@Sun.COM 17845331Samw if (sr->fid_ofile) { 17855331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 17865331Samw access = READ_CONTROL; 17875331Samw 17885331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 17895331Samw access |= ACCESS_SYSTEM_SECURITY; 17905331Samw 17915331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 17925331Samw if (error != NT_STATUS_SUCCESS) { 17935331Samw return (EACCES); 17945331Samw } 17955331Samw } 17965331Samw 17975331Samw unnamed_node = SMB_IS_STREAM(snode); 17985331Samw if (unnamed_node) { 17995331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 18005331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 18015331Samw /* 18025331Samw * Streams don't have ACL, any read ACL attempt on a stream 18035331Samw * should be performed on the unnamed stream. 18045331Samw */ 18055331Samw snode = unnamed_node; 18065331Samw } 18075331Samw 18087348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) 18095331Samw flags = ATTR_NOACLCHECK; 18105331Samw 18115331Samw error = smb_vop_acl_read(snode->vp, &acl, flags, 18125772Sas200622 sr->tid_tree->t_acltype, cr); 18135331Samw if (error != 0) { 18145331Samw return (error); 18155331Samw } 18165331Samw 18175331Samw error = acl_translate(acl, _ACL_ACE_ENABLED, 18185331Samw (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid); 18195331Samw 18205331Samw if (error == 0) { 18215521Sas200622 smb_fsacl_split(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl, 18225331Samw fs_sd->sd_secinfo); 18235331Samw } 18245331Samw 18255331Samw acl_free(acl); 18265331Samw return (error); 18275331Samw } 18285331Samw 18295331Samw /* 18305331Samw * smb_fsop_aclwrite 18315331Samw * 18325331Samw * Stores the filesystem ACL provided in fs_sd->sd_acl. 18335331Samw */ 18345331Samw int 18355331Samw smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 18365331Samw smb_fssd_t *fs_sd) 18375331Samw { 18385331Samw int target_flavor; 18395331Samw int error = 0; 18405331Samw int flags = 0; 18415331Samw int access = 0; 18425331Samw acl_t *acl, *dacl, *sacl; 18435331Samw smb_node_t *unnamed_node; 18445331Samw 18455331Samw ASSERT(cr); 18465331Samw 18475331Samw ASSERT(sr); 18485331Samw ASSERT(sr->tid_tree); 18497348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 18505331Samw return (EROFS); 18515331Samw 18528845Samw@Sun.COM if (SMB_TREE_HAS_ACCESS(sr, ACE_WRITE_ACL) == 0) 18538845Samw@Sun.COM return (EACCES); 18548845Samw@Sun.COM 18555331Samw if (sr->fid_ofile) { 18565331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 18575331Samw access = WRITE_DAC; 18585331Samw 18595331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 18605331Samw access |= ACCESS_SYSTEM_SECURITY; 18615331Samw 18625331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 18635331Samw if (error != NT_STATUS_SUCCESS) 18645331Samw return (EACCES); 18655331Samw } 18665331Samw 18675331Samw switch (sr->tid_tree->t_acltype) { 18685331Samw case ACLENT_T: 18695331Samw target_flavor = _ACL_ACLENT_ENABLED; 18705331Samw break; 18715331Samw 18725331Samw case ACE_T: 18735331Samw target_flavor = _ACL_ACE_ENABLED; 18745331Samw break; 18755331Samw default: 18765331Samw return (EINVAL); 18775331Samw } 18785331Samw 18795331Samw unnamed_node = SMB_IS_STREAM(snode); 18805331Samw if (unnamed_node) { 18815331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 18825331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 18835331Samw /* 18845331Samw * Streams don't have ACL, any write ACL attempt on a stream 18855331Samw * should be performed on the unnamed stream. 18865331Samw */ 18875331Samw snode = unnamed_node; 18885331Samw } 18895331Samw 18905331Samw dacl = fs_sd->sd_zdacl; 18915331Samw sacl = fs_sd->sd_zsacl; 18925331Samw 18935331Samw ASSERT(dacl || sacl); 18945331Samw if ((dacl == NULL) && (sacl == NULL)) 18955331Samw return (EINVAL); 18965331Samw 18975331Samw if (dacl && sacl) 18985521Sas200622 acl = smb_fsacl_merge(dacl, sacl); 18995331Samw else if (dacl) 19005331Samw acl = dacl; 19015331Samw else 19025331Samw acl = sacl; 19035331Samw 19045331Samw error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR), 19055331Samw fs_sd->sd_uid, fs_sd->sd_gid); 19065331Samw if (error == 0) { 19077348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 19087348SJose.Borrego@Sun.COM SMB_TREE_ACEMASKONACCESS)) 19095331Samw flags = ATTR_NOACLCHECK; 19105331Samw 19115772Sas200622 error = smb_vop_acl_write(snode->vp, acl, flags, cr); 19125331Samw } 19135331Samw 19145331Samw if (dacl && sacl) 19155331Samw acl_free(acl); 19165331Samw 19175331Samw return (error); 19185331Samw } 19195331Samw 19205331Samw acl_type_t 19215331Samw smb_fsop_acltype(smb_node_t *snode) 19225331Samw { 19235331Samw return (smb_vop_acl_type(snode->vp)); 19245331Samw } 19255331Samw 19265331Samw /* 19275331Samw * smb_fsop_sdread 19285331Samw * 19295331Samw * Read the requested security descriptor items from filesystem. 19305331Samw * The items are specified in fs_sd->sd_secinfo. 19315331Samw */ 19325331Samw int 19335331Samw smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 19345331Samw smb_fssd_t *fs_sd) 19355331Samw { 19365331Samw int error = 0; 19375331Samw int getowner = 0; 19385331Samw cred_t *ga_cred; 19395331Samw smb_attr_t attr; 19405331Samw 19415331Samw ASSERT(cr); 19425331Samw ASSERT(fs_sd); 19435331Samw 19445331Samw /* 19455331Samw * File's uid/gid is fetched in two cases: 19465331Samw * 19475331Samw * 1. it's explicitly requested 19485331Samw * 19495331Samw * 2. target ACL is ACE_T (ZFS ACL). They're needed for 19505331Samw * owner@/group@ entries. In this case kcred should be used 19515331Samw * because uid/gid are fetched on behalf of smb server. 19525331Samw */ 19535331Samw if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) { 19545331Samw getowner = 1; 19555331Samw ga_cred = cr; 19565331Samw } else if (sr->tid_tree->t_acltype == ACE_T) { 19575331Samw getowner = 1; 19585331Samw ga_cred = kcred; 19595331Samw } 19605331Samw 19615331Samw if (getowner) { 19625331Samw /* 19635331Samw * Windows require READ_CONTROL to read owner/group SID since 19645331Samw * they're part of Security Descriptor. 19655331Samw * ZFS only requires read_attribute. Need to have a explicit 19665331Samw * access check here. 19675331Samw */ 19685331Samw if (sr->fid_ofile == NULL) { 19695331Samw error = smb_fsop_access(sr, ga_cred, snode, 19705331Samw READ_CONTROL); 19715331Samw if (error) 19725331Samw return (error); 19735331Samw } 19745331Samw 19755331Samw attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 19765331Samw error = smb_fsop_getattr(sr, ga_cred, snode, &attr); 19775331Samw if (error == 0) { 19785331Samw fs_sd->sd_uid = attr.sa_vattr.va_uid; 19795331Samw fs_sd->sd_gid = attr.sa_vattr.va_gid; 19805331Samw } else { 19815331Samw return (error); 19825331Samw } 19835331Samw } 19845331Samw 19855331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 19865331Samw error = smb_fsop_aclread(sr, cr, snode, fs_sd); 19875331Samw } 19885331Samw 19895331Samw return (error); 19905331Samw } 19915331Samw 19925331Samw /* 19935331Samw * smb_fsop_sdmerge 19945331Samw * 19955331Samw * From SMB point of view DACL and SACL are two separate list 19965331Samw * which can be manipulated independently without one affecting 19975331Samw * the other, but entries for both DACL and SACL will end up 19985331Samw * in the same ACL if target filesystem supports ACE_T ACLs. 19995331Samw * 20005331Samw * So, if either DACL or SACL is present in the client set request 20015331Samw * the entries corresponding to the non-present ACL shouldn't 20025331Samw * be touched in the FS ACL. 20035331Samw * 20045331Samw * fs_sd parameter contains DACL and SACL specified by SMB 20055331Samw * client to be set on a file/directory. The client could 20065331Samw * specify both or one of these ACLs (if none is specified 20075331Samw * we don't get this far). When both DACL and SACL are given 20085331Samw * by client the existing ACL should be overwritten. If only 20095331Samw * one of them is specified the entries corresponding to the other 20105331Samw * ACL should not be touched. For example, if only DACL 20115331Samw * is specified in input fs_sd, the function reads audit entries 20125331Samw * of the existing ACL of the file and point fs_sd->sd_zsdacl 20135331Samw * pointer to the fetched SACL, this way when smb_fsop_sdwrite() 20145331Samw * function is called the passed fs_sd would point to the specified 20155331Samw * DACL by client and fetched SACL from filesystem, so the file 20165331Samw * will end up with correct ACL. 20175331Samw */ 20185331Samw static int 20195331Samw smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd) 20205331Samw { 20215331Samw smb_fssd_t cur_sd; 20225331Samw int error = 0; 20235331Samw 20245331Samw if (sr->tid_tree->t_acltype != ACE_T) 20255331Samw /* Don't bother if target FS doesn't support ACE_T */ 20265331Samw return (0); 20275331Samw 20285331Samw if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) { 20295331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) { 20305331Samw /* 20315331Samw * Don't overwrite existing audit entries 20325331Samw */ 20335521Sas200622 smb_fssd_init(&cur_sd, SMB_SACL_SECINFO, 20345331Samw fs_sd->sd_flags); 20355331Samw 20365331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 20375331Samw if (error == 0) { 20385331Samw ASSERT(fs_sd->sd_zsacl == NULL); 20395331Samw fs_sd->sd_zsacl = cur_sd.sd_zsacl; 20405331Samw if (fs_sd->sd_zsacl && fs_sd->sd_zdacl) 20415331Samw fs_sd->sd_zsacl->acl_flags = 20425331Samw fs_sd->sd_zdacl->acl_flags; 20435331Samw } 20445331Samw } else { 20455331Samw /* 20465331Samw * Don't overwrite existing access entries 20475331Samw */ 20485521Sas200622 smb_fssd_init(&cur_sd, SMB_DACL_SECINFO, 20495331Samw fs_sd->sd_flags); 20505331Samw 20515331Samw error = smb_fsop_sdread(sr, kcred, snode, &cur_sd); 20525331Samw if (error == 0) { 20535331Samw ASSERT(fs_sd->sd_zdacl == NULL); 20545331Samw fs_sd->sd_zdacl = cur_sd.sd_zdacl; 20555331Samw if (fs_sd->sd_zdacl && fs_sd->sd_zsacl) 20565331Samw fs_sd->sd_zdacl->acl_flags = 20575331Samw fs_sd->sd_zsacl->acl_flags; 20585331Samw } 20595331Samw } 20605331Samw 20615331Samw if (error) 20625521Sas200622 smb_fssd_term(&cur_sd); 20635331Samw } 20645331Samw 20655331Samw return (error); 20665331Samw } 20675331Samw 20685331Samw /* 20695331Samw * smb_fsop_sdwrite 20705331Samw * 20715331Samw * Stores the given uid, gid and acl in filesystem. 20725331Samw * Provided items in fs_sd are specified by fs_sd->sd_secinfo. 20735331Samw * 20745331Samw * A SMB security descriptor could contain owner, primary group, 20755331Samw * DACL and SACL. Setting an SD should be atomic but here it has to 20765331Samw * be done via two separate FS operations: VOP_SETATTR and 20775331Samw * VOP_SETSECATTR. Therefore, this function has to simulate the 20785331Samw * atomicity as well as it can. 20797619SJose.Borrego@Sun.COM * 20807619SJose.Borrego@Sun.COM * Get the current uid, gid before setting the new uid/gid 20817619SJose.Borrego@Sun.COM * so if smb_fsop_aclwrite fails they can be restored. root cred is 20827619SJose.Borrego@Sun.COM * used to get currend uid/gid since this operation is performed on 20837619SJose.Borrego@Sun.COM * behalf of the server not the user. 20847619SJose.Borrego@Sun.COM * 20857619SJose.Borrego@Sun.COM * If setting uid/gid fails with EPERM it means that and invalid 20867619SJose.Borrego@Sun.COM * owner has been specified. Callers should translate this to 20877619SJose.Borrego@Sun.COM * STATUS_INVALID_OWNER which is not the normal mapping for EPERM 20887619SJose.Borrego@Sun.COM * in upper layers, so EPERM is mapped to EBADE. 20895331Samw */ 20905331Samw int 20915331Samw smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 20925331Samw smb_fssd_t *fs_sd, int overwrite) 20935331Samw { 20945331Samw int error = 0; 20955331Samw int access = 0; 20965331Samw smb_attr_t set_attr; 20975331Samw smb_attr_t orig_attr; 20985331Samw 20995331Samw ASSERT(cr); 21005331Samw ASSERT(fs_sd); 21015331Samw 21025331Samw ASSERT(sr); 21035331Samw ASSERT(sr->tid_tree); 21047348SJose.Borrego@Sun.COM if (SMB_TREE_IS_READONLY(sr)) 21055331Samw return (EROFS); 21065331Samw 21075331Samw bzero(&set_attr, sizeof (smb_attr_t)); 21085331Samw 21095331Samw if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) { 21105331Samw set_attr.sa_vattr.va_uid = fs_sd->sd_uid; 21115331Samw set_attr.sa_mask |= SMB_AT_UID; 21127619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21135331Samw } 21145331Samw 21155331Samw if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) { 21165331Samw set_attr.sa_vattr.va_gid = fs_sd->sd_gid; 21175331Samw set_attr.sa_mask |= SMB_AT_GID; 21187619SJose.Borrego@Sun.COM access |= WRITE_OWNER; 21195331Samw } 21205331Samw 21215331Samw if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) 21225331Samw access |= WRITE_DAC; 21235331Samw 21245331Samw if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) 21255331Samw access |= ACCESS_SYSTEM_SECURITY; 21265331Samw 21275331Samw if (sr->fid_ofile) 21285331Samw error = smb_ofile_access(sr->fid_ofile, cr, access); 21295331Samw else 21305331Samw error = smb_fsop_access(sr, cr, snode, access); 21315331Samw 21325331Samw if (error) 21335331Samw return (EACCES); 21345331Samw 21355331Samw if (set_attr.sa_mask) { 21365331Samw orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID; 21375331Samw error = smb_fsop_getattr(sr, kcred, snode, &orig_attr); 21387619SJose.Borrego@Sun.COM if (error == 0) { 21395331Samw error = smb_fsop_setattr(sr, cr, snode, &set_attr, 21405331Samw NULL); 21417619SJose.Borrego@Sun.COM if (error == EPERM) 21427619SJose.Borrego@Sun.COM error = EBADE; 21437619SJose.Borrego@Sun.COM } 21445331Samw 21455331Samw if (error) 21465331Samw return (error); 21475331Samw } 21485331Samw 21495331Samw if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) { 21505331Samw if (overwrite == 0) { 21515331Samw error = smb_fsop_sdmerge(sr, snode, fs_sd); 21525331Samw if (error) 21535331Samw return (error); 21545331Samw } 21555331Samw 21565331Samw error = smb_fsop_aclwrite(sr, cr, snode, fs_sd); 21575331Samw if (error) { 21585331Samw /* 21595331Samw * Revert uid/gid changes if required. 21605331Samw */ 21615331Samw if (set_attr.sa_mask) { 21625331Samw orig_attr.sa_mask = set_attr.sa_mask; 21635331Samw (void) smb_fsop_setattr(sr, kcred, snode, 21645331Samw &orig_attr, NULL); 21655331Samw } 21665331Samw } 21675331Samw } 21685331Samw 21695331Samw return (error); 21705331Samw } 21715331Samw 21725331Samw /* 21735331Samw * smb_fsop_sdinherit 21745331Samw * 21755331Samw * Inherit the security descriptor from the parent container. 21765331Samw * This function is called after FS has created the file/folder 21775331Samw * so if this doesn't do anything it means FS inheritance is 21785331Samw * in place. 21795331Samw * 21805331Samw * Do inheritance for ZFS internally. 21815331Samw * 21825331Samw * If we want to let ZFS does the inheritance the 21835331Samw * following setting should be true: 21845331Samw * 21855331Samw * - aclinherit = passthrough 21865331Samw * - aclmode = passthrough 21875331Samw * - smbd umask = 0777 21885331Samw * 21895331Samw * This will result in right effective permissions but 21905331Samw * ZFS will always add 6 ACEs for owner, owning group 21915331Samw * and others to be POSIX compliant. This is not what 21925331Samw * Windows clients/users expect, so we decided that CIFS 21935331Samw * implements Windows rules and overwrite whatever ZFS 21945331Samw * comes up with. This way we also don't have to care 21955331Samw * about ZFS aclinherit and aclmode settings. 21965331Samw */ 21975331Samw static int 21985331Samw smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd) 21995331Samw { 22005331Samw int is_dir; 22015521Sas200622 acl_t *dacl = NULL; 22025521Sas200622 acl_t *sacl = NULL; 22035331Samw ksid_t *owner_sid; 22045331Samw int error; 22055331Samw 22065331Samw ASSERT(fs_sd); 22075331Samw 22085331Samw if (sr->tid_tree->t_acltype != ACE_T) { 22095331Samw /* 22105331Samw * No forced inheritance for non-ZFS filesystems. 22115331Samw */ 22125331Samw fs_sd->sd_secinfo = 0; 22135331Samw return (0); 22145331Samw } 22155331Samw 22165331Samw 22175331Samw /* Fetch parent directory's ACL */ 22185331Samw error = smb_fsop_sdread(sr, kcred, dnode, fs_sd); 22195331Samw if (error) { 22205331Samw return (error); 22215331Samw } 22225331Samw 22235331Samw is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR); 22245331Samw owner_sid = crgetsid(sr->user_cr, KSID_OWNER); 22255331Samw ASSERT(owner_sid); 22265521Sas200622 dacl = smb_fsacl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO, 22275331Samw owner_sid->ks_id); 22285521Sas200622 sacl = smb_fsacl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO, 22295331Samw (uid_t)-1); 22305331Samw 22315521Sas200622 if (sacl == NULL) 22325521Sas200622 fs_sd->sd_secinfo &= ~SMB_SACL_SECINFO; 22335521Sas200622 22345521Sas200622 smb_fsacl_free(fs_sd->sd_zdacl); 22355521Sas200622 smb_fsacl_free(fs_sd->sd_zsacl); 22365331Samw 22375331Samw fs_sd->sd_zdacl = dacl; 22385331Samw fs_sd->sd_zsacl = sacl; 22395331Samw 22405331Samw return (0); 22415331Samw } 22425331Samw 22435331Samw /* 22445331Samw * smb_fsop_eaccess 22455331Samw * 22465331Samw * Returns the effective permission of the given credential for the 22475331Samw * specified object. 22485331Samw * 22495331Samw * This is just a workaround. We need VFS/FS support for this. 22505331Samw */ 22515331Samw void 22525331Samw smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode, 22535331Samw uint32_t *eaccess) 22545331Samw { 22555331Samw int access = 0; 22565331Samw vnode_t *dir_vp; 22575331Samw smb_node_t *unnamed_node; 22585331Samw 22595331Samw ASSERT(cr); 22605331Samw ASSERT(snode); 22615331Samw ASSERT(snode->n_magic == SMB_NODE_MAGIC); 22625331Samw ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); 22635331Samw 22645331Samw unnamed_node = SMB_IS_STREAM(snode); 22655331Samw if (unnamed_node) { 22665331Samw ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC); 22675331Samw ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING); 22685331Samw /* 22695331Samw * Streams authorization should be performed against the 22705331Samw * unnamed stream. 22715331Samw */ 22725331Samw snode = unnamed_node; 22735331Samw } 22745331Samw 22757348SJose.Borrego@Sun.COM if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) { 22765331Samw dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL; 22775331Samw smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp, 22785331Samw cr); 22795331Samw return; 22805331Samw } 22815331Samw 22825331Samw /* 22835331Samw * FS doesn't understand 32-bit mask 22845331Samw */ 22855331Samw smb_vop_eaccess(snode->vp, &access, 0, NULL, cr); 22868845Samw@Sun.COM access &= sr->tid_tree->t_access; 22875331Samw 22885331Samw *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES; 22895331Samw 22905331Samw if (access & VREAD) 22915331Samw *eaccess |= FILE_READ_DATA; 22925331Samw 22935331Samw if (access & VEXEC) 22945331Samw *eaccess |= FILE_EXECUTE; 22955331Samw 22965331Samw if (access & VWRITE) 22975331Samw *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | 22985331Samw FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD; 22995331Samw } 23005521Sas200622 23015772Sas200622 /* 23025772Sas200622 * smb_fsop_shrlock 23035772Sas200622 * 23045772Sas200622 * For the current open request, check file sharing rules 23055772Sas200622 * against existing opens. 23065772Sas200622 * 23075772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 23085772Sas200622 * sharing conflict. Returns NT_STATUS_SUCCESS otherwise. 23095772Sas200622 * 23105772Sas200622 * Full system-wide share reservation synchronization is available 23115772Sas200622 * when the nbmand (non-blocking mandatory) mount option is set 23125772Sas200622 * (i.e. nbl_need_crit() is true) and nbmand critical regions are used. 23135772Sas200622 * This provides synchronization with NFS and local processes. The 23145772Sas200622 * critical regions are entered in VOP_SHRLOCK()/fs_shrlock() (called 23155772Sas200622 * from smb_open_subr()/smb_fsop_shrlock()/smb_vop_shrlock()) as well 23165772Sas200622 * as the CIFS rename and delete paths. 23175772Sas200622 * 23185772Sas200622 * The CIFS server will also enter the nbl critical region in the open, 23195772Sas200622 * rename, and delete paths when nbmand is not set. There is limited 23205772Sas200622 * coordination with local and VFS share reservations in this case. 23215772Sas200622 * Note that when the nbmand mount option is not set, the VFS layer 23225772Sas200622 * only processes advisory reservations and the delete mode is not checked. 23235772Sas200622 * 23245772Sas200622 * Whether or not the nbmand mount option is set, intra-CIFS share 23255772Sas200622 * checking is done in the open, delete, and rename paths using a CIFS 23265772Sas200622 * critical region (node->n_share_lock). 23275772Sas200622 */ 23285772Sas200622 23295772Sas200622 uint32_t 23306139Sjb150015 smb_fsop_shrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid, 23315772Sas200622 uint32_t desired_access, uint32_t share_access) 23325772Sas200622 { 23335772Sas200622 int rc; 23345772Sas200622 23355772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 23365772Sas200622 return (NT_STATUS_SUCCESS); 23375772Sas200622 23385772Sas200622 /* Allow access if the request is just for meta data */ 23395772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) 23405772Sas200622 return (NT_STATUS_SUCCESS); 23415772Sas200622 23425772Sas200622 rc = smb_node_open_check(node, cr, desired_access, share_access); 23435772Sas200622 if (rc) 23445772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 23455772Sas200622 23465772Sas200622 rc = smb_vop_shrlock(node->vp, uniq_fid, desired_access, share_access, 23475772Sas200622 cr); 23485772Sas200622 if (rc) 23495772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 23505772Sas200622 23515772Sas200622 return (NT_STATUS_SUCCESS); 23525772Sas200622 } 23535772Sas200622 23545521Sas200622 void 23555772Sas200622 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid) 23565521Sas200622 { 23575772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 23585772Sas200622 return; 23595772Sas200622 23605772Sas200622 (void) smb_vop_unshrlock(node->vp, uniq_fid, cr); 23615772Sas200622 } 23626600Sas200622 23636600Sas200622 int 23646600Sas200622 smb_fsop_frlock(smb_node_t *node, smb_lock_t *lock, boolean_t unlock, 23656600Sas200622 cred_t *cr) 23666600Sas200622 { 23676600Sas200622 flock64_t bf; 23686600Sas200622 int flag = F_REMOTELOCK; 23696600Sas200622 23706771Sjb150015 /* 23716771Sjb150015 * VOP_FRLOCK() will not be called if: 23726771Sjb150015 * 23736771Sjb150015 * 1) The lock has a range of zero bytes. The semantics of Windows and 23746771Sjb150015 * POSIX are different. In the case of POSIX it asks for the locking 23756771Sjb150015 * of all the bytes from the offset provided until the end of the 23766771Sjb150015 * file. In the case of Windows a range of zero locks nothing and 23776771Sjb150015 * doesn't conflict with any other lock. 23786771Sjb150015 * 23796771Sjb150015 * 2) The lock rolls over (start + lenght < start). Solaris will assert 23806771Sjb150015 * if such a request is submitted. This will not create 23816771Sjb150015 * incompatibilities between POSIX and Windows. In the Windows world, 23826771Sjb150015 * if a client submits such a lock, the server will not lock any 23836771Sjb150015 * bytes. Interestingly if the same lock (same offset and length) is 23846771Sjb150015 * resubmitted Windows will consider that there is an overlap and 23856771Sjb150015 * the granting rules will then apply. 23866771Sjb150015 */ 23876771Sjb150015 if ((lock->l_length == 0) || 23886771Sjb150015 ((lock->l_start + lock->l_length - 1) < lock->l_start)) 23896771Sjb150015 return (0); 23906771Sjb150015 23916600Sas200622 bzero(&bf, sizeof (bf)); 23926600Sas200622 23936600Sas200622 if (unlock) { 23946600Sas200622 bf.l_type = F_UNLCK; 23956600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READONLY) { 23966600Sas200622 bf.l_type = F_RDLCK; 23976600Sas200622 flag |= FREAD; 23986600Sas200622 } else if (lock->l_type == SMB_LOCK_TYPE_READWRITE) { 23996600Sas200622 bf.l_type = F_WRLCK; 24006600Sas200622 flag |= FWRITE; 24016600Sas200622 } 24026600Sas200622 24036600Sas200622 bf.l_start = lock->l_start; 24046600Sas200622 bf.l_len = lock->l_length; 24057348SJose.Borrego@Sun.COM bf.l_pid = lock->l_file->f_uniqid; 24066600Sas200622 bf.l_sysid = smb_ct.cc_sysid; 24076600Sas200622 24086600Sas200622 return (smb_vop_frlock(node->vp, cr, flag, &bf)); 24096600Sas200622 } 2410