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;