summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <gwr@racktopsystems.com>2022-01-08 21:25:25 -0500
committerToomas Soome <tsoome@me.com>2022-10-24 20:52:49 +0300
commit268cac54f3b029bc35167d895c6d82ded041d24b (patch)
treed3eda3689df9a5c5e1fe49a24f5f95cdf90a0662
parentdb8a370dba45fa238d7ad5ac85e2fffef8713c75 (diff)
downloadillumos-gate-268cac54f3b029bc35167d895c6d82ded041d24b.tar.gz
15093 SMB error after Win10 tries FSCTL_PIPE_WAIT
Reviewed by: Andy Stormont <astormont@racktopsystems.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Dan McDonald <danmcd@mnx.io>
-rw-r--r--usr/src/lib/smbsrv/libfksmbsrv/common/fake_lookup.c88
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_opipe.c75
2 files changed, 160 insertions, 3 deletions
diff --git a/usr/src/lib/smbsrv/libfksmbsrv/common/fake_lookup.c b/usr/src/lib/smbsrv/libfksmbsrv/common/fake_lookup.c
index 7cd43cd92e..672b3e666a 100644
--- a/usr/src/lib/smbsrv/libfksmbsrv/common/fake_lookup.c
+++ b/usr/src/lib/smbsrv/libfksmbsrv/common/fake_lookup.c
@@ -22,10 +22,11 @@
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
@@ -57,6 +58,91 @@
#include <sys/dnlc.h>
#include <sys/fs/snode.h>
+int
+lookupname(
+ char *fnamep,
+ enum uio_seg seg,
+ int followlink,
+ vnode_t **dirvpp,
+ vnode_t **compvpp)
+{
+ return (lookupnameatcred(fnamep, seg, followlink, dirvpp, compvpp, NULL,
+ CRED()));
+}
+
+/*
+ * Lookup the user file name,
+ * Handle allocation and freeing of pathname buffer, return error.
+ */
+int
+lookupnameatcred(
+ char *fnamep, /* user pathname */
+ enum uio_seg seg, /* addr space that name is in */
+ int followlink, /* follow sym links */
+ vnode_t **dirvpp, /* ret for ptr to parent dir vnode */
+ vnode_t **compvpp, /* ret for ptr to component vnode */
+ vnode_t *startvp, /* start path search from vp */
+ cred_t *cr) /* credential */
+{
+ char namebuf[TYPICALMAXPATHLEN];
+ struct pathname lookpn;
+ int error;
+
+ error = pn_get_buf(fnamep, seg, &lookpn, namebuf, sizeof (namebuf));
+ if (error == 0) {
+ error = lookuppnatcred(&lookpn, NULL, followlink,
+ dirvpp, compvpp, startvp, cr);
+ }
+ if (error == ENAMETOOLONG) {
+ /*
+ * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
+ */
+ if ((error = pn_get(fnamep, seg, &lookpn)) != 0)
+ return (error);
+ error = lookuppnatcred(&lookpn, NULL, followlink,
+ dirvpp, compvpp, startvp, cr);
+ pn_free(&lookpn);
+ }
+
+ return (error);
+}
+
+/*
+ * Lookup the user file name from a given vp, using a specific credential.
+ */
+int
+lookuppnatcred(
+ struct pathname *pnp, /* pathname to lookup */
+ struct pathname *rpnp, /* if non-NULL, return resolved path */
+ int followlink, /* (don't) follow sym links */
+ vnode_t **dirvpp, /* ptr for parent vnode */
+ vnode_t **compvpp, /* ptr for entry vnode */
+ vnode_t *startvp, /* start search from this vp */
+ cred_t *cr) /* user credential */
+{
+ vnode_t *vp; /* current directory vp */
+ vnode_t *rootvp;
+
+ if (pnp->pn_pathlen == 0)
+ return (ENOENT);
+
+ /* Simplified for fake_... */
+ vp = rootvp = rootdir;
+
+ /*
+ * Skip over leading slashes
+ */
+ if (pnp->pn_path[0] == '/') {
+ do {
+ pnp->pn_path++;
+ pnp->pn_pathlen--;
+ } while (pnp->pn_path[0] == '/');
+ }
+
+ return (lookuppnvp(pnp, rpnp, followlink, dirvpp,
+ compvpp, rootvp, vp, cr));
+}
+
/*
* Starting at current directory, translate pathname pnp to end.
* Leave pathname of final component in pnp, return the vnode
diff --git a/usr/src/uts/common/fs/smbsrv/smb_opipe.c b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
index 6742a5c052..0cd4750d49 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -37,6 +38,8 @@
#include <smbsrv/smb_xdr.h>
#include <smb/winioctl.h>
+static uint32_t smb_opipe_wait(smb_request_t *, smb_fsctl_t *);
+
/*
* Allocate a new opipe and return it, or NULL, in which case
* the caller will report "internal error".
@@ -148,6 +151,27 @@ smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe)
return (rc);
}
+static int
+smb_opipe_exists(char *name)
+{
+ struct sockaddr_un saddr;
+ vnode_t *vp; /* Underlying filesystem vnode */
+ int err;
+
+ bzero(&saddr, sizeof (saddr));
+ saddr.sun_family = AF_UNIX;
+ (void) snprintf(saddr.sun_path, sizeof (saddr.sun_path),
+ "%s/%s", SMB_PIPE_DIR, name);
+
+ err = lookupname(saddr.sun_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
+ if (err == 0) {
+ VN_RELE(vp); /* release hold from lookup */
+ }
+
+ return (err);
+}
+
+
/*
* Helper for open: encode and send the user info.
*
@@ -573,9 +597,11 @@ smb_opipe_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
break;
case FSCTL_PIPE_PEEK:
+ status = NT_STATUS_INVALID_DEVICE_REQUEST;
+ break;
+
case FSCTL_PIPE_WAIT:
- /* XXX todo */
- status = NT_STATUS_NOT_SUPPORTED;
+ status = smb_opipe_wait(sr, fsctl);
break;
default:
@@ -655,3 +681,48 @@ smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl)
return (status);
}
+
+static uint32_t
+smb_opipe_wait(smb_request_t *sr, smb_fsctl_t *fsctl)
+{
+ char *name;
+ uint64_t timeout;
+ uint32_t namelen;
+ int rc;
+ uint8_t tflag;
+
+ rc = smb_mbc_decodef(fsctl->in_mbc, "qlb.",
+ &timeout, /* q */
+ &namelen, /* l */
+ &tflag); /* b */
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+ rc = smb_mbc_decodef(fsctl->in_mbc, "%#U",
+ sr, /* % */
+ namelen, /* # */
+ &name); /* U */
+ if (rc != 0)
+ return (NT_STATUS_INVALID_PARAMETER);
+
+ rc = smb_opipe_exists(name);
+ if (rc != 0)
+ return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * At this point we know the pipe exists.
+ *
+ * If the tflag is set, we're supposed to wait for up to
+ * timeout (100s of milliseconds) for a pipe "instance"
+ * to become "available" (so pipe open would work).
+ * However, this implementation has no need to wait,
+ * so just take a short delay instead.
+ */
+ if (tflag != 0) {
+ clock_t ticks = MSEC_TO_TICK(timeout * 100);
+ if (ticks > MSEC_TO_TICK(100))
+ ticks = MSEC_TO_TICK(100);
+ delay(ticks);
+ }
+
+ return (0);
+}