diff options
author | Gordon Ross <gwr@racktopsystems.com> | 2022-01-08 21:25:25 -0500 |
---|---|---|
committer | Toomas Soome <tsoome@me.com> | 2022-10-24 20:52:49 +0300 |
commit | 268cac54f3b029bc35167d895c6d82ded041d24b (patch) | |
tree | d3eda3689df9a5c5e1fe49a24f5f95cdf90a0662 | |
parent | db8a370dba45fa238d7ad5ac85e2fffef8713c75 (diff) | |
download | illumos-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.c | 88 | ||||
-rw-r--r-- | usr/src/uts/common/fs/smbsrv/smb_opipe.c | 75 |
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); +} |