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,11 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
  * This module provides the interface to NDR RPC.
  */

@@ -33,14 +33,12 @@
 #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>
+#include <smb/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 *

@@ -95,10 +93,34 @@
 
         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,35 +187,70 @@
         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;
+        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)
-                goto out;
+        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;
 
-        rc = ksocket_recv(opipe->p_socket, &status, sizeof (status), 0,
-            &iocnt, sr->user_cr);
-        if (rc != 0 || iocnt != sizeof (status))
-                goto out;
+        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,14 +264,14 @@
  * 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_opipe_open(smb_request_t *sr, smb_ofile_t *ofile)
 {
         smb_arg_open_t  *op = &sr->sr_open;
-        smb_ofile_t *ofile;
+        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,34 +287,44 @@
                 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.
+         * 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.
          */
-        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) {
+        if (!smb_tree_is_connected(sr->tid_tree)) {
                 smb_opipe_dealloc(opipe);
-                return (err.status);
+                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;
 
-        op->dsize = 0x01000;
-        op->dattr = FILE_ATTRIBUTE_NORMAL;
+        /*
+         * 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_LOCK | SMB_OACT_OPENED; /* 0x8001 */
+        op->action_taken = SMB_OACT_OPLOCK | SMB_OACT_OPENED;
         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);

@@ -370,21 +437,49 @@
                 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;
+        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,12 +533,13 @@
         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 = 0x1000LL;
+        ap->sa_allocsz = SMB_PIPE_MAX_MSGSIZE;
 
         return (0);
 }
 
 int

@@ -457,18 +553,22 @@
         (void) snprintf(buf, buflen, "\\%s", opipe->p_name);
         return (0);
 }
 
 /*
- * Handler for smb2_ioctl
+ * 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,11 +585,11 @@
         }
 
         return (status);
 }
 
-static uint32_t
+uint32_t
 smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl)
 {
         smb_vdb_t       vdb;
         smb_ofile_t     *ofile;
         struct mbuf     *mb;