Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5844 want SMB2 ioctl FSCTL_SRV_COPYCHUNK
NEX-6124 smb_fsop_read/write should allow file != sr->fid_ofile
NEX-6125 smbtorture invalid response with smb2.ioctl
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-4538 SMB1 create file should support extended_response format (2)
NEX-6116 Failures in smbtorture raw.open
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Include this commit if upstreaming/backporting any of:
NEX-4540 SMB server declines EA support incorrectly
NEX-4239 smbtorture create failures re. allocation size
(illumos) 6398 SMB should support path names longer than 1024
NEX-4538 SMB1 create file should support extended_response format
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
NEX-2522 svcadm disable network/smb/server may hang
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-3662 Backport illumos 1501: taskq_create_proc ... TQ_DYNAMIC puts tasks in p0 (take 2)
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
NEX-3576 RPC error when displaying open files via Windows MMC
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-2188 Browsing top level share produces RPC error 1728
SMB-119 Text file contains garbage when re-opened
SMB-120 Share enumeration fails with Windows 8
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-39 Use AF_UNIX pipes for RPC
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 (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
re #6812 rb1753 backport illumos 1604 smbd print_enable doesn't really work
        
*** 18,28 ****
   *
   * CDDL HEADER END
   */
  /*
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * This module provides the interface to NDR RPC.
   */
--- 18,28 ----
   *
   * CDDL HEADER END
   */
  /*
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
   */
  
  /*
   * This module provides the interface to NDR RPC.
   */
*** 33,46 ****
  #include <sys/stropts.h>
  #include <sys/socket.h>
  #include <sys/filio.h>
  #include <smbsrv/smb_kproto.h>
  #include <smbsrv/smb_xdr.h>
! #include <smbsrv/winioctl.h>
  
- static uint32_t smb_opipe_transceive(smb_request_t *, smb_fsctl_t *);
- 
  /*
   * Allocate a new opipe and return it, or NULL, in which case
   * the caller will report "internal error".
   */
  static smb_opipe_t *
--- 33,44 ----
  #include <sys/stropts.h>
  #include <sys/socket.h>
  #include <sys/filio.h>
  #include <smbsrv/smb_kproto.h>
  #include <smbsrv/smb_xdr.h>
! #include <smb/winioctl.h>
  
  /*
   * Allocate a new opipe and return it, or NULL, in which case
   * the caller will report "internal error".
   */
  static smb_opipe_t *
*** 95,104 ****
--- 93,126 ----
  
          kmem_cache_free(smb_cache_opipe, opipe);
  }
  
  /*
+  * Unblock a request that might be blocked reading some
+  * pipe (AF_UNIX socket).  We don't have an easy way to
+  * interrupt just the thread servicing this request, so
+  * we shutdown(3socket) the socket, waking all readers.
+  * That's a bit heavy-handed, making the socket unusable
+  * after this, so we do this only when disconnecting a
+  * session (i.e. stopping the SMB service), and not when
+  * handling an SMB2_cancel or SMB_nt_cancel request.
+  */
+ static void
+ smb_opipe_cancel(smb_request_t *sr)
+ {
+         ksocket_t so;
+ 
+         switch (sr->session->s_state) {
+         case SMB_SESSION_STATE_DISCONNECTED:
+         case SMB_SESSION_STATE_TERMINATED:
+                 if ((so = sr->cancel_arg2) != NULL)
+                         (void) ksocket_shutdown(so, SHUT_RDWR, sr->user_cr);
+                 break;
+         }
+ }
+ 
+ /*
   * Helper for open: build pipe name and connect.
   */
  static int
  smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe)
  {
*** 165,199 ****
          xdrmem_create(&xdrs, buf + sizeof (phdr),
              buflen - (sizeof (phdr)), XDR_ENCODE);
          if (!smb_netuserinfo_xdr(&xdrs, &nui))
                  goto out;
  
!         /*
!          * If we fail sending the netuserinfo or recv'ing the
!          * status reponse, we have probably run into the limit
!          * on the number of open pipes.  That's this status:
!          */
!         errp->status = NT_STATUS_PIPE_NOT_AVAILABLE;
  
          rc = ksocket_send(opipe->p_socket, buf, buflen, 0,
              &iocnt, sr->user_cr);
          if (rc == 0 && iocnt != buflen)
                  rc = EIO;
!         if (rc != 0)
!                 goto out;
  
!         rc = ksocket_recv(opipe->p_socket, &status, sizeof (status), 0,
!             &iocnt, sr->user_cr);
!         if (rc != 0 || iocnt != sizeof (status))
!                 goto out;
  
          /*
           * Return the status we read from the pipe service,
           * normally NT_STATUS_SUCCESS, but could be something
           * else like NT_STATUS_ACCESS_DENIED.
           */
          errp->status = status;
  
  out:
          xdr_destroy(&xdrs);
          kmem_free(buf, buflen);
          smb_user_netinfo_fini(&nui);
--- 187,256 ----
          xdrmem_create(&xdrs, buf + sizeof (phdr),
              buflen - (sizeof (phdr)), XDR_ENCODE);
          if (!smb_netuserinfo_xdr(&xdrs, &nui))
                  goto out;
  
!         mutex_enter(&sr->sr_mutex);
!         if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
!                 mutex_exit(&sr->sr_mutex);
!                 errp->status = NT_STATUS_CANCELLED;
!                 goto out;
!         }
!         sr->sr_state = SMB_REQ_STATE_WAITING_PIPE;
!         sr->cancel_method = smb_opipe_cancel;
!         sr->cancel_arg2 = opipe->p_socket;
!         mutex_exit(&sr->sr_mutex);
  
          rc = ksocket_send(opipe->p_socket, buf, buflen, 0,
              &iocnt, sr->user_cr);
          if (rc == 0 && iocnt != buflen)
                  rc = EIO;
!         if (rc == 0)
!                 rc = ksocket_recv(opipe->p_socket, &status, sizeof (status),
!                     0, &iocnt, sr->user_cr);
!         if (rc == 0 && iocnt != sizeof (status))
!                 rc = EIO;
  
!         mutex_enter(&sr->sr_mutex);
!         sr->cancel_method = NULL;
!         sr->cancel_arg2 = NULL;
!         switch (sr->sr_state) {
!         case SMB_REQ_STATE_WAITING_PIPE:
!                 sr->sr_state = SMB_REQ_STATE_ACTIVE;
!                 break;
!         case SMB_REQ_STATE_CANCEL_PENDING:
!                 sr->sr_state = SMB_REQ_STATE_CANCELLED;
!                 rc = EINTR;
!                 break;
!         default:
!                 /* keep rc from above */
!                 break;
!         }
!         mutex_exit(&sr->sr_mutex);
  
+ 
          /*
           * Return the status we read from the pipe service,
           * normally NT_STATUS_SUCCESS, but could be something
           * else like NT_STATUS_ACCESS_DENIED.
           */
+         switch (rc) {
+         case 0:
                  errp->status = status;
+                 break;
+         case EINTR:
+                 errp->status = NT_STATUS_CANCELLED;
+                 break;
+         /*
+          * If we fail sending the netuserinfo or recv'ing the
+          * status reponse, we have probably run into the limit
+          * on the number of open pipes.  That's this status:
+          */
+         default:
+                 errp->status = NT_STATUS_PIPE_NOT_AVAILABLE;
+                 break;
+         }
  
  out:
          xdr_destroy(&xdrs);
          kmem_free(buf, buflen);
          smb_user_netinfo_fini(&nui);
*** 207,220 ****
   * If we recognize the pipe, we setup a new ofile.
   *
   * Returns 0 on success, Otherwise an NT status code.
   */
  int
! smb_opipe_open(smb_request_t *sr, uint32_t uniqid)
  {
          smb_arg_open_t  *op = &sr->sr_open;
!         smb_ofile_t *ofile;
          smb_opipe_t *opipe;
          smb_error_t err;
  
          opipe = smb_opipe_alloc(sr);
          if (opipe == NULL)
--- 264,277 ----
   * If we recognize the pipe, we setup a new ofile.
   *
   * Returns 0 on success, Otherwise an NT status code.
   */
  int
! smb_opipe_open(smb_request_t *sr, smb_ofile_t *ofile)
  {
          smb_arg_open_t  *op = &sr->sr_open;
!         smb_attr_t *ap = &op->fqi.fq_fattr;
          smb_opipe_t *opipe;
          smb_error_t err;
  
          opipe = smb_opipe_alloc(sr);
          if (opipe == NULL)
*** 230,263 ****
                  smb_opipe_dealloc(opipe);
                  return (err.status);
          }
  
          /*
!          * Note: If smb_ofile_open succeeds, the new ofile is
!          * in the FID lists can can be used by I/O requests.
           */
!         op->create_options = 0;
!         op->pipe = opipe;
!         ofile = smb_ofile_open(sr, NULL, op,
!             SMB_FTYPE_MESG_PIPE, uniqid, &err);
!         op->pipe = NULL;
!         if (ofile == NULL) {
                  smb_opipe_dealloc(opipe);
!                 return (err.status);
          }
  
          /* An "up" pointer, for debug. */
          opipe->p_ofile = ofile;
  
!         op->dsize = 0x01000;
!         op->dattr = FILE_ATTRIBUTE_NORMAL;
          op->ftype = SMB_FTYPE_MESG_PIPE;
!         op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
          op->devstate = SMB_PIPE_READMODE_MESSAGE
              | SMB_PIPE_TYPE_MESSAGE
              | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
-         op->fileid = ofile->f_fid;
  
          sr->smb_fid = ofile->f_fid;
          sr->fid_ofile = ofile;
  
          return (NT_STATUS_SUCCESS);
--- 287,330 ----
                  smb_opipe_dealloc(opipe);
                  return (err.status);
          }
  
          /*
!          * We might have blocked in smb_opipe_connect long enough so
!          * a tree disconnect might have happened.  In that case, we
!          * would be adding an ofile to a tree that's disconnecting,
!          * which would interfere with tear-down.
           */
!         if (!smb_tree_is_connected(sr->tid_tree)) {
                  smb_opipe_dealloc(opipe);
!                 return (NT_STATUS_NETWORK_NAME_DELETED);
          }
  
+         /*
+          * Note: The new opipe is given to smb_ofile_open
+          * via op->pipe
+          */
+         op->pipe = opipe;
+         smb_ofile_open(sr, op, ofile);
+         op->pipe = NULL;
+ 
          /* An "up" pointer, for debug. */
          opipe->p_ofile = ofile;
  
!         /*
!          * Caller expects attributes in op->fqi
!          */
!         (void) smb_opipe_getattr(ofile, &op->fqi.fq_fattr);
! 
!         op->dsize = 0;
!         op->dattr = ap->sa_dosattr;
!         op->fileid = ap->sa_vattr.va_nodeid;
          op->ftype = SMB_FTYPE_MESG_PIPE;
!         op->action_taken = SMB_OACT_OPLOCK | SMB_OACT_OPENED;
          op->devstate = SMB_PIPE_READMODE_MESSAGE
              | SMB_PIPE_TYPE_MESSAGE
              | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
  
          sr->smb_fid = ofile->f_fid;
          sr->fid_ofile = ofile;
  
          return (NT_STATUS_SUCCESS);
*** 370,390 ****
                  ksocket_hold(sock);
          mutex_exit(&opipe->p_mutex);
          if (sock == NULL)
                  return (EBADF);
  
!         bzero(&msghdr, sizeof (msghdr));
!         msghdr.msg_iov = uio->uio_iov;
!         msghdr.msg_iovlen = uio->uio_iovcnt;
  
          /*
           * This should block only if there's no data.
           * A single call to recvmsg does just that.
           * (Intentionaly no recv loop here.)
           */
          rc = ksocket_recvmsg(sock, &msghdr, 0,
              &recvcnt, ofile->f_cr);
          if (rc != 0)
                  goto out;
  
          if (recvcnt == 0) {
                  /* Other side closed. */
--- 437,485 ----
                  ksocket_hold(sock);
          mutex_exit(&opipe->p_mutex);
          if (sock == NULL)
                  return (EBADF);
  
!         mutex_enter(&sr->sr_mutex);
!         if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
!                 mutex_exit(&sr->sr_mutex);
!                 rc = EINTR;
!                 goto out;
!         }
!         sr->sr_state = SMB_REQ_STATE_WAITING_PIPE;
!         sr->cancel_method = smb_opipe_cancel;
!         sr->cancel_arg2 = sock;
!         mutex_exit(&sr->sr_mutex);
  
          /*
           * This should block only if there's no data.
           * A single call to recvmsg does just that.
           * (Intentionaly no recv loop here.)
           */
+         bzero(&msghdr, sizeof (msghdr));
+         msghdr.msg_iov = uio->uio_iov;
+         msghdr.msg_iovlen = uio->uio_iovcnt;
          rc = ksocket_recvmsg(sock, &msghdr, 0,
              &recvcnt, ofile->f_cr);
+ 
+         mutex_enter(&sr->sr_mutex);
+         sr->cancel_method = NULL;
+         sr->cancel_arg2 = NULL;
+         switch (sr->sr_state) {
+         case SMB_REQ_STATE_WAITING_PIPE:
+                 sr->sr_state = SMB_REQ_STATE_ACTIVE;
+                 break;
+         case SMB_REQ_STATE_CANCEL_PENDING:
+                 sr->sr_state = SMB_REQ_STATE_CANCELLED;
+                 rc = EINTR;
+                 break;
+         default:
+                 /* keep rc from above */
+                 break;
+         }
+         mutex_exit(&sr->sr_mutex);
+ 
          if (rc != 0)
                  goto out;
  
          if (recvcnt == 0) {
                  /* Other side closed. */
*** 438,449 ****
          if (of->f_pipe == NULL)
                  return (EINVAL);
  
          ap->sa_vattr.va_type = VFIFO;
          ap->sa_vattr.va_nlink = 1;
          ap->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
!         ap->sa_allocsz = 0x1000LL;
  
          return (0);
  }
  
  int
--- 533,545 ----
          if (of->f_pipe == NULL)
                  return (EINVAL);
  
          ap->sa_vattr.va_type = VFIFO;
          ap->sa_vattr.va_nlink = 1;
+         ap->sa_vattr.va_nodeid = (uintptr_t)of->f_pipe;
          ap->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
!         ap->sa_allocsz = SMB_PIPE_MAX_MSGSIZE;
  
          return (0);
  }
  
  int
*** 457,474 ****
          (void) snprintf(buf, buflen, "\\%s", opipe->p_name);
          return (0);
  }
  
  /*
!  * Handler for smb2_ioctl
   */
  /* ARGSUSED */
  uint32_t
  smb_opipe_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
  {
          uint32_t status;
  
          switch (fsctl->CtlCode) {
          case FSCTL_PIPE_TRANSCEIVE:
                  status = smb_opipe_transceive(sr, fsctl);
                  break;
  
--- 553,574 ----
          (void) snprintf(buf, buflen, "\\%s", opipe->p_name);
          return (0);
  }
  
  /*
!  * Handle device type FILE_DEVICE_NAMED_PIPE
!  * for smb2_ioctl
   */
  /* ARGSUSED */
  uint32_t
  smb_opipe_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
  {
          uint32_t status;
  
+         if (!STYPE_ISIPC(sr->tid_tree->t_res_type))
+                 return (NT_STATUS_INVALID_DEVICE_REQUEST);
+ 
          switch (fsctl->CtlCode) {
          case FSCTL_PIPE_TRANSCEIVE:
                  status = smb_opipe_transceive(sr, fsctl);
                  break;
  
*** 485,495 ****
          }
  
          return (status);
  }
  
! static uint32_t
  smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl)
  {
          smb_vdb_t       vdb;
          smb_ofile_t     *ofile;
          struct mbuf     *mb;
--- 585,595 ----
          }
  
          return (status);
  }
  
! uint32_t
  smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl)
  {
          smb_vdb_t       vdb;
          smb_ofile_t     *ofile;
          struct mbuf     *mb;