Print this page
NEX-19152 MacOS HighSierra Finder crashes...
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-19025 CIFS gets confused with filenames containing enhanced Unicode
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
and: (fix build, check-rtime)
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-4820 intended nbmand locking functionality is confused
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17289 Minimal SMB 3.0.2 support
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-16157 Removal of "Read Attributes" prevents reading directory over SMB
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-16157 Removal of "Read Attributes" prevents reading directory over SMB
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6116 Failures in smbtorture raw.open (2)
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6276 SMB sparse file support
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6096 Enable compile warnings re. parentheses in smbsrv
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
SMB-65 SMB server in non-global zones (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).
re #7815 SMB server delivers old modification time...


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/stat.h>
  28 #include <sys/uio.h>
  29 #include <sys/statvfs.h>
  30 #include <sys/vnode.h>
  31 #include <sys/thread.h>
  32 #include <sys/pathname.h>
  33 #include <sys/cred.h>
  34 #include <sys/extdirent.h>
  35 #include <sys/nbmlock.h>
  36 #include <sys/share.h>
  37 #include <sys/fcntl.h>
  38 #include <nfs/lm.h>
  39 
  40 #include <smbsrv/smb_kproto.h>
  41 #include <smbsrv/string.h>
  42 #include <smbsrv/smb_vops.h>
  43 #include <smbsrv/smb_fsops.h>


 233             ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) ||
 234             (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
 235             vn_is_mapped(vp, V_RDORWR));
 236 }
 237 
 238 /*
 239  * The smb_vop_* functions have minimal knowledge of CIFS semantics and
 240  * serve as an interface to the VFS layer.
 241  *
 242  * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
 243  * (Higher-level CIFS service code should never skip the smb_fsop_* layer
 244  * to call smb_vop_* layer functions directly.)
 245  */
 246 
 247 /*
 248  * XXX - Extended attributes support in the file system assumed.
 249  * This is needed for full NT Streams functionality.
 250  */
 251 
 252 int
 253 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr)
 254 {
 255         int error;
 256 
 257         (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
 258         error = VOP_READ(vp, uiop, 0, cr, &smb_ct);
 259         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
 260         return (error);
 261 }
 262 
 263 int
 264 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount,
 265     cred_t *cr)
 266 {
 267         int error;
 268 
 269         *lcount = uiop->uio_resid;
 270 
 271         uiop->uio_llimit = MAXOFFSET_T;
 272 
 273         (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
 274         error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct);
 275         VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
 276 
 277         *lcount -= uiop->uio_resid;
 278 
 279         return (error);
 280 }
 281 

















 282 /*
 283  * smb_vop_getattr()
 284  *
 285  * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
 286  * service (instead of calling VOP_GETATTR directly) to retrieve attributes
 287  * due to special processing needed for streams files.
 288  *
 289  * All attributes are retrieved.
 290  *
 291  * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
 292  * the corresponding unnamed stream).
 293  * A named stream's attributes (as far as CIFS is concerned) are those of the
 294  * unnamed stream (minus the size attribute, and the type), plus  the size of
 295  * the named stream, and a type value of VREG.
 296  * Although the file system may store other attributes with the named stream,
 297  * these should not be used by CIFS for any purpose.
 298  *
 299  * File systems without VFSFT_XVATTR do not support DOS attributes or create
 300  * time (crtime). In this case the mtime is used as the crtime.
 301  * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr


 512 
 513 /*
 514  * smb_vop_access
 515  *
 516  * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
 517  * against file's ACL or Unix permissions. CIFS on the other hand needs to
 518  * know if the requested operation can succeed for the given object, this
 519  * requires more checks in case of DELETE bit since permissions on the parent
 520  * directory are important as well. Based on Windows rules if parent's ACL
 521  * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
 522  * permissions.
 523  */
 524 int
 525 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
 526 {
 527         int error = 0;
 528 
 529         if (mode == 0)
 530                 return (0);
 531 
 532         if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) {
 533                 if (dir_vp) {









 534                         error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
 535                             cr, NULL);
 536 
 537                         if (error == 0)
 538                                 mode &= ~ACE_DELETE;
 539                 }






 540         }
 541 
 542         if (mode) {
 543                 error = VOP_ACCESS(vp, mode, flags, cr, NULL);
 544         }
 545 

 546         return (error);
 547 }
 548 
 549 /*
 550  * smb_vop_lookup
 551  *
 552  * dvp:         directory vnode (in)
 553  * name:        name of file to be looked up (in)
 554  * vpp:         looked-up vnode (out)
 555  * od_name:     on-disk name of file (out).
 556  *              This parameter is optional.  If a pointer is passed in, it
 557  *              must be allocated with MAXNAMELEN bytes
 558  * rootvp:      vnode of the tree root (in)
 559  *              This parameter is always passed in non-NULL except at the time
 560  *              of share set up.
 561  * direntflags: dirent flags returned from VOP_LOOKUP
 562  */
 563 int
 564 smb_vop_lookup(
 565     vnode_t             *dvp,


 603 
 604                         vfsp = cvp->v_vfsp;
 605                         vfs_rlock_wait(vfsp);
 606                         if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
 607                             (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
 608                                 vfs_unlock(vfsp);
 609                                 return (EIO);
 610                         }
 611                         vfs_unlock(vfsp);
 612                 }
 613         }
 614 
 615         if (flags & SMB_IGNORE_CASE)
 616                 option_flags = FIGNORECASE;
 617 
 618         if (flags & SMB_CATIA)
 619                 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
 620 
 621         pn_alloc(&rpn);
 622 






 623         error = VOP_LOOKUP(dvp, np, vpp, NULL, option_flags, NULL, cr,
 624             &smb_ct, direntflags, &rpn);
 625 
 626         if (error == 0) {
 627                 if (od_name) {
 628                         bzero(od_name, MAXNAMELEN);
 629                         np = (option_flags == FIGNORECASE) ? rpn.pn_buf : name;
 630 



 631                         if (flags & SMB_CATIA)
 632                                 smb_vop_catia_v4tov5(np, od_name, MAXNAMELEN);
 633                         else
 634                                 (void) strlcpy(od_name, np, MAXNAMELEN);
 635                 }
 636 
 637                 if (attr != NULL) {
 638                         attr->sa_mask = SMB_AT_ALL;
 639                         (void) smb_vop_getattr(*vpp, NULL, attr, 0,
 640                             zone_kcred());
 641                 }
 642         }
 643 
 644         pn_free(&rpn);
 645         return (error);
 646 }
 647 
 648 int
 649 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
 650     int flags, cred_t *cr, vsecattr_t *vsap)


 661 
 662         attr->sa_vattr.va_mask = 0;
 663 
 664         if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
 665                 smb_vop_setup_xvattr(attr, &xvattr);
 666                 vap = &xvattr.xva_vattr;
 667         } else {
 668                 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
 669                 vap = &attr->sa_vattr;
 670         }
 671 
 672         if (flags & SMB_CATIA) {
 673                 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
 674                 if (strchr(np, '/') != NULL)
 675                         return (EILSEQ);
 676         }
 677 
 678         error = VOP_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode,
 679             vpp, cr, option_flags, &smb_ct, vsap);
 680 














 681         return (error);
 682 }
 683 
 684 int
 685 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr)
 686 {
 687         int error;
 688         int option_flags = 0;
 689         char *np = name;
 690         char namebuf[MAXNAMELEN];
 691 
 692         if (flags & SMB_IGNORE_CASE)
 693                 option_flags = FIGNORECASE;
 694 
 695         if (flags & SMB_CATIA)
 696                 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
 697 
 698         error = VOP_REMOVE(dvp, np, cr, &smb_ct, option_flags);
 699 
 700         return (error);


 953  * not literally stored on-disk in the format returned.
 954  * If the file system supports extended directory entries (has features
 955  * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
 956  * filled with edirent_t structures, instead of dirent64_t structures.
 957  * If the file system supports access based enumeration (abe), set
 958  * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
 959  */
 960 int
 961 smb_vop_readdir(vnode_t *vp, uint32_t offset,
 962     void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
 963 {
 964         int error = 0;
 965         int flags = 0;
 966         int rdirent_size;
 967         struct uio auio;
 968         struct iovec aiov;
 969 
 970         if (vp->v_type != VDIR)
 971                 return (ENOTDIR);
 972 
 973         if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {

 974                 flags |= V_RDDIR_ENTFLAGS;
 975                 rdirent_size = sizeof (edirent_t);
 976         } else {
 977                 rdirent_size = sizeof (dirent64_t);
 978         }
 979 
 980         if (*count < rdirent_size)
 981                 return (EINVAL);
 982 
 983         if (rddir_flag & SMB_ABE)
 984                 flags |= V_RDDIR_ACCFILTER;
 985 
 986         aiov.iov_base = buf;
 987         aiov.iov_len = *count;
 988         auio.uio_iov = &aiov;
 989         auio.uio_iovcnt = 1;
 990         auio.uio_loffset = (uint64_t)offset;
 991         auio.uio_segflg = UIO_SYSSPACE;
 992         auio.uio_extflg = UIO_COPY_DEFAULT;
 993         auio.uio_resid = *count;


1201         ASSERT(vp);
1202         ASSERT(aclp);
1203 
1204         *aclp = NULL;
1205         bzero(&vsecattr, sizeof (vsecattr_t));
1206 
1207         switch (acl_type) {
1208         case ACLENT_T:
1209                 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
1210                     VSA_DFACLCNT;
1211                 break;
1212 
1213         case ACE_T:
1214                 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
1215                 break;
1216 
1217         default:
1218                 return (EINVAL);
1219         }
1220 
1221         if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct))
1222                 return (error);
1223 
1224         *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type);
1225         if (vp->v_type == VDIR)
1226                 (*aclp)->acl_flags |= ACL_IS_DIR;
1227 
1228         return (0);
1229 }
1230 
1231 /*
1232  * smb_vop_acl_write
1233  *
1234  * Writes the given ACL in aclp for the specified file.
1235  */
1236 int
1237 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr)
1238 {
1239         int error;
1240         vsecattr_t vsecattr;
1241         int aclbsize;


1431          */
1432         if (nbl_need_check(vp) && (vp->v_type != VREG))
1433                 return (0);
1434 
1435         /*
1436          * For s_access and s_deny, we do not need to pass in the original
1437          * values.
1438          */
1439         shr.s_access = 0;
1440         shr.s_deny = 0;
1441         shr.s_sysid = smb_ct.cc_sysid;
1442         shr.s_pid = uniq_fid;
1443         shr.s_own_len = sizeof (shr_own);
1444         shr.s_owner = (caddr_t)&shr_own;
1445         shr_own.sl_id = shr.s_sysid;
1446         shr_own.sl_pid = shr.s_pid;
1447 
1448         return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL));
1449 }
1450 












1451 int
1452 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf)
1453 {
1454         int cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK;
1455         flk_callback_t flk_cb;

1456 








1457         flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL);
1458 
1459         return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct));
1460 }
1461 
1462 static callb_cpr_t *
1463 /* ARGSUSED */
1464 smb_lock_frlock_callback(flk_cb_when_t when, void *error)
1465 {
1466         return (0);
1467 }
1468 
1469 /*
1470  * smb_vop_catia_init_v4_lookup
1471  * Initialize  mapping between wide characters in the range from
1472  * 0x00A4 to 0x00FF and their UNIX (v4) equivalent (wide character).
1473  * Indexed by the decimal value of the wide character (164-255)
1474  * with an offset of -164.
1475  */
1476 static void


1514         smb_vop_catia_init_v5_lookup();
1515 }
1516 
1517 /*
1518  * smb_vop_catia_v5tov4
1519  * (windows (v5) to unix (v4))
1520  *
1521  * Traverse each character in the given source filename and convert the
1522  * multibyte that is equivalent to any special Windows character listed
1523  * in the catia_maps table to the Unix ASCII character if any is
1524  * encountered in the filename. The translated name is returned in buf.
1525  *
1526  * If an error occurs the conversion terminates and name is returned,
1527  * otherwise buf is returned.
1528  */
1529 char *
1530 smb_vop_catia_v5tov4(char *name, char *buf, int buflen)
1531 {
1532         int v4_idx, numbytes, inc;
1533         int space_left = buflen - 1; /* one byte reserved for null */
1534         smb_wchar_t wc;
1535         char mbstring[MTS_MB_CHAR_MAX];
1536         char *p, *src = name, *dst = buf;
1537 
1538         ASSERT(name);
1539         ASSERT(buf);
1540 
1541         if (!buf || !name)
1542                 return (name);
1543 
1544         bzero(buf, buflen);
1545 
1546         while (*src) {
1547                 if ((numbytes = smb_mbtowc(&wc, src, MTS_MB_CHAR_MAX)) < 0)
1548                         return (name);
1549 
1550                 if (wc < SMB_CATIA_V4_LOOKUP_LOW ||
1551                     wc > SMB_CATIA_V4_LOOKUP_UPPER) {
1552                         inc = numbytes;
1553                         p = src;
1554                 } else {


1571 }
1572 
1573 /*
1574  * smb_vop_catia_v4tov5
1575  * (unix (v4) to windows (v5))
1576  *
1577  * Traverse each character in the given filename 'srcbuf' and convert
1578  * the special Unix character that is listed in the catia_maps table to
1579  * the UTF-8 encoding of the corresponding Windows character if any is
1580  * encountered in the filename.
1581  *
1582  * The translated name is returned in buf.
1583  * If an error occurs the conversion terminates and the original name
1584  * is returned in buf.
1585  */
1586 void
1587 smb_vop_catia_v4tov5(char *name, char *buf, int buflen)
1588 {
1589         int v5_idx, numbytes;
1590         int space_left = buflen - 1; /* one byte reserved for null */
1591         smb_wchar_t wc;
1592         char mbstring[MTS_MB_CHAR_MAX];
1593         char *src = name, *dst = buf;
1594 
1595         ASSERT(name);
1596         ASSERT(buf);
1597 
1598         if (!buf || !name)
1599                 return;
1600 
1601         (void) bzero(buf, buflen);
1602         while (*src) {
1603                 if (smb_isascii(*src)) {
1604                         /* Lookup required */
1605                         v5_idx = (int)*src++;
1606                         numbytes = smb_wctomb(mbstring,
1607                             smb_catia_v5_lookup[v5_idx]);
1608                         if (space_left < numbytes)
1609                                 break;
1610                         (void) strncpy(dst, mbstring, numbytes);
1611                 } else {


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/stat.h>
  28 #include <sys/uio.h>
  29 #include <sys/statvfs.h>
  30 #include <sys/vnode.h>
  31 #include <sys/thread.h>
  32 #include <sys/pathname.h>
  33 #include <sys/cred.h>
  34 #include <sys/extdirent.h>
  35 #include <sys/nbmlock.h>
  36 #include <sys/share.h>
  37 #include <sys/fcntl.h>
  38 #include <nfs/lm.h>
  39 
  40 #include <smbsrv/smb_kproto.h>
  41 #include <smbsrv/string.h>
  42 #include <smbsrv/smb_vops.h>
  43 #include <smbsrv/smb_fsops.h>


 233             ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) ||
 234             (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
 235             vn_is_mapped(vp, V_RDORWR));
 236 }
 237 
 238 /*
 239  * The smb_vop_* functions have minimal knowledge of CIFS semantics and
 240  * serve as an interface to the VFS layer.
 241  *
 242  * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
 243  * (Higher-level CIFS service code should never skip the smb_fsop_* layer
 244  * to call smb_vop_* layer functions directly.)
 245  */
 246 
 247 /*
 248  * XXX - Extended attributes support in the file system assumed.
 249  * This is needed for full NT Streams functionality.
 250  */
 251 
 252 int
 253 smb_vop_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr)
 254 {
 255         int error;
 256 
 257         (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
 258         error = VOP_READ(vp, uiop, ioflag, cr, &smb_ct);
 259         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
 260         return (error);
 261 }
 262 
 263 int
 264 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount,
 265     cred_t *cr)
 266 {
 267         int error;
 268 
 269         *lcount = uiop->uio_resid;
 270 
 271         uiop->uio_llimit = MAXOFFSET_T;
 272 
 273         (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
 274         error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct);
 275         VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
 276 
 277         *lcount -= uiop->uio_resid;
 278 
 279         return (error);
 280 }
 281 
 282 int
 283 smb_vop_ioctl(vnode_t *vp, int cmd, void *arg, cred_t *cr)
 284 {
 285         int error, rval = 0;
 286         uint_t flags = 0;
 287 
 288 #ifdef  FKIOCTL
 289         flags |= FKIOCTL;
 290 #endif
 291         error = VOP_IOCTL(vp, cmd, (intptr_t)arg, (int)flags, cr,
 292             &rval, &smb_ct);
 293         if (error != 0)
 294                 rval = error;
 295 
 296         return (rval);
 297 }
 298 
 299 /*
 300  * smb_vop_getattr()
 301  *
 302  * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
 303  * service (instead of calling VOP_GETATTR directly) to retrieve attributes
 304  * due to special processing needed for streams files.
 305  *
 306  * All attributes are retrieved.
 307  *
 308  * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
 309  * the corresponding unnamed stream).
 310  * A named stream's attributes (as far as CIFS is concerned) are those of the
 311  * unnamed stream (minus the size attribute, and the type), plus  the size of
 312  * the named stream, and a type value of VREG.
 313  * Although the file system may store other attributes with the named stream,
 314  * these should not be used by CIFS for any purpose.
 315  *
 316  * File systems without VFSFT_XVATTR do not support DOS attributes or create
 317  * time (crtime). In this case the mtime is used as the crtime.
 318  * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr


 529 
 530 /*
 531  * smb_vop_access
 532  *
 533  * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
 534  * against file's ACL or Unix permissions. CIFS on the other hand needs to
 535  * know if the requested operation can succeed for the given object, this
 536  * requires more checks in case of DELETE bit since permissions on the parent
 537  * directory are important as well. Based on Windows rules if parent's ACL
 538  * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
 539  * permissions.
 540  */
 541 int
 542 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
 543 {
 544         int error = 0;
 545 
 546         if (mode == 0)
 547                 return (0);
 548 
 549         error = VOP_ACCESS(vp, mode, flags, cr, NULL);
 550 
 551         if (error == 0)
 552                 return (0);
 553 
 554         if ((mode & (ACE_DELETE|ACE_READ_ATTRIBUTES)) == 0 ||
 555             flags != V_ACE_MASK || dir_vp == NULL)
 556                 return (error);
 557 
 558         smb_audit_save();
 559         if ((mode & ACE_DELETE) != 0) {
 560                 error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
 561                     cr, NULL);
 562 
 563                 if (error == 0)
 564                         mode &= ~ACE_DELETE;
 565         }
 566         if ((mode & ACE_READ_ATTRIBUTES) != 0) {
 567                 error = VOP_ACCESS(dir_vp, ACE_LIST_DIRECTORY, flags,
 568                     cr, NULL);
 569 
 570                 if (error == 0)
 571                         mode &= ~ACE_READ_ATTRIBUTES;
 572         }
 573 
 574         if (mode != 0)
 575                 error = VOP_ACCESS(vp, mode, flags, cr, NULL);

 576 
 577         smb_audit_load();
 578         return (error);
 579 }
 580 
 581 /*
 582  * smb_vop_lookup
 583  *
 584  * dvp:         directory vnode (in)
 585  * name:        name of file to be looked up (in)
 586  * vpp:         looked-up vnode (out)
 587  * od_name:     on-disk name of file (out).
 588  *              This parameter is optional.  If a pointer is passed in, it
 589  *              must be allocated with MAXNAMELEN bytes
 590  * rootvp:      vnode of the tree root (in)
 591  *              This parameter is always passed in non-NULL except at the time
 592  *              of share set up.
 593  * direntflags: dirent flags returned from VOP_LOOKUP
 594  */
 595 int
 596 smb_vop_lookup(
 597     vnode_t             *dvp,


 635 
 636                         vfsp = cvp->v_vfsp;
 637                         vfs_rlock_wait(vfsp);
 638                         if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
 639                             (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
 640                                 vfs_unlock(vfsp);
 641                                 return (EIO);
 642                         }
 643                         vfs_unlock(vfsp);
 644                 }
 645         }
 646 
 647         if (flags & SMB_IGNORE_CASE)
 648                 option_flags = FIGNORECASE;
 649 
 650         if (flags & SMB_CATIA)
 651                 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
 652 
 653         pn_alloc(&rpn);
 654 
 655         /*
 656          * Easier to not have junk in rpn, as not every FS type
 657          * will necessarily fill that in for us.
 658          */
 659         bzero(rpn.pn_buf, rpn.pn_bufsize);
 660 
 661         error = VOP_LOOKUP(dvp, np, vpp, NULL, option_flags, NULL, cr,
 662             &smb_ct, direntflags, &rpn);
 663 
 664         if (error == 0) {
 665                 if (od_name) {
 666                         bzero(od_name, MAXNAMELEN);
 667                         if ((option_flags & FIGNORECASE) != 0 &&
 668                             rpn.pn_buf[0] != '\0')
 669                                 np = rpn.pn_buf;
 670                         else
 671                                 np = name;
 672                         if (flags & SMB_CATIA)
 673                                 smb_vop_catia_v4tov5(np, od_name, MAXNAMELEN);
 674                         else
 675                                 (void) strlcpy(od_name, np, MAXNAMELEN);
 676                 }
 677 
 678                 if (attr != NULL) {
 679                         attr->sa_mask = SMB_AT_ALL;
 680                         (void) smb_vop_getattr(*vpp, NULL, attr, 0,
 681                             zone_kcred());
 682                 }
 683         }
 684 
 685         pn_free(&rpn);
 686         return (error);
 687 }
 688 
 689 int
 690 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
 691     int flags, cred_t *cr, vsecattr_t *vsap)


 702 
 703         attr->sa_vattr.va_mask = 0;
 704 
 705         if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
 706                 smb_vop_setup_xvattr(attr, &xvattr);
 707                 vap = &xvattr.xva_vattr;
 708         } else {
 709                 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
 710                 vap = &attr->sa_vattr;
 711         }
 712 
 713         if (flags & SMB_CATIA) {
 714                 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
 715                 if (strchr(np, '/') != NULL)
 716                         return (EILSEQ);
 717         }
 718 
 719         error = VOP_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode,
 720             vpp, cr, option_flags, &smb_ct, vsap);
 721 
 722         /*
 723          * One could argue that filesystems should obey the size
 724          * if specified in the create attributes.  Unfortunately,
 725          * they only appear to let you truncate the size to zero.
 726          * SMB needs to set a non-zero size, so work-around.
 727          */
 728         if (error == 0 && *vpp != NULL &&
 729             (vap->va_mask & AT_SIZE) != 0 &&
 730             vap->va_size > 0) {
 731                 vattr_t ta = *vap;
 732                 ta.va_mask = AT_SIZE;
 733                 (void) VOP_SETATTR(*vpp, &ta, 0, cr, &smb_ct);
 734         }
 735 
 736         return (error);
 737 }
 738 
 739 int
 740 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr)
 741 {
 742         int error;
 743         int option_flags = 0;
 744         char *np = name;
 745         char namebuf[MAXNAMELEN];
 746 
 747         if (flags & SMB_IGNORE_CASE)
 748                 option_flags = FIGNORECASE;
 749 
 750         if (flags & SMB_CATIA)
 751                 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
 752 
 753         error = VOP_REMOVE(dvp, np, cr, &smb_ct, option_flags);
 754 
 755         return (error);


1008  * not literally stored on-disk in the format returned.
1009  * If the file system supports extended directory entries (has features
1010  * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
1011  * filled with edirent_t structures, instead of dirent64_t structures.
1012  * If the file system supports access based enumeration (abe), set
1013  * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
1014  */
1015 int
1016 smb_vop_readdir(vnode_t *vp, uint32_t offset,
1017     void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
1018 {
1019         int error = 0;
1020         int flags = 0;
1021         int rdirent_size;
1022         struct uio auio;
1023         struct iovec aiov;
1024 
1025         if (vp->v_type != VDIR)
1026                 return (ENOTDIR);
1027 
1028         if ((rddir_flag & SMB_EDIRENT) != 0 &&
1029             vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
1030                 flags |= V_RDDIR_ENTFLAGS;
1031                 rdirent_size = sizeof (edirent_t);
1032         } else {
1033                 rdirent_size = sizeof (dirent64_t);
1034         }
1035 
1036         if (*count < rdirent_size)
1037                 return (EINVAL);
1038 
1039         if (rddir_flag & SMB_ABE)
1040                 flags |= V_RDDIR_ACCFILTER;
1041 
1042         aiov.iov_base = buf;
1043         aiov.iov_len = *count;
1044         auio.uio_iov = &aiov;
1045         auio.uio_iovcnt = 1;
1046         auio.uio_loffset = (uint64_t)offset;
1047         auio.uio_segflg = UIO_SYSSPACE;
1048         auio.uio_extflg = UIO_COPY_DEFAULT;
1049         auio.uio_resid = *count;


1257         ASSERT(vp);
1258         ASSERT(aclp);
1259 
1260         *aclp = NULL;
1261         bzero(&vsecattr, sizeof (vsecattr_t));
1262 
1263         switch (acl_type) {
1264         case ACLENT_T:
1265                 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
1266                     VSA_DFACLCNT;
1267                 break;
1268 
1269         case ACE_T:
1270                 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
1271                 break;
1272 
1273         default:
1274                 return (EINVAL);
1275         }
1276 
1277         if ((error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) != 0)
1278                 return (error);
1279 
1280         *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type);
1281         if (vp->v_type == VDIR)
1282                 (*aclp)->acl_flags |= ACL_IS_DIR;
1283 
1284         return (0);
1285 }
1286 
1287 /*
1288  * smb_vop_acl_write
1289  *
1290  * Writes the given ACL in aclp for the specified file.
1291  */
1292 int
1293 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr)
1294 {
1295         int error;
1296         vsecattr_t vsecattr;
1297         int aclbsize;


1487          */
1488         if (nbl_need_check(vp) && (vp->v_type != VREG))
1489                 return (0);
1490 
1491         /*
1492          * For s_access and s_deny, we do not need to pass in the original
1493          * values.
1494          */
1495         shr.s_access = 0;
1496         shr.s_deny = 0;
1497         shr.s_sysid = smb_ct.cc_sysid;
1498         shr.s_pid = uniq_fid;
1499         shr.s_own_len = sizeof (shr_own);
1500         shr.s_owner = (caddr_t)&shr_own;
1501         shr_own.sl_id = shr.s_sysid;
1502         shr_own.sl_pid = shr.s_pid;
1503 
1504         return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL));
1505 }
1506 
1507 /*
1508  * Note about mandatory vs advisory locks:
1509  *
1510  * The SMB server really should always request mandatory locks, and
1511  * if the file system does not support them, the SMB server should
1512  * just tell the client it could not get the lock. If we were to
1513  * tell the SMB client "you got the lock" when what they really
1514  * got was only an advisory lock, we would be lying to the client
1515  * about their having exclusive access to the locked range, which
1516  * could easily lead to data corruption.  If someone really wants
1517  * the (dangerous) behavior they can set: smb_allow_advisory_locks
1518  */
1519 int
1520 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf)
1521 {

1522         flk_callback_t flk_cb;
1523         int cmd = F_SETLK_NBMAND;
1524 
1525         if (smb_allow_advisory_locks != 0 && !nbl_need_check(vp)) {
1526                 /*
1527                  * The file system does not support nbmand, and
1528                  * smb_allow_advisory_locks is enabled. (danger!)
1529                  */
1530                 cmd = F_SETLK;
1531         }
1532 
1533         flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL);
1534 
1535         return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct));
1536 }
1537 
1538 static callb_cpr_t *
1539 /* ARGSUSED */
1540 smb_lock_frlock_callback(flk_cb_when_t when, void *error)
1541 {
1542         return (0);
1543 }
1544 
1545 /*
1546  * smb_vop_catia_init_v4_lookup
1547  * Initialize  mapping between wide characters in the range from
1548  * 0x00A4 to 0x00FF and their UNIX (v4) equivalent (wide character).
1549  * Indexed by the decimal value of the wide character (164-255)
1550  * with an offset of -164.
1551  */
1552 static void


1590         smb_vop_catia_init_v5_lookup();
1591 }
1592 
1593 /*
1594  * smb_vop_catia_v5tov4
1595  * (windows (v5) to unix (v4))
1596  *
1597  * Traverse each character in the given source filename and convert the
1598  * multibyte that is equivalent to any special Windows character listed
1599  * in the catia_maps table to the Unix ASCII character if any is
1600  * encountered in the filename. The translated name is returned in buf.
1601  *
1602  * If an error occurs the conversion terminates and name is returned,
1603  * otherwise buf is returned.
1604  */
1605 char *
1606 smb_vop_catia_v5tov4(char *name, char *buf, int buflen)
1607 {
1608         int v4_idx, numbytes, inc;
1609         int space_left = buflen - 1; /* one byte reserved for null */
1610         uint32_t wc;
1611         char mbstring[MTS_MB_CHAR_MAX];
1612         char *p, *src = name, *dst = buf;
1613 
1614         ASSERT(name);
1615         ASSERT(buf);
1616 
1617         if (!buf || !name)
1618                 return (name);
1619 
1620         bzero(buf, buflen);
1621 
1622         while (*src) {
1623                 if ((numbytes = smb_mbtowc(&wc, src, MTS_MB_CHAR_MAX)) < 0)
1624                         return (name);
1625 
1626                 if (wc < SMB_CATIA_V4_LOOKUP_LOW ||
1627                     wc > SMB_CATIA_V4_LOOKUP_UPPER) {
1628                         inc = numbytes;
1629                         p = src;
1630                 } else {


1647 }
1648 
1649 /*
1650  * smb_vop_catia_v4tov5
1651  * (unix (v4) to windows (v5))
1652  *
1653  * Traverse each character in the given filename 'srcbuf' and convert
1654  * the special Unix character that is listed in the catia_maps table to
1655  * the UTF-8 encoding of the corresponding Windows character if any is
1656  * encountered in the filename.
1657  *
1658  * The translated name is returned in buf.
1659  * If an error occurs the conversion terminates and the original name
1660  * is returned in buf.
1661  */
1662 void
1663 smb_vop_catia_v4tov5(char *name, char *buf, int buflen)
1664 {
1665         int v5_idx, numbytes;
1666         int space_left = buflen - 1; /* one byte reserved for null */
1667         uint32_t wc;
1668         char mbstring[MTS_MB_CHAR_MAX];
1669         char *src = name, *dst = buf;
1670 
1671         ASSERT(name);
1672         ASSERT(buf);
1673 
1674         if (!buf || !name)
1675                 return;
1676 
1677         (void) bzero(buf, buflen);
1678         while (*src) {
1679                 if (smb_isascii(*src)) {
1680                         /* Lookup required */
1681                         v5_idx = (int)*src++;
1682                         numbytes = smb_wctomb(mbstring,
1683                             smb_catia_v5_lookup[v5_idx]);
1684                         if (space_left < numbytes)
1685                                 break;
1686                         (void) strncpy(dst, mbstring, numbytes);
1687                 } else {